From 6efcf825712fd7d92a778d80aee3ef08109f15ae Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 31 Jul 2023 04:46:59 -0300 Subject: [PATCH 001/147] feat: define dataclasses of homepage on world module --- worldometer/world/__init__.py | 21 ++++++ worldometer/world/ometers.py | 124 ++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 worldometer/world/__init__.py create mode 100644 worldometer/world/ometers.py diff --git a/worldometer/world/__init__.py b/worldometer/world/__init__.py new file mode 100644 index 0000000..4be236a --- /dev/null +++ b/worldometer/world/__init__.py @@ -0,0 +1,21 @@ +__all__ = [ + 'Energy', + 'Environment', + 'Food', + 'GovernmentAndEconomics', + 'Health', + 'SocietyAndMedia', + 'Water', + 'WorldPopulation' +] + +from worldometer.world.ometers import ( + Energy, + Environment, + Food, + GovernmentAndEconomics, + Health, + SocietyAndMedia, + Water, + WorldPopulation +) diff --git a/worldometer/world/ometers.py b/worldometer/world/ometers.py new file mode 100644 index 0000000..f4fffc0 --- /dev/null +++ b/worldometer/world/ometers.py @@ -0,0 +1,124 @@ +from dataclasses import dataclass, field + +from typing import List, Union + + +@dataclass +class WorldPopulation: + _data: dict = field(default_factory=dict, repr=False, init=False) + current_population: Union[int, None] = None + births_today: Union[int, None] = None + births_this_year: Union[int, None] = None + deaths_today: Union[int, None] = None + deaths_this_year: Union[int, None] = None + net_population_growth_today: Union[int, None] = None + net_population_growth_this_year: Union[int, None] = None + + +@dataclass +class GovernmentAndEconomics: + _data: dict = field(default_factory=dict, repr=False, init=False) + public_healthcare_expenditure_today: Union[int, None] = None + public_education_expenditure_today: Union[int, None] = None + public_education_expenditure_today: Union[int, None] = None + public_education_expenditure_today: Union[int, None] = None + bicycles_produced_this_year: Union[int, None] = None + computers_produced_this_year: Union[int, None] = None + + +@dataclass +class SocietyAndMedia: + _data: dict = field(default_factory=dict, repr=False, init=False) + new_book_titles_published_this_year: Union[int, None] = None + newspapers_circulated_today: Union[int, None] = None + tv_sets_sold_worldwide_today: Union[int, None] = None + cellular_phones_sold_today: Union[int, None] = None + money_spent_on_videogames_today: Union[int, None] = None + internet_users_in_the_world_today: Union[int, None] = None + emails_sent_today: Union[int, None] = None + blog_posts_written_today: Union[int, None] = None + tweets_sent_today: Union[int, None] = None + google_searches_today: Union[int, None] = None + + +@dataclass +class Environment: + _data: dict = field(default_factory=dict, repr=False, init=False) + forest_loss_this_year: Union[int, None] = None + land_lost_to_soil_erosion_this_year: Union[int, None] = None + co2_emissions_this_year: Union[int, None] = None + desertification_this_year: Union[int, None] = None + toxic_chemicals_released_in_the_environment_this_year: Union[int, None] = None + + +@dataclass +class Food: + _data: dict = field(default_factory=dict, repr=False, init=False) + undernourished_people_in_the_world: Union[int, None] = None + overweight_people_in_the_world: Union[int, None] = None + obese_people_in_the_world: Union[int, None] = None + people_who_died_of_hunger_today: Union[int, None] = None + money_spent_for_obesity_related_diseases_in_the_usa_today: Union[int, None] = None + money_spent_on_weight_loss_programs_in_the_usa_today: Union[int, None] = None + + +@dataclass +class Water: + _data: dict = field(default_factory=dict, repr=False, init=False) + water_used_this_year: Union[int, None] = None + deaths_caused_by_water_related_diseases_this_year: Union[int, None] = None + people_with_no_access_to_a_safe_drinking_water_source: Union[int, None] = None + + +@dataclass +class Energy: + _data: dict = field(default_factory=dict, repr=False, init=False) + energy_used_today: Union[int, None] = None + non_renewable_sources: Union[int, None] = None + renewable_sources: Union[int, None] = None + solar_energy_striking_earth_today: Union[int, None] = None + oil_pumped_today: Union[int, None] = None + oil_left: Union[int, None] = None + days_to_the_end_of_oil: Union[int, None] = None + natural_gas_left: Union[int, None] = None + days_to_the_end_of_natural_gas: Union[int, None] = None + coal_left: Union[int, None] = None + days_to_the_end_of_coal: Union[int, None] = None + + +@dataclass +class Health: + _data: dict = field(default_factory=dict, repr=False, init=False) + communicable_disease_deaths_this_year: Union[int, None] = None + seasonal_flu_deaths_this_year: Union[int, None] = None + deaths_of_children_under_5_this_year: Union[int, None] = None + abortions_this_year: Union[int, None] = None + deaths_of_mothers_during_birth_this_year: Union[int, None] = None + hiv_aids_infected_people: Union[int, None] = None + deaths_caused_by_hiv_aids_this_year: Union[int, None] = None + deaths_caused_by_cancer_this_year: Union[int, None] = None + deaths_caused_by_malaria_this_year: Union[int, None] = None + cigarettes_smoked_today: Union[int, None] = None + deaths_caused_by_smoking_this_year: Union[int, None] = None + deaths_caused_by_alcohol_this_year: Union[int, None] = None + suicides_this_year: Union[int, None] = None + money_spent_on_illegal_drugs_this_year: Union[int, None] = None + road_traffic_accident_fatalities_this_year: Union[int, None] = None + + +@dataclass +class CountryCodeData: + country: str + calling_code: str + three_letter_iso: str + two_letter_iso: str + three_digit_iso_numeric: str + + +@dataclass +class CountryCodes: + _data: List[CountryCodeData] = field( + default_factory=list, + repr=False, + init=False + ) From c6d878a76ba8494d5f0e653ce46294c0064815be Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 17 Aug 2023 04:38:49 -0300 Subject: [PATCH 002/147] refactor: change dataclass representation to common class --- worldometer/world/ometers.py | 192 ++++++++++++++++++++--------------- 1 file changed, 112 insertions(+), 80 deletions(-) diff --git a/worldometer/world/ometers.py b/worldometer/world/ometers.py index f4fffc0..9acdf2b 100644 --- a/worldometer/world/ometers.py +++ b/worldometer/world/ometers.py @@ -1,109 +1,141 @@ from dataclasses import dataclass, field -from typing import List, Union +from typing import List -@dataclass class WorldPopulation: - _data: dict = field(default_factory=dict, repr=False, init=False) - current_population: Union[int, None] = None - births_today: Union[int, None] = None - births_this_year: Union[int, None] = None - deaths_today: Union[int, None] = None - deaths_this_year: Union[int, None] = None - net_population_growth_today: Union[int, None] = None - net_population_growth_this_year: Union[int, None] = None + + def __init__(self) -> None: + self._data = self._load_data() + self.current_population = self._data.get('current_population') + self.births_today = self._data.get('births_today') + self.births_this_year = self._data.get('births_this_year') + self.deaths_today = self._data.get('dth1s_today') + self.deaths_this_year = self._data.get('dth1s_this_year') + self.net_population_growth_today = self._data.get('absolute_growth') + self.net_population_growth_this_year = self._data.get('absolute_growth_year') + + def _load_data(self) -> dict: + return {} -@dataclass class GovernmentAndEconomics: - _data: dict = field(default_factory=dict, repr=False, init=False) - public_healthcare_expenditure_today: Union[int, None] = None - public_education_expenditure_today: Union[int, None] = None - public_education_expenditure_today: Union[int, None] = None - public_education_expenditure_today: Union[int, None] = None - bicycles_produced_this_year: Union[int, None] = None - computers_produced_this_year: Union[int, None] = None + + def __init__(self) -> None: + self._data = self._load_data() + self.public_healthcare_expenditure_today = self._data.get('gov_expenditures_health') + self.public_education_expenditure_today = self._data.get('gov_expenditures_education') + self.public_military_expenditure_today = self._data.get('gov_expenditures_military') + self.cars_produced_this_year = self._data.get('automobile_produced') + self.bicycles_produced_this_year = self._data.get('bicycle_produced') + self.computers_produced_this_year = self._data.get('computers_sold') + + def _load_data(self) -> dict: + return {} -@dataclass class SocietyAndMedia: - _data: dict = field(default_factory=dict, repr=False, init=False) - new_book_titles_published_this_year: Union[int, None] = None - newspapers_circulated_today: Union[int, None] = None - tv_sets_sold_worldwide_today: Union[int, None] = None - cellular_phones_sold_today: Union[int, None] = None - money_spent_on_videogames_today: Union[int, None] = None - internet_users_in_the_world_today: Union[int, None] = None - emails_sent_today: Union[int, None] = None - blog_posts_written_today: Union[int, None] = None - tweets_sent_today: Union[int, None] = None - google_searches_today: Union[int, None] = None + + def __init__(self) -> None: + self._data = self._load_data() + self.new_book_titles_published_this_year = self._data.get('books_published') + self.newspapers_circulated_today = self._data.get('newspapers_circulated') + self.tv_sets_sold_worldwide_today = self._data.get('tv') + self.cellular_phones_sold_today = self._data.get('cellular') + self.money_spent_on_videogames_today = self._data.get('videogames') + self.internet_users_in_the_world_today = self._data.get('internet_users') + self.emails_sent_today = self._data.get('em') + self.blog_posts_written_today = self._data.get('blog_posts') + self.tweets_sent_today = self._data.get('tweets') + self.google_searches_today = self._data.get('google_searches') + + def _load_data(self) -> dict: + return {} -@dataclass class Environment: - _data: dict = field(default_factory=dict, repr=False, init=False) - forest_loss_this_year: Union[int, None] = None - land_lost_to_soil_erosion_this_year: Union[int, None] = None - co2_emissions_this_year: Union[int, None] = None - desertification_this_year: Union[int, None] = None - toxic_chemicals_released_in_the_environment_this_year: Union[int, None] = None + + def __init__(self) -> None: + self._data = self._load_data() + self.forest_loss_this_year = self._data.get('forest_loss') + self.land_lost_to_soil_erosion_this_year = self._data.get('soil_erosion') + self.co2_emissions_this_year = self._data.get('co2_emissions') + self.desertification_this_year = self._data.get('desert_land_formed') + self.toxic_chemicals_released_in_the_environment_this_year = self._data.get('tox_chem') + + def _load_data(self) -> dict: + return {} -@dataclass class Food: - _data: dict = field(default_factory=dict, repr=False, init=False) - undernourished_people_in_the_world: Union[int, None] = None - overweight_people_in_the_world: Union[int, None] = None - obese_people_in_the_world: Union[int, None] = None - people_who_died_of_hunger_today: Union[int, None] = None - money_spent_for_obesity_related_diseases_in_the_usa_today: Union[int, None] = None - money_spent_on_weight_loss_programs_in_the_usa_today: Union[int, None] = None + + def __init__(self) -> None: + self._data = self._load_data() + self.undernourished_people_in_the_world = self._data.get('undernourished') + self.overweight_people_in_the_world = self._data.get('overweight') + self.obese_people_in_the_world = self._data.get('obese') + self.people_who_died_of_hunger_today = self._data.get('dth1_hunger') + self.money_spent_for_obesity_related_diseases_in_the_usa_today = self._data.get('obesity_spending') + self.money_spent_on_weight_loss_programs_in_the_usa_today = self._data.get('spending_on_weight_loss') + + def _load_data(self) -> dict: + return {} -@dataclass class Water: - _data: dict = field(default_factory=dict, repr=False, init=False) - water_used_this_year: Union[int, None] = None - deaths_caused_by_water_related_diseases_this_year: Union[int, None] = None - people_with_no_access_to_a_safe_drinking_water_source: Union[int, None] = None + + def __init__(self) -> None: + self._data = self._load_data() + self.water_used_this_year = self._data.get('water_consumed') + self.deaths_caused_by_water_related_diseases_this_year = self._data.get('water_disax') + self.people_with_no_access_to_a_safe_drinking_water_source = self._data.get('nowater_population') + + def _load_data(self) -> dict: + return {} -@dataclass class Energy: - _data: dict = field(default_factory=dict, repr=False, init=False) - energy_used_today: Union[int, None] = None - non_renewable_sources: Union[int, None] = None - renewable_sources: Union[int, None] = None - solar_energy_striking_earth_today: Union[int, None] = None - oil_pumped_today: Union[int, None] = None - oil_left: Union[int, None] = None - days_to_the_end_of_oil: Union[int, None] = None - natural_gas_left: Union[int, None] = None - days_to_the_end_of_natural_gas: Union[int, None] = None - coal_left: Union[int, None] = None - days_to_the_end_of_coal: Union[int, None] = None + + def __init__(self) -> None: + self._data = self._load_data() + self.energy_used_today = self._data.get('energy_used') + self.non_renewable_sources = self._data.get('energy_nonren') + self.renewable_sources = self._data.get('energy_ren') + self.solar_energy_striking_earth_today = self._data.get('solar_energy') + self.oil_pumped_today = self._data.get('oil_consumption') + self.oil_left = self._data.get('oil_reserves') + self.days_to_the_end_of_oil = self._data.get('oil_days') + self.natural_gas_left = self._data.get('gas_reserves') + self.days_to_the_end_of_natural_gas = self._data.get('gas_days') + self.coal_left = self._data.get('coal_reserves') + self.days_to_the_end_of_coal = self._data.get('coal_days') + + def _load_data(self) -> dict: + return {} -@dataclass class Health: - _data: dict = field(default_factory=dict, repr=False, init=False) - communicable_disease_deaths_this_year: Union[int, None] = None - seasonal_flu_deaths_this_year: Union[int, None] = None - deaths_of_children_under_5_this_year: Union[int, None] = None - abortions_this_year: Union[int, None] = None - deaths_of_mothers_during_birth_this_year: Union[int, None] = None - hiv_aids_infected_people: Union[int, None] = None - deaths_caused_by_hiv_aids_this_year: Union[int, None] = None - deaths_caused_by_cancer_this_year: Union[int, None] = None - deaths_caused_by_malaria_this_year: Union[int, None] = None - cigarettes_smoked_today: Union[int, None] = None - deaths_caused_by_smoking_this_year: Union[int, None] = None - deaths_caused_by_alcohol_this_year: Union[int, None] = None - suicides_this_year: Union[int, None] = None - money_spent_on_illegal_drugs_this_year: Union[int, None] = None - road_traffic_accident_fatalities_this_year: Union[int, None] = None + + def __init__(self) -> None: + self._data = self._load_data() + self.communicable_disease_deaths_this_year = self._data.get('dth1s_communicable_disaxs') + self.seasonal_flu_deaths_this_year = self._data.get('dth1s_flu') + self.deaths_of_children_under_5_this_year = self._data.get('dth1s_children') + self.abortions_this_year = self._data.get('ab') + self.deaths_of_mothers_during_birth_this_year = self._data.get('dth1s_maternal') + self.hiv_aids_infected_people = self._data.get('infections_hiv') + self.deaths_caused_by_hiv_aids_this_year = self._data.get('dth1s_ads') + self.deaths_caused_by_cancer_this_year = self._data.get('dth1s_cancer') + self.deaths_caused_by_malaria_this_year = self._data.get('dth1s_malarial') + self.cigarettes_smoked_today = self._data.get('cigarettes_smoked') + self.deaths_caused_by_smoking_this_year = self._data.get('dth1s_cigarettes') + self.deaths_caused_by_alcohol_this_year = self._data.get('dth1s_alchool') + self.suicides_this_year = self._data.get('sui') + self.money_spent_on_illegal_drugs_this_year = self._data.get('drug_spending') + self.road_traffic_accident_fatalities_this_year = self._data.get('dth1s_cars') + + def _load_data(self) -> dict: + return {} @dataclass From 094006d7e2c038914d2ed6913828c877c25f7caa Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 17 Aug 2023 19:32:11 -0300 Subject: [PATCH 003/147] refactor: change CountryCodes dataclass to common class --- worldometer/world/ometers.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/worldometer/world/ometers.py b/worldometer/world/ometers.py index 9acdf2b..40e1610 100644 --- a/worldometer/world/ometers.py +++ b/worldometer/world/ometers.py @@ -1,4 +1,4 @@ -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import List @@ -147,10 +147,10 @@ class CountryCodeData: three_digit_iso_numeric: str -@dataclass class CountryCodes: - _data: List[CountryCodeData] = field( - default_factory=list, - repr=False, - init=False - ) + + def __init__(self) -> None: + self._data = self._load_data() + + def _load_data(self) -> List[CountryCodeData]: + return [] From bb6dbffe8f41fbb2c40c0262a1bfad46aa11c744 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 17 Aug 2023 19:37:59 -0300 Subject: [PATCH 004/147] refactor: create country_codes module and move CountryCodes class --- worldometer/world/__init__.py | 4 +++- worldometer/world/country_codes.py | 20 ++++++++++++++++++++ worldometer/world/ometers.py | 23 ----------------------- 3 files changed, 23 insertions(+), 24 deletions(-) create mode 100644 worldometer/world/country_codes.py diff --git a/worldometer/world/__init__.py b/worldometer/world/__init__.py index 4be236a..d986c2b 100644 --- a/worldometer/world/__init__.py +++ b/worldometer/world/__init__.py @@ -6,7 +6,8 @@ 'Health', 'SocietyAndMedia', 'Water', - 'WorldPopulation' + 'WorldPopulation', + 'CountryCodes' ] from worldometer.world.ometers import ( @@ -19,3 +20,4 @@ Water, WorldPopulation ) +from worldometer.world.country_codes import CountryCodes diff --git a/worldometer/world/country_codes.py b/worldometer/world/country_codes.py new file mode 100644 index 0000000..82cdcf9 --- /dev/null +++ b/worldometer/world/country_codes.py @@ -0,0 +1,20 @@ +from dataclasses import dataclass +from typing import List + + +@dataclass +class CountryCodeData: + country: str + calling_code: str + three_letter_iso: str + two_letter_iso: str + three_digit_iso_numeric: str + + +class CountryCodes: + + def __init__(self) -> None: + self._data = self._load_data() + + def _load_data(self) -> List[CountryCodeData]: + return [] diff --git a/worldometer/world/ometers.py b/worldometer/world/ometers.py index 40e1610..f57d497 100644 --- a/worldometer/world/ometers.py +++ b/worldometer/world/ometers.py @@ -1,8 +1,3 @@ -from dataclasses import dataclass - -from typing import List - - class WorldPopulation: def __init__(self) -> None: @@ -136,21 +131,3 @@ def __init__(self) -> None: def _load_data(self) -> dict: return {} - - -@dataclass -class CountryCodeData: - country: str - calling_code: str - three_letter_iso: str - two_letter_iso: str - three_digit_iso_numeric: str - - -class CountryCodes: - - def __init__(self) -> None: - self._data = self._load_data() - - def _load_data(self) -> List[CountryCodeData]: - return [] From 19c679548de5b5821f60c55fb21ce2f31fd1d73f Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 17 Aug 2023 19:46:48 -0300 Subject: [PATCH 005/147] feat: define data method in countryCodes class --- worldometer/world/country_codes.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/worldometer/world/country_codes.py b/worldometer/world/country_codes.py index 82cdcf9..799bb01 100644 --- a/worldometer/world/country_codes.py +++ b/worldometer/world/country_codes.py @@ -1,3 +1,4 @@ +from copy import deepcopy from dataclasses import dataclass from typing import List @@ -18,3 +19,6 @@ def __init__(self) -> None: def _load_data(self) -> List[CountryCodeData]: return [] + + def data(self) -> List[CountryCodeData]: + return deepcopy(self._data) From 51a06487622e5a355a26e189c54220bc4e403cc4 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 17 Aug 2023 19:57:29 -0300 Subject: [PATCH 006/147] refactor: rename CountryCodeData to CountryCodesData --- worldometer/world/country_codes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worldometer/world/country_codes.py b/worldometer/world/country_codes.py index 799bb01..4adfb9d 100644 --- a/worldometer/world/country_codes.py +++ b/worldometer/world/country_codes.py @@ -4,7 +4,7 @@ @dataclass -class CountryCodeData: +class CountryCodesData: country: str calling_code: str three_letter_iso: str @@ -17,8 +17,8 @@ class CountryCodes: def __init__(self) -> None: self._data = self._load_data() - def _load_data(self) -> List[CountryCodeData]: + def _load_data(self) -> List[CountryCodesData]: return [] - def data(self) -> List[CountryCodeData]: + def data(self) -> List[CountryCodesData]: return deepcopy(self._data) From 19a338ce875a0a0a037039eb990bec2b29992f61 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 17 Aug 2023 20:02:04 -0300 Subject: [PATCH 007/147] refactor: rename ometers module to counters --- worldometer/world/__init__.py | 2 +- worldometer/world/{ometers.py => counters.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename worldometer/world/{ometers.py => counters.py} (100%) diff --git a/worldometer/world/__init__.py b/worldometer/world/__init__.py index d986c2b..98f9315 100644 --- a/worldometer/world/__init__.py +++ b/worldometer/world/__init__.py @@ -10,7 +10,7 @@ 'CountryCodes' ] -from worldometer.world.ometers import ( +from worldometer.world.counters import ( Energy, Environment, Food, diff --git a/worldometer/world/ometers.py b/worldometer/world/counters.py similarity index 100% rename from worldometer/world/ometers.py rename to worldometer/world/counters.py From 06d793f18c97d3a94a11076b68ab73b0780d98ef Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 17 Aug 2023 21:46:00 -0300 Subject: [PATCH 008/147] refactor: create WorldCounters to encapsulate all counter classes All counter classes, with the exception of WorldCounters, are now dataclasses and are encapsulated within WorldCounters. This will make it easier to manage the data state without having to render the page in every instance. --- worldometer/world/__init__.py | 20 +------- worldometer/world/counters.py | 89 ++++++++++++++++++++--------------- 2 files changed, 52 insertions(+), 57 deletions(-) diff --git a/worldometer/world/__init__.py b/worldometer/world/__init__.py index 98f9315..db967d8 100644 --- a/worldometer/world/__init__.py +++ b/worldometer/world/__init__.py @@ -1,23 +1,7 @@ __all__ = [ - 'Energy', - 'Environment', - 'Food', - 'GovernmentAndEconomics', - 'Health', - 'SocietyAndMedia', - 'Water', - 'WorldPopulation', + 'WorldCounters', 'CountryCodes' ] -from worldometer.world.counters import ( - Energy, - Environment, - Food, - GovernmentAndEconomics, - Health, - SocietyAndMedia, - Water, - WorldPopulation -) +from worldometer.world.counters import WorldCounters from worldometer.world.country_codes import CountryCodes diff --git a/worldometer/world/counters.py b/worldometer/world/counters.py index f57d497..c4aa60a 100644 --- a/worldometer/world/counters.py +++ b/worldometer/world/counters.py @@ -1,7 +1,35 @@ -class WorldPopulation: +from dataclasses import dataclass, field +from typing import Dict + +class WorldCounters: def __init__(self) -> None: self._data = self._load_data() + self._init_counters() + + def _load_data(self) -> Dict[str, int]: + return {} + + def _init_counters(self) -> None: + self.world_population = WorldPopulation(self._data) + self.government_and_economics = GovernmentAndEconomics(self._data) + self.society_and_media = SocietyAndMedia(self._data) + self.environment = Environment(self._data) + self.food = Food(self._data) + self.water = Water(self._data) + self.energy = Energy(self._data) + self.health = Health(self._data) + + def reload_data(self): + self._data = self._load_data() + self._init_counters() + + +@dataclass +class WorldPopulation: + _data: Dict[str, int] = field(repr=False) + + def __post_init__(self) -> None: self.current_population = self._data.get('current_population') self.births_today = self._data.get('births_today') self.births_this_year = self._data.get('births_this_year') @@ -10,14 +38,12 @@ def __init__(self) -> None: self.net_population_growth_today = self._data.get('absolute_growth') self.net_population_growth_this_year = self._data.get('absolute_growth_year') - def _load_data(self) -> dict: - return {} - +@dataclass class GovernmentAndEconomics: + _data: Dict[str, int] = field(repr=False) - def __init__(self) -> None: - self._data = self._load_data() + def __post_init__(self) -> None: self.public_healthcare_expenditure_today = self._data.get('gov_expenditures_health') self.public_education_expenditure_today = self._data.get('gov_expenditures_education') self.public_military_expenditure_today = self._data.get('gov_expenditures_military') @@ -25,14 +51,12 @@ def __init__(self) -> None: self.bicycles_produced_this_year = self._data.get('bicycle_produced') self.computers_produced_this_year = self._data.get('computers_sold') - def _load_data(self) -> dict: - return {} - +@dataclass class SocietyAndMedia: + _data: Dict[str, int] = field(repr=False) - def __init__(self) -> None: - self._data = self._load_data() + def __post_init__(self) -> None: self.new_book_titles_published_this_year = self._data.get('books_published') self.newspapers_circulated_today = self._data.get('newspapers_circulated') self.tv_sets_sold_worldwide_today = self._data.get('tv') @@ -44,28 +68,24 @@ def __init__(self) -> None: self.tweets_sent_today = self._data.get('tweets') self.google_searches_today = self._data.get('google_searches') - def _load_data(self) -> dict: - return {} - +@dataclass class Environment: + _data: Dict[str, int] = field(repr=False) - def __init__(self) -> None: - self._data = self._load_data() + def __post_init__(self) -> None: self.forest_loss_this_year = self._data.get('forest_loss') self.land_lost_to_soil_erosion_this_year = self._data.get('soil_erosion') self.co2_emissions_this_year = self._data.get('co2_emissions') self.desertification_this_year = self._data.get('desert_land_formed') self.toxic_chemicals_released_in_the_environment_this_year = self._data.get('tox_chem') - def _load_data(self) -> dict: - return {} - +@dataclass class Food: + _data: Dict[str, int] = field(repr=False) - def __init__(self) -> None: - self._data = self._load_data() + def __post_init__(self) -> None: self.undernourished_people_in_the_world = self._data.get('undernourished') self.overweight_people_in_the_world = self._data.get('overweight') self.obese_people_in_the_world = self._data.get('obese') @@ -73,26 +93,22 @@ def __init__(self) -> None: self.money_spent_for_obesity_related_diseases_in_the_usa_today = self._data.get('obesity_spending') self.money_spent_on_weight_loss_programs_in_the_usa_today = self._data.get('spending_on_weight_loss') - def _load_data(self) -> dict: - return {} - +@dataclass class Water: + _data: Dict[str, int] - def __init__(self) -> None: - self._data = self._load_data() + def __post_init__(self) -> None: self.water_used_this_year = self._data.get('water_consumed') self.deaths_caused_by_water_related_diseases_this_year = self._data.get('water_disax') self.people_with_no_access_to_a_safe_drinking_water_source = self._data.get('nowater_population') - def _load_data(self) -> dict: - return {} - +@dataclass class Energy: + _data: Dict[str, int] = field(repr=False) - def __init__(self) -> None: - self._data = self._load_data() + def __post_init__(self) -> None: self.energy_used_today = self._data.get('energy_used') self.non_renewable_sources = self._data.get('energy_nonren') self.renewable_sources = self._data.get('energy_ren') @@ -105,14 +121,12 @@ def __init__(self) -> None: self.coal_left = self._data.get('coal_reserves') self.days_to_the_end_of_coal = self._data.get('coal_days') - def _load_data(self) -> dict: - return {} - +@dataclass class Health: + _data: Dict[str, int] = field(repr=False) - def __init__(self) -> None: - self._data = self._load_data() + def __post_init__(self) -> None: self.communicable_disease_deaths_this_year = self._data.get('dth1s_communicable_disaxs') self.seasonal_flu_deaths_this_year = self._data.get('dth1s_flu') self.deaths_of_children_under_5_this_year = self._data.get('dth1s_children') @@ -128,6 +142,3 @@ def __init__(self) -> None: self.suicides_this_year = self._data.get('sui') self.money_spent_on_illegal_drugs_this_year = self._data.get('drug_spending') self.road_traffic_accident_fatalities_this_year = self._data.get('dth1s_cars') - - def _load_data(self) -> dict: - return {} From 531e74b2525410556afa2609b9d3754fbeb6a5f6 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Fri, 18 Aug 2023 01:36:19 -0300 Subject: [PATCH 009/147] feat: create scraper package and implement http requester --- worldometer/scraper/__init__.py | 0 worldometer/scraper/controller.py | 0 worldometer/scraper/http_requester.py | 30 +++++++++++++++++++++++++++ worldometer/scraper/parser.py | 0 4 files changed, 30 insertions(+) create mode 100644 worldometer/scraper/__init__.py create mode 100644 worldometer/scraper/controller.py create mode 100644 worldometer/scraper/http_requester.py create mode 100644 worldometer/scraper/parser.py diff --git a/worldometer/scraper/__init__.py b/worldometer/scraper/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/worldometer/scraper/controller.py b/worldometer/scraper/controller.py new file mode 100644 index 0000000..e69de29 diff --git a/worldometer/scraper/http_requester.py b/worldometer/scraper/http_requester.py new file mode 100644 index 0000000..b95fd42 --- /dev/null +++ b/worldometer/scraper/http_requester.py @@ -0,0 +1,30 @@ +from typing import Dict, Union + +from requests_html import HTML, HTMLSession + + +class HTTPRequester: + + def __init__(self, timeout: int = 30) -> None: + self.base_url = 'https://www.worldometers.info' + self.session = HTMLSession() + self.timeout = timeout + + def get_page_content(self, url_path: str = '') -> HTML: + url = f'{self.base_url}/{url_path}' + res = self.session.get(url, timeout=self.timeout) + + # requests-html does not have the type hint set correctly in + # some modules (session.get is one of them), so type checkers + # report a problem. I will probably trade this package in the future. + html_obj = res.html # type: ignore + return html_obj + + def render_page(self, html_obj: HTML, script: str = '') -> Union[HTML, Dict[str, dict]]: + + script_return = html_obj.render(script=script) + + if script and script_return: + return script_return + + return HTML(html=html_obj.html) diff --git a/worldometer/scraper/parser.py b/worldometer/scraper/parser.py new file mode 100644 index 0000000..e69de29 From 8afdb4e57ba09c130d83716301c86d20d606dde2 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 19 Aug 2023 02:13:23 -0300 Subject: [PATCH 010/147] refactor: rename http_requester module to browser and more changes: - HTTPRequester -> Browser. This makes a lot more sense as the class doesn't just perform http requests. - Removal of base_url and timeout attributes. Both will be sent to the get_page_content method. - Separation of the responsibilities of rendering and executing a script injected into an html page for the render_page and run_js_script methods. --- worldometer/scraper/browser.py | 25 ++++++++++++++++++++++ worldometer/scraper/http_requester.py | 30 --------------------------- 2 files changed, 25 insertions(+), 30 deletions(-) create mode 100644 worldometer/scraper/browser.py delete mode 100644 worldometer/scraper/http_requester.py diff --git a/worldometer/scraper/browser.py b/worldometer/scraper/browser.py new file mode 100644 index 0000000..32d4064 --- /dev/null +++ b/worldometer/scraper/browser.py @@ -0,0 +1,25 @@ +from typing import Dict + +from requests_html import HTML, HTMLSession + + +class Browser: + + def __init__(self) -> None: + self.session = HTMLSession() + + def get_page_content(self, url: str, timeout: int = 30) -> HTML: + res = self.session.get(url, timeout=timeout) + + # requests-html does not have the type hint set correctly in + # some modules (session.get is one of them), so type checkers + # report a problem. I will probably trade this package in the future. + html_obj = res.html # type: ignore + return html_obj + + def render_page(self, html_obj: HTML) -> None: + html_obj.render() + + def run_js_script(self, html_obj: HTML, script: str = '') -> Dict[str, dict]: + script_return = html_obj.render(script=script) + return script_return # type: ignore diff --git a/worldometer/scraper/http_requester.py b/worldometer/scraper/http_requester.py deleted file mode 100644 index b95fd42..0000000 --- a/worldometer/scraper/http_requester.py +++ /dev/null @@ -1,30 +0,0 @@ -from typing import Dict, Union - -from requests_html import HTML, HTMLSession - - -class HTTPRequester: - - def __init__(self, timeout: int = 30) -> None: - self.base_url = 'https://www.worldometers.info' - self.session = HTMLSession() - self.timeout = timeout - - def get_page_content(self, url_path: str = '') -> HTML: - url = f'{self.base_url}/{url_path}' - res = self.session.get(url, timeout=self.timeout) - - # requests-html does not have the type hint set correctly in - # some modules (session.get is one of them), so type checkers - # report a problem. I will probably trade this package in the future. - html_obj = res.html # type: ignore - return html_obj - - def render_page(self, html_obj: HTML, script: str = '') -> Union[HTML, Dict[str, dict]]: - - script_return = html_obj.render(script=script) - - if script and script_return: - return script_return - - return HTML(html=html_obj.html) From 09c42f2d2bfac07e4784992ea599c163ab00b8ef Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 21 Aug 2023 15:07:41 -0300 Subject: [PATCH 011/147] feat: create getter of rts_counters object --- worldometer/scraper/parser.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/worldometer/scraper/parser.py b/worldometer/scraper/parser.py index e69de29..86ff8d9 100644 --- a/worldometer/scraper/parser.py +++ b/worldometer/scraper/parser.py @@ -0,0 +1,5 @@ +from typing import Dict + + +def get_rts_counters_only_with_last_value_key(rts_counters: Dict[str, dict]): + return {key: val.get('last_value') for key, val in rts_counters.items()} From dfb6b96963514eb553531543ee45167185947cde Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 21 Aug 2023 16:01:51 -0300 Subject: [PATCH 012/147] fix: define type hint of rts_counters parser --- worldometer/scraper/parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldometer/scraper/parser.py b/worldometer/scraper/parser.py index 86ff8d9..a58a940 100644 --- a/worldometer/scraper/parser.py +++ b/worldometer/scraper/parser.py @@ -1,5 +1,5 @@ -from typing import Dict +from typing import Dict, Optional -def get_rts_counters_only_with_last_value_key(rts_counters: Dict[str, dict]): +def get_rts_counters_only_with_last_value_key(rts_counters: Dict[str, dict]) -> Dict[str, Optional[int]]: return {key: val.get('last_value') for key, val in rts_counters.items()} From 2a055b7516eb52f1759c3b09a821b40a3cf556a9 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 21 Aug 2023 16:05:33 -0300 Subject: [PATCH 013/147] feat: implement scraper controller to get rts_counters object --- worldometer/scraper/controller.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/worldometer/scraper/controller.py b/worldometer/scraper/controller.py index e69de29..4aab753 100644 --- a/worldometer/scraper/controller.py +++ b/worldometer/scraper/controller.py @@ -0,0 +1,14 @@ +from typing import Dict, Optional + +from worldometer.scraper.browser import Browser +from worldometer.scraper.parser import get_rts_counters_only_with_last_value_key + + +browser = Browser() + + +def get_rts_counters_object() -> Dict[str, Optional[int]]: + html = browser.get_page_content('https://www.worldometers.info') + script_return = browser.run_js_script(html, script='() => rts_counters') + rts_counters = get_rts_counters_only_with_last_value_key(rts_counters=script_return) + return rts_counters From 217b858de7d3853d2abf88a0c96dd93849df216f Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 21 Aug 2023 16:33:53 -0300 Subject: [PATCH 014/147] refactor: define base_url const of worldometers.info --- worldometer/scraper/controller.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worldometer/scraper/controller.py b/worldometer/scraper/controller.py index 4aab753..6e2e28d 100644 --- a/worldometer/scraper/controller.py +++ b/worldometer/scraper/controller.py @@ -3,12 +3,13 @@ from worldometer.scraper.browser import Browser from worldometer.scraper.parser import get_rts_counters_only_with_last_value_key +BASE_URL = 'https://www.worldometers.info' browser = Browser() def get_rts_counters_object() -> Dict[str, Optional[int]]: - html = browser.get_page_content('https://www.worldometers.info') + html = browser.get_page_content(BASE_URL) script_return = browser.run_js_script(html, script='() => rts_counters') rts_counters = get_rts_counters_only_with_last_value_key(rts_counters=script_return) return rts_counters From 73ba6ee6e9c0f16e8594ca87c27b5efef57f902c Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 21 Aug 2023 17:58:09 -0300 Subject: [PATCH 015/147] feat: create utils module and make_url function to use in controller --- worldometer/scraper/controller.py | 5 ++++- worldometer/scraper/utils.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 worldometer/scraper/utils.py diff --git a/worldometer/scraper/controller.py b/worldometer/scraper/controller.py index 6e2e28d..3d456e3 100644 --- a/worldometer/scraper/controller.py +++ b/worldometer/scraper/controller.py @@ -3,13 +3,16 @@ from worldometer.scraper.browser import Browser from worldometer.scraper.parser import get_rts_counters_only_with_last_value_key +from worldometer.scraper.utils import make_url + BASE_URL = 'https://www.worldometers.info' browser = Browser() def get_rts_counters_object() -> Dict[str, Optional[int]]: - html = browser.get_page_content(BASE_URL) + url = make_url(BASE_URL) + html = browser.get_page_content(url) script_return = browser.run_js_script(html, script='() => rts_counters') rts_counters = get_rts_counters_only_with_last_value_key(rts_counters=script_return) return rts_counters diff --git a/worldometer/scraper/utils.py b/worldometer/scraper/utils.py new file mode 100644 index 0000000..a992ca3 --- /dev/null +++ b/worldometer/scraper/utils.py @@ -0,0 +1,10 @@ +import re + +from typing import Optional + + +def make_url(base_url: str, path_url: Optional[str] = None) -> str: + url = base_url + if path_url and re.match(r'^/{1}.+', path_url): + url += path_url + return url From e6dcdc18fd4c813717ffd48885533f986be0f80c Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 26 Aug 2023 01:00:35 -0300 Subject: [PATCH 016/147] chore: set pandas as dependency --- Pipfile | 1 + Pipfile.lock | 925 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 545 insertions(+), 381 deletions(-) diff --git a/Pipfile b/Pipfile index 6359526..85c5da5 100644 --- a/Pipfile +++ b/Pipfile @@ -5,6 +5,7 @@ name = "pypi" [packages] requests-html = "0.10.0" +pandas = "*" [dev-packages] pylint = "2.6.0" diff --git a/Pipfile.lock b/Pipfile.lock index d9d8f33..161227b 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "3a37814eebe63bcde3a5c6749cc05a45e39e711f5ed01c0f8953581b81d07d3a" + "sha256": "a94bf33a7491abd7e9e5e360f96c4b865e39bfd74195cf178c753d0f7ecb95c0" }, "pipfile-spec": 6, "requires": {}, @@ -23,11 +23,11 @@ }, "beautifulsoup4": { "hashes": [ - "sha256:58d5c3d29f5a36ffeb94f02f0d786cd53014cf9b3b3951d42e0080d8a9498d30", - "sha256:ad9aa55b65ef2808eb405f46cf74df7fcb7044d5cbc26487f96eb2ef2e436693" + "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da", + "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a" ], - "markers": "python_version >= '3.6'", - "version": "==4.11.1" + "markers": "python_full_version >= '3.6.0'", + "version": "==4.12.2" }, "bs4": { "hashes": [ @@ -37,27 +37,92 @@ }, "certifi": { "hashes": [ - "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3", - "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18" + "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082", + "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9" ], "markers": "python_version >= '3.6'", - "version": "==2022.12.7" + "version": "==2023.7.22" }, "charset-normalizer": { "hashes": [ - "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", - "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" - ], - "markers": "python_version >= '3.6'", - "version": "==2.1.1" - }, - "colorama": { - "hashes": [ - "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", - "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" - ], - "markers": "platform_system == 'Windows'", - "version": "==0.4.6" + "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96", + "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c", + "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710", + "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706", + "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020", + "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252", + "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad", + "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329", + "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a", + "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f", + "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6", + "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4", + "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a", + "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46", + "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2", + "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23", + "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace", + "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd", + "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982", + "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10", + "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2", + "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea", + "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09", + "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5", + "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149", + "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489", + "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9", + "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80", + "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592", + "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3", + "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6", + "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed", + "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c", + "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200", + "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a", + "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e", + "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d", + "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6", + "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623", + "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669", + "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3", + "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa", + "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9", + "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2", + "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f", + "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1", + "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4", + "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a", + "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8", + "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3", + "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029", + "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f", + "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959", + "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22", + "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7", + "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952", + "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346", + "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e", + "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d", + "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299", + "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd", + "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a", + "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3", + "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037", + "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94", + "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c", + "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858", + "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a", + "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449", + "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c", + "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918", + "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1", + "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c", + "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac", + "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.2.0" }, "cssselect": { "hashes": [ @@ -69,10 +134,10 @@ }, "fake-useragent": { "hashes": [ - "sha256:579c72b18ba792a5bd54ba48e63e464d21933e336472c974091a6757f31bfcdc", - "sha256:9f9b3667d3741ba81e34ebf9a6aa32658ecf7835499257826dd72642af629d59" + "sha256:ad2b5414d19493d0789572f04200d4f656f84d20b205cc805233212957fe385d", + "sha256:b411f903331f695e3840ccadcf011f745a405764e97c588f2b8fde9e400a5446" ], - "version": "==1.1.1" + "version": "==1.2.1" }, "idna": { "hashes": [ @@ -84,98 +149,179 @@ }, "importlib-metadata": { "hashes": [ - "sha256:d5059f9f1e8e41f80e9c56c2ee58811450c31984dfa625329ffd7c0dad88a73b", - "sha256:d84d17e21670ec07990e1044a99efe8d615d860fd176fc29ef5c306068fda313" + "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb", + "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743" ], - "markers": "python_version >= '3.7'", - "version": "==5.1.0" - }, - "importlib-resources": { - "hashes": [ - "sha256:32bb095bda29741f6ef0e5278c42df98d135391bee5f932841efc0041f748dc3", - "sha256:c09b067d82e72c66f4f8eb12332f5efbebc9b007c0b6c40818108c9870adc363" - ], - "markers": "python_version < '3.10'", - "version": "==5.10.1" + "markers": "python_version >= '3.8'", + "version": "==6.8.0" }, "lxml": { "hashes": [ - "sha256:01d36c05f4afb8f7c20fd9ed5badca32a2029b93b1750f571ccc0b142531caf7", - "sha256:04876580c050a8c5341d706dd464ff04fd597095cc8c023252566a8826505726", - "sha256:05ca3f6abf5cf78fe053da9b1166e062ade3fa5d4f92b4ed688127ea7d7b1d03", - "sha256:090c6543d3696cbe15b4ac6e175e576bcc3f1ccfbba970061b7300b0c15a2140", - "sha256:0dc313ef231edf866912e9d8f5a042ddab56c752619e92dfd3a2c277e6a7299a", - "sha256:0f2b1e0d79180f344ff9f321327b005ca043a50ece8713de61d1cb383fb8ac05", - "sha256:13598ecfbd2e86ea7ae45ec28a2a54fb87ee9b9fdb0f6d343297d8e548392c03", - "sha256:16efd54337136e8cd72fb9485c368d91d77a47ee2d42b057564aae201257d419", - "sha256:1ab8f1f932e8f82355e75dda5413a57612c6ea448069d4fb2e217e9a4bed13d4", - "sha256:223f4232855ade399bd409331e6ca70fb5578efef22cf4069a6090acc0f53c0e", - "sha256:2455cfaeb7ac70338b3257f41e21f0724f4b5b0c0e7702da67ee6c3640835b67", - "sha256:2899456259589aa38bfb018c364d6ae7b53c5c22d8e27d0ec7609c2a1ff78b50", - "sha256:2a29ba94d065945944016b6b74e538bdb1751a1db6ffb80c9d3c2e40d6fa9894", - "sha256:2a87fa548561d2f4643c99cd13131acb607ddabb70682dcf1dff5f71f781a4bf", - "sha256:2e430cd2824f05f2d4f687701144556646bae8f249fd60aa1e4c768ba7018947", - "sha256:36c3c175d34652a35475a73762b545f4527aec044910a651d2bf50de9c3352b1", - "sha256:3818b8e2c4b5148567e1b09ce739006acfaa44ce3156f8cbbc11062994b8e8dd", - "sha256:3efea981d956a6f7173b4659849f55081867cf897e719f57383698af6f618a92", - "sha256:5344a43228767f53a9df6e5b253f8cdca7dfc7b7aeae52551958192f56d98457", - "sha256:58bfa3aa19ca4c0f28c5dde0ff56c520fbac6f0daf4fac66ed4c8d2fb7f22e74", - "sha256:5b4545b8a40478183ac06c073e81a5ce4cf01bf1734962577cf2bb569a5b3bbf", - "sha256:5f50a1c177e2fa3ee0667a5ab79fdc6b23086bc8b589d90b93b4bd17eb0e64d1", - "sha256:63da2ccc0857c311d764e7d3d90f429c252e83b52d1f8f1d1fe55be26827d1f4", - "sha256:6749649eecd6a9871cae297bffa4ee76f90b4504a2a2ab528d9ebe912b101975", - "sha256:6804daeb7ef69e7b36f76caddb85cccd63d0c56dedb47555d2fc969e2af6a1a5", - "sha256:689bb688a1db722485e4610a503e3e9210dcc20c520b45ac8f7533c837be76fe", - "sha256:6943826a0374fb135bb11843594eda9ae150fba9d1d027d2464c713da7c09afe", - "sha256:699a9af7dffaf67deeae27b2112aa06b41c370d5e7633e0ee0aea2e0b6c211f7", - "sha256:76cf573e5a365e790396a5cc2b909812633409306c6531a6877c59061e42c4f2", - "sha256:7b515674acfdcadb0eb5d00d8a709868173acece5cb0be3dd165950cbfdf5409", - "sha256:7b770ed79542ed52c519119473898198761d78beb24b107acf3ad65deae61f1f", - "sha256:7d2278d59425777cfcb19735018d897ca8303abe67cc735f9f97177ceff8027f", - "sha256:7e91ee82f4199af8c43d8158024cbdff3d931df350252288f0d4ce656df7f3b5", - "sha256:821b7f59b99551c69c85a6039c65b75f5683bdc63270fec660f75da67469ca24", - "sha256:822068f85e12a6e292803e112ab876bc03ed1f03dddb80154c395f891ca6b31e", - "sha256:8340225bd5e7a701c0fa98284c849c9b9fc9238abf53a0ebd90900f25d39a4e4", - "sha256:85cabf64adec449132e55616e7ca3e1000ab449d1d0f9d7f83146ed5bdcb6d8a", - "sha256:880bbbcbe2fca64e2f4d8e04db47bcdf504936fa2b33933efd945e1b429bea8c", - "sha256:8e20cb5a47247e383cf4ff523205060991021233ebd6f924bca927fcf25cf86f", - "sha256:9b22c5c66f67ae00c0199f6055705bc3eb3fcb08d03d2ec4059a2b1b25ed48d7", - "sha256:9f102706d0ca011de571de32c3247c6476b55bb6bc65a20f682f000b07a4852a", - "sha256:a08cff61517ee26cb56f1e949cca38caabe9ea9fbb4b1e10a805dc39844b7d5c", - "sha256:a0a336d6d3e8b234a3aae3c674873d8f0e720b76bc1d9416866c41cd9500ffb9", - "sha256:a35f8b7fa99f90dd2f5dc5a9fa12332642f087a7641289ca6c40d6e1a2637d8e", - "sha256:a38486985ca49cfa574a507e7a2215c0c780fd1778bb6290c21193b7211702ab", - "sha256:a5da296eb617d18e497bcf0a5c528f5d3b18dadb3619fbdadf4ed2356ef8d941", - "sha256:a6e441a86553c310258aca15d1c05903aaf4965b23f3bc2d55f200804e005ee5", - "sha256:a82d05da00a58b8e4c0008edbc8a4b6ec5a4bc1e2ee0fb6ed157cf634ed7fa45", - "sha256:ab323679b8b3030000f2be63e22cdeea5b47ee0abd2d6a1dc0c8103ddaa56cd7", - "sha256:b1f42b6921d0e81b1bcb5e395bc091a70f41c4d4e55ba99c6da2b31626c44892", - "sha256:b23e19989c355ca854276178a0463951a653309fb8e57ce674497f2d9f208746", - "sha256:b264171e3143d842ded311b7dccd46ff9ef34247129ff5bf5066123c55c2431c", - "sha256:b26a29f0b7fc6f0897f043ca366142d2b609dc60756ee6e4e90b5f762c6adc53", - "sha256:b9cc34af337a97d470040f99ba4282f6e6bac88407d021688a5d585e44a23184", - "sha256:bc718cd47b765e790eecb74d044cc8d37d58562f6c314ee9484df26276d36a38", - "sha256:c83203addf554215463b59f6399835201999b5e48019dc17f182ed5ad87205c9", - "sha256:c9ec3eaf616d67db0764b3bb983962b4f385a1f08304fd30c7283954e6a7869b", - "sha256:ca34efc80a29351897e18888c71c6aca4a359247c87e0b1c7ada14f0ab0c0fb2", - "sha256:ca989b91cf3a3ba28930a9fc1e9aeafc2a395448641df1f387a2d394638943b0", - "sha256:d17bc7c2ccf49c478c5bdd447594e82692c74222698cfc9b5daae7ae7e90743b", - "sha256:d6b430a9938a5a5d85fc107d852262ddcd48602c120e3dbb02137c83d212b380", - "sha256:da4dd7c9c50c059aba52b3524f84d7de956f7fef88f0bafcf4ad7dde94a064e8", - "sha256:df0623dcf9668ad0445e0558a21211d4e9a149ea8f5666917c8eeec515f0a6d1", - "sha256:e5168986b90a8d1f2f9dc1b841467c74221bd752537b99761a93d2d981e04889", - "sha256:efa29c2fe6b4fdd32e8ef81c1528506895eca86e1d8c4657fda04c9b3786ddf9", - "sha256:f1496ea22ca2c830cbcbd473de8f114a320da308438ae65abad6bab7867fe38f", - "sha256:f49e52d174375a7def9915c9f06ec4e569d235ad428f70751765f48d5926678c" + "sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3", + "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d", + "sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a", + "sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120", + "sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305", + "sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287", + "sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23", + "sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52", + "sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f", + "sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4", + "sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584", + "sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f", + "sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693", + "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef", + "sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5", + "sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02", + "sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc", + "sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7", + "sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da", + "sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a", + "sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40", + "sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8", + "sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd", + "sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601", + "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c", + "sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be", + "sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2", + "sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c", + "sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129", + "sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc", + "sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2", + "sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1", + "sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7", + "sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d", + "sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477", + "sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d", + "sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e", + "sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7", + "sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2", + "sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574", + "sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf", + "sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b", + "sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98", + "sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12", + "sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42", + "sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35", + "sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d", + "sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce", + "sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d", + "sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f", + "sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db", + "sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4", + "sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694", + "sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac", + "sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2", + "sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7", + "sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96", + "sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d", + "sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b", + "sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a", + "sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13", + "sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340", + "sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6", + "sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458", + "sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c", + "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c", + "sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9", + "sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432", + "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991", + "sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69", + "sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf", + "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb", + "sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b", + "sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833", + "sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76", + "sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85", + "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e", + "sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50", + "sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8", + "sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4", + "sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b", + "sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5", + "sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190", + "sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7", + "sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa", + "sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0", + "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9", + "sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0", + "sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b", + "sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5", + "sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7", + "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==4.9.2" + "version": "==4.9.3" + }, + "numpy": { + "hashes": [ + "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2", + "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55", + "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf", + "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01", + "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca", + "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901", + "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d", + "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4", + "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf", + "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380", + "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044", + "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545", + "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f", + "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f", + "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3", + "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364", + "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9", + "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418", + "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f", + "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295", + "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3", + "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187", + "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926", + "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357", + "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760" + ], + "markers": "python_version >= '3.10'", + "version": "==1.25.2" + }, + "pandas": { + "hashes": [ + "sha256:04dbdbaf2e4d46ca8da896e1805bc04eb85caa9a82e259e8eed00254d5e0c682", + "sha256:1168574b036cd8b93abc746171c9b4f1b83467438a5e45909fed645cf8692dbc", + "sha256:1994c789bf12a7c5098277fb43836ce090f1073858c10f9220998ac74f37c69b", + "sha256:258d3624b3ae734490e4d63c430256e716f488c4fcb7c8e9bde2d3aa46c29089", + "sha256:32fca2ee1b0d93dd71d979726b12b61faa06aeb93cf77468776287f41ff8fdc5", + "sha256:37673e3bdf1551b95bf5d4ce372b37770f9529743d2498032439371fc7b7eb26", + "sha256:3ef285093b4fe5058eefd756100a367f27029913760773c8bf1d2d8bebe5d210", + "sha256:5247fb1ba347c1261cbbf0fcfba4a3121fbb4029d95d9ef4dc45406620b25c8b", + "sha256:5ec591c48e29226bcbb316e0c1e9423622bc7a4eaf1ef7c3c9fa1a3981f89641", + "sha256:694888a81198786f0e164ee3a581df7d505024fbb1f15202fc7db88a71d84ebd", + "sha256:69d7f3884c95da3a31ef82b7618af5710dba95bb885ffab339aad925c3e8ce78", + "sha256:6a21ab5c89dcbd57f78d0ae16630b090eec626360085a4148693def5452d8a6b", + "sha256:81af086f4543c9d8bb128328b5d32e9986e0c84d3ee673a2ac6fb57fd14f755e", + "sha256:9e4da0d45e7f34c069fe4d522359df7d23badf83abc1d1cef398895822d11061", + "sha256:9eae3dc34fa1aa7772dd3fc60270d13ced7346fcbcfee017d3132ec625e23bb0", + "sha256:9ee1a69328d5c36c98d8e74db06f4ad518a1840e8ccb94a4ba86920986bb617e", + "sha256:b084b91d8d66ab19f5bb3256cbd5ea661848338301940e17f4492b2ce0801fe8", + "sha256:b9cb1e14fdb546396b7e1b923ffaeeac24e4cedd14266c3497216dd4448e4f2d", + "sha256:ba619e410a21d8c387a1ea6e8a0e49bb42216474436245718d7f2e88a2f8d7c0", + "sha256:c02f372a88e0d17f36d3093a644c73cfc1788e876a7c4bcb4020a77512e2043c", + "sha256:ce0c6f76a0f1ba361551f3e6dceaff06bde7514a374aa43e33b588ec10420183", + "sha256:d9cd88488cceb7635aebb84809d087468eb33551097d600c6dad13602029c2df", + "sha256:e4c7c9f27a4185304c7caf96dc7d91bc60bc162221152de697c98eb0b2648dd8", + "sha256:f167beed68918d62bffb6ec64f2e1d8a7d297a038f86d4aed056b9493fca407f", + "sha256:f3421a7afb1a43f7e38e82e844e2bca9a6d793d66c1a7f9f0ff39a795bbc5e02" + ], + "index": "pypi", + "markers": "python_version >= '3.8'", + "version": "==2.0.3" }, "parse": { "hashes": [ - "sha256:9ff82852bcb65d139813e2a5197627a94966245c897796760a3a2a8eb66f020b" + "sha256:371ed3800dc63983832159cc9373156613947707bc448b5215473a219dbd4362", + "sha256:cc3a47236ff05da377617ddefa867b7ba983819c664e1afe46249e5b469be464" ], - "version": "==1.19.0" + "version": "==1.19.1" }, "pyee": { "hashes": [ @@ -189,23 +335,38 @@ "sha256:11a734d8f02c6b128035aba8faf32748f2016310a6a1cbc6aa5b1e2580742e8f", "sha256:ddb0d15cb644720160d49abb1ad0d97e87a55581febf1b7531be9e983aad7742" ], - "markers": "python_version >= '3.7' and python_version < '4'", + "markers": "python_version >= '3.7' and python_version < '4.0'", "version": "==1.0.2" }, "pyquery": { "hashes": [ - "sha256:1fc33b7699455ed25c75282bc8f80ace1ac078b0dda5a933dacbd8b1c1f83963", - "sha256:a388eefb6bc4a55350de0316fbd97cda999ae669b6743ae5b99102ba54f5aa72" + "sha256:8dfc9b4b7c5f877d619bbae74b1898d5743f6ca248cfd5d72b504dd614da312f", + "sha256:963e8d4e90262ff6d8dec072ea97285dc374a2f69cad7776f4082abcf6a1d8ae" + ], + "version": "==2.0.0" + }, + "python-dateutil": { + "hashes": [ + "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", + "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], - "version": "==1.4.3" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.8.2" + }, + "pytz": { + "hashes": [ + "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588", + "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb" + ], + "version": "==2023.3" }, "requests": { "hashes": [ - "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", - "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" + "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", + "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" ], - "markers": "python_version >= '3.7' and python_version < '4'", - "version": "==2.28.1" + "markers": "python_version >= '3.7'", + "version": "==2.31.0" }, "requests-html": { "hashes": [ @@ -213,39 +374,56 @@ "sha256:cb8a78cf829c4eca9d6233f28524f65dd2bfaafb4bdbbc407f0a0b8f487df6e2" ], "index": "pypi", + "markers": "python_full_version >= '3.6.0'", "version": "==0.10.0" }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" + }, "soupsieve": { "hashes": [ - "sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759", - "sha256:fc53893b3da2c33de295667a0e19f078c14bf86544af307354de5fcf12a3f30d" + "sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8", + "sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea" ], - "markers": "python_version >= '3.6'", - "version": "==2.3.2.post1" + "markers": "python_version >= '3.7'", + "version": "==2.4.1" }, "tqdm": { "hashes": [ - "sha256:5f4f682a004951c1b450bc753c710e9280c5746ce6ffedee253ddbcbf54cf1e4", - "sha256:6fee160d6ffcd1b1c68c65f14c829c22832bc401726335ce92c52d395944a6a1" + "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386", + "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==4.64.1" + "markers": "python_version >= '3.7'", + "version": "==4.66.1" + }, + "tzdata": { + "hashes": [ + "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a", + "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda" + ], + "markers": "python_version >= '2'", + "version": "==2023.3" }, "urllib3": { "hashes": [ - "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc", - "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8" + "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f", + "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.13" + "version": "==1.26.16" }, "w3lib": { "hashes": [ - "sha256:0e1198f1b745195b6b3dd1a4cd66011fbf82f30a4d9dabaee1f9e5c86f020274", - "sha256:7fd5bd7980a95d1a8185e867d05f68a591aa281a3ded4590d2641d7b09086ed4" + "sha256:c4432926e739caa8e3f49f5de783f336df563d9490416aebd5d39fb896d264e7", + "sha256:ed5b74e997eea2abe3c1321f916e344144ee8e9072a6f33463ee8e57f858a4b1" ], "markers": "python_version >= '3.7'", - "version": "==2.1.1" + "version": "==2.1.2" }, "websockets": { "hashes": [ @@ -324,76 +502,134 @@ }, "zipp": { "hashes": [ - "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa", - "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766" + "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0", + "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147" ], - "markers": "python_version >= '3.7'", - "version": "==3.11.0" + "markers": "python_version >= '3.8'", + "version": "==3.16.2" } }, "develop": { "alabaster": { "hashes": [ - "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359", - "sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02" + "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3", + "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2" ], - "version": "==0.7.12" + "markers": "python_version >= '3.6'", + "version": "==0.7.13" }, "astroid": { "hashes": [ - "sha256:10e0ad5f7b79c435179d0d0f0df69998c4eef4597534aae44910db060baeb907", - "sha256:1493fe8bd3dfd73dc35bd53c9d5b6e49ead98497c47b2307662556a5692d29d7" + "sha256:87ae7f2398b8a0ae5638ddecf9987f081b756e0e9fc071aeebdca525671fc4dc", + "sha256:b31c92f545517dcc452f284bc9c044050862fbe6d93d2b3de4a215a6b384bf0d" ], - "markers": "python_full_version >= '3.7.2'", - "version": "==2.12.13" + "markers": "python_version >= '3.6'", + "version": "==2.5" }, "babel": { "hashes": [ - "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe", - "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6" + "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610", + "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455" ], - "markers": "python_version >= '3.6'", - "version": "==2.11.0" + "markers": "python_version >= '3.7'", + "version": "==2.12.1" }, "certifi": { "hashes": [ - "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3", - "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18" + "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082", + "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9" ], "markers": "python_version >= '3.6'", - "version": "==2022.12.7" + "version": "==2023.7.22" }, "charset-normalizer": { "hashes": [ - "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845", - "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f" - ], - "markers": "python_version >= '3.6'", - "version": "==2.1.1" - }, - "colorama": { - "hashes": [ - "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", - "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" - ], - "markers": "platform_system == 'Windows'", - "version": "==0.4.6" - }, - "dill": { - "hashes": [ - "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0", - "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373" - ], - "markers": "python_version >= '3.7'", - "version": "==0.3.6" + "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96", + "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c", + "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710", + "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706", + "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020", + "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252", + "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad", + "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329", + "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a", + "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f", + "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6", + "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4", + "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a", + "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46", + "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2", + "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23", + "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace", + "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd", + "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982", + "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10", + "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2", + "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea", + "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09", + "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5", + "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149", + "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489", + "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9", + "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80", + "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592", + "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3", + "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6", + "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed", + "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c", + "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200", + "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a", + "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e", + "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d", + "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6", + "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623", + "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669", + "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3", + "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa", + "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9", + "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2", + "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f", + "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1", + "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4", + "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a", + "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8", + "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3", + "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029", + "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f", + "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959", + "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22", + "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7", + "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952", + "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346", + "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e", + "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d", + "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299", + "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd", + "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a", + "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3", + "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037", + "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94", + "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c", + "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858", + "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a", + "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449", + "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c", + "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918", + "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1", + "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c", + "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac", + "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa" + ], + "markers": "python_full_version >= '3.7.0'", + "version": "==3.2.0" }, "docutils": { "hashes": [ - "sha256:33995a6753c30b7f577febfc2c50411fec6aac7f7ffeb7c4cfe5991072dcf9e6", - "sha256:5e1de4d849fee02c63b040a4a3fd567f4ab104defd8a5511fbbc24a8a017efbc" + "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6", + "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b" ], "markers": "python_version >= '3.7'", - "version": "==0.19" + "version": "==0.20.1" }, "idna": { "hashes": [ @@ -411,21 +647,13 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.4.1" }, - "importlib-metadata": { - "hashes": [ - "sha256:d5059f9f1e8e41f80e9c56c2ee58811450c31984dfa625329ffd7c0dad88a73b", - "sha256:d84d17e21670ec07990e1044a99efe8d615d860fd176fc29ef5c306068fda313" - ], - "markers": "python_version >= '3.7'", - "version": "==5.1.0" - }, "isort": { "hashes": [ - "sha256:dd8bbc5c0990f2a095d754e50360915f73b4c26fc82733eb5bfc6b48396af4d2", - "sha256:e486966fba83f25b8045f8dd7455b0a0d1e4de481e1d7ce4669902d9fb85e622" + "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504", + "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6" ], - "markers": "python_version >= '3.7'", - "version": "==5.11.2" + "markers": "python_full_version >= '3.8.0'", + "version": "==5.12.0" }, "jinja2": { "hashes": [ @@ -437,129 +665,150 @@ }, "lazy-object-proxy": { "hashes": [ - "sha256:0c1c7c0433154bb7c54185714c6929acc0ba04ee1b167314a779b9025517eada", - "sha256:14010b49a2f56ec4943b6cf925f597b534ee2fe1f0738c84b3bce0c1a11ff10d", - "sha256:4e2d9f764f1befd8bdc97673261b8bb888764dfdbd7a4d8f55e4fbcabb8c3fb7", - "sha256:4fd031589121ad46e293629b39604031d354043bb5cdf83da4e93c2d7f3389fe", - "sha256:5b51d6f3bfeb289dfd4e95de2ecd464cd51982fe6f00e2be1d0bf94864d58acd", - "sha256:6850e4aeca6d0df35bb06e05c8b934ff7c533734eb51d0ceb2d63696f1e6030c", - "sha256:6f593f26c470a379cf7f5bc6db6b5f1722353e7bf937b8d0d0b3fba911998858", - "sha256:71d9ae8a82203511a6f60ca5a1b9f8ad201cac0fc75038b2dc5fa519589c9288", - "sha256:7e1561626c49cb394268edd00501b289053a652ed762c58e1081224c8d881cec", - "sha256:8f6ce2118a90efa7f62dd38c7dbfffd42f468b180287b748626293bf12ed468f", - "sha256:ae032743794fba4d171b5b67310d69176287b5bf82a21f588282406a79498891", - "sha256:afcaa24e48bb23b3be31e329deb3f1858f1f1df86aea3d70cb5c8578bfe5261c", - "sha256:b70d6e7a332eb0217e7872a73926ad4fdc14f846e85ad6749ad111084e76df25", - "sha256:c219a00245af0f6fa4e95901ed28044544f50152840c5b6a3e7b2568db34d156", - "sha256:ce58b2b3734c73e68f0e30e4e725264d4d6be95818ec0a0be4bb6bf9a7e79aa8", - "sha256:d176f392dbbdaacccf15919c77f526edf11a34aece58b55ab58539807b85436f", - "sha256:e20bfa6db17a39c706d24f82df8352488d2943a3b7ce7d4c22579cb89ca8896e", - "sha256:eac3a9a5ef13b332c059772fd40b4b1c3d45a3a2b05e33a361dee48e54a4dad0", - "sha256:eb329f8d8145379bf5dbe722182410fe8863d186e51bf034d2075eb8d85ee25b" + "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382", + "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82", + "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9", + "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494", + "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46", + "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30", + "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63", + "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4", + "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae", + "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be", + "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701", + "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd", + "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006", + "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a", + "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586", + "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8", + "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821", + "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07", + "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b", + "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171", + "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b", + "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2", + "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7", + "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4", + "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8", + "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e", + "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f", + "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda", + "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4", + "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e", + "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671", + "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11", + "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455", + "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734", + "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb", + "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59" ], "markers": "python_version >= '3.7'", - "version": "==1.8.0" + "version": "==1.9.0" }, "markupsafe": { "hashes": [ - "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", - "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", - "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", - "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", - "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", - "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", - "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", - "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", - "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", - "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", - "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", - "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", - "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", - "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", - "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", - "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", - "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", - "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", - "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", - "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", - "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", - "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", - "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", - "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", - "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", - "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", - "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", - "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", - "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", - "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", - "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", - "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", - "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", - "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", - "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", - "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", - "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", - "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", - "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", - "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" + "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e", + "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", + "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", + "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", + "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", + "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", + "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", + "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", + "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", + "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9", + "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", + "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", + "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", + "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", + "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", + "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", + "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac", + "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52", + "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", + "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", + "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", + "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", + "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", + "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", + "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0", + "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", + "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", + "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", + "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", + "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", + "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", + "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", + "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", + "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", + "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad", + "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee", + "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc", + "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2", + "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48", + "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7", + "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e", + "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b", + "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa", + "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5", + "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e", + "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb", + "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", + "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", + "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", + "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2" ], "markers": "python_version >= '3.7'", - "version": "==2.1.1" + "version": "==2.1.3" }, "mccabe": { "hashes": [ - "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", - "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" + "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", + "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" ], "markers": "python_version >= '3.6'", - "version": "==0.7.0" + "version": "==0.6.1" }, "packaging": { "hashes": [ - "sha256:2198ec20bd4c017b8f9717e00f0c8714076fc2fd93816750ab48e2c41de2cfd3", - "sha256:957e2148ba0e1a3b282772e791ef1d8083648bc131c8ab0c1feba110ce1146c3" - ], - "markers": "python_version >= '3.7'", - "version": "==22.0" - }, - "platformdirs": { - "hashes": [ - "sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca", - "sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e" + "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61", + "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f" ], "markers": "python_version >= '3.7'", - "version": "==2.6.0" + "version": "==23.1" }, "pygments": { "hashes": [ - "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1", - "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42" + "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692", + "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29" ], - "markers": "python_version >= '3.6'", - "version": "==2.13.0" + "markers": "python_version >= '3.7'", + "version": "==2.16.1" }, "pylint": { "hashes": [ - "sha256:ea82cd6a1e11062dc86d555d07c021b0fb65afe39becbe6fe692efd6c4a67443", - "sha256:ec4a87c33da054ab86a6c79afa6771dc8765cb5631620053e727fcf3ef8cbed7" + "sha256:bb4a908c9dadbc3aac18860550e870f58e1a02c9f2c204fdf5693d73be061210", + "sha256:bfe68f020f8a0fece830a22dd4d5dddb4ecc6137db04face4c3420a46a52239f" ], "index": "pypi", - "version": "==2.15.8" + "markers": "python_version >= '3.5'", + "version": "==2.6.0" }, - "pytz": { + "requests": { "hashes": [ - "sha256:222439474e9c98fced559f1709d89e6c9cbf8d79c794ff3eb9f8800064291427", - "sha256:e89512406b793ca39f5971bc999cc538ce125c0e51c27941bef4568b460095e2" + "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", + "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" ], - "version": "==2022.6" + "markers": "python_version >= '3.7'", + "version": "==2.31.0" }, - "requests": { + "setuptools": { "hashes": [ - "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", - "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" + "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d", + "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b" ], - "markers": "python_version >= '3.7' and python_version < '4'", - "version": "==2.28.1" + "markers": "python_version >= '3.8'", + "version": "==68.1.2" }, "snowballstemmer": { "hashes": [ @@ -570,19 +819,20 @@ }, "sphinx": { "hashes": [ - "sha256:060ca5c9f7ba57a08a1219e547b269fadf125ae25b06b9fa7f66768efb652d6d", - "sha256:51026de0a9ff9fc13c05d74913ad66047e104f56a129ff73e174eb5c3ee794b5" + "sha256:68da66ca3d6b35b22bea5c53d938d5f8988663dca042f0a46429a1eba1010051", + "sha256:deb468efb3abaa70d790add4147d18782d86fdeacf648d6e8afb7a99807f1546" ], "index": "pypi", - "version": "==5.3.0" + "markers": "python_version >= '3.5'", + "version": "==3.5.0" }, "sphinxcontrib-applehelp": { "hashes": [ - "sha256:806111e5e962be97c29ec4c1e7fe277bfd19e9652fb1a4392105b43e01af885a", - "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58" + "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228", + "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e" ], - "markers": "python_version >= '3.5'", - "version": "==1.0.2" + "markers": "python_version >= '3.8'", + "version": "==1.0.4" }, "sphinxcontrib-devhelp": { "hashes": [ @@ -594,11 +844,11 @@ }, "sphinxcontrib-htmlhelp": { "hashes": [ - "sha256:d412243dfb797ae3ec2b59eca0e52dac12e75a241bf0e4eb861e450d06c6ed07", - "sha256:f5f8bb2d0d629f398bf47d0d69c07bc13b65f75a81ad9e2f71a63d4b7a2f6db2" + "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff", + "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903" ], - "markers": "python_version >= '3.6'", - "version": "==2.0.0" + "markers": "python_version >= '3.8'", + "version": "==2.0.1" }, "sphinxcontrib-jsmath": { "hashes": [ @@ -624,115 +874,28 @@ "markers": "python_version >= '3.5'", "version": "==1.1.5" }, - "tomli": { + "toml": { "hashes": [ - "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" + "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", + "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" ], - "markers": "python_version < '3.11'", - "version": "==2.0.1" - }, - "tomlkit": { - "hashes": [ - "sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b", - "sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73" - ], - "markers": "python_version >= '3.6'", - "version": "==0.11.6" - }, - "typing-extensions": { - "hashes": [ - "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa", - "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e" - ], - "markers": "python_version < '3.10'", - "version": "==4.4.0" + "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.10.2" }, "urllib3": { "hashes": [ - "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc", - "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8" + "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f", + "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.13" + "version": "==1.26.16" }, "wrapt": { "hashes": [ - "sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3", - "sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b", - "sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4", - "sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2", - "sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656", - "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3", - "sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff", - "sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310", - "sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a", - "sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57", - "sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069", - "sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383", - "sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe", - "sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87", - "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d", - "sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b", - "sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907", - "sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f", - "sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0", - "sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28", - "sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1", - "sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853", - "sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc", - "sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3", - "sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3", - "sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164", - "sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1", - "sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c", - "sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1", - "sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7", - "sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1", - "sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320", - "sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed", - "sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1", - "sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248", - "sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c", - "sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456", - "sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77", - "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef", - "sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1", - "sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7", - "sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86", - "sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4", - "sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d", - "sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d", - "sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8", - "sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5", - "sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471", - "sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00", - "sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68", - "sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3", - "sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d", - "sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735", - "sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d", - "sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569", - "sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7", - "sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59", - "sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5", - "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb", - "sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b", - "sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f", - "sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462", - "sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015", - "sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af" + "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7" ], "markers": "python_version < '3.11'", - "version": "==1.14.1" - }, - "zipp": { - "hashes": [ - "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa", - "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766" - ], - "markers": "python_version >= '3.7'", - "version": "==3.11.0" + "version": "==1.12.1" } } } From 3b3f03e4f5e41b703f5399833a10e5c4c6699b09 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 26 Aug 2023 01:02:19 -0300 Subject: [PATCH 017/147] feat: implement html table data parser --- worldometer/scraper/parser.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/worldometer/scraper/parser.py b/worldometer/scraper/parser.py index a58a940..d38e9f1 100644 --- a/worldometer/scraper/parser.py +++ b/worldometer/scraper/parser.py @@ -1,5 +1,19 @@ -from typing import Dict, Optional +from typing import Dict, List, Optional + +import pandas as pd def get_rts_counters_only_with_last_value_key(rts_counters: Dict[str, dict]) -> Dict[str, Optional[int]]: return {key: val.get('last_value') for key, val in rts_counters.items()} + + +def get_html_table_data( + html: str, + new_headers: List[str], + table_position: int = 0 +) -> List[dict]: + dfs = pd.read_html(html) + df = dfs[table_position] + df.columns = new_headers + data = df.to_dict(orient='records') + return data From f365b4ad0498652c02138a826e5a22c15ca4e463 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 26 Aug 2023 01:34:25 -0300 Subject: [PATCH 018/147] feat: implement data table controller --- worldometer/scraper/controller.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/worldometer/scraper/controller.py b/worldometer/scraper/controller.py index 3d456e3..5badee1 100644 --- a/worldometer/scraper/controller.py +++ b/worldometer/scraper/controller.py @@ -1,7 +1,8 @@ -from typing import Dict, Optional +from typing import Dict, List, Optional from worldometer.scraper.browser import Browser from worldometer.scraper.parser import get_rts_counters_only_with_last_value_key +from worldometer.scraper.parser import get_html_table_data from worldometer.scraper.utils import make_url @@ -16,3 +17,17 @@ def get_rts_counters_object() -> Dict[str, Optional[int]]: script_return = browser.run_js_script(html, script='() => rts_counters') rts_counters = get_rts_counters_only_with_last_value_key(rts_counters=script_return) return rts_counters + + +def get_data_table( + path_url: str, + new_headers: List[str], + table_position: int, + render: bool = False +) -> List[dict]: + url = make_url(BASE_URL, path_url) + html = browser.get_page_content(url) + if render: + browser.render_page(html) + data = get_html_table_data(html.html, new_headers, table_position) + return data From ffc71ea9f2cffbd670adb5709d261d0362dcbb84 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 26 Aug 2023 04:53:50 -0300 Subject: [PATCH 019/147] chore: set html5lib as dependency --- Pipfile | 1 + Pipfile.lock | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Pipfile b/Pipfile index 85c5da5..adbd09d 100644 --- a/Pipfile +++ b/Pipfile @@ -6,6 +6,7 @@ name = "pypi" [packages] requests-html = "0.10.0" pandas = "*" +html5lib = "*" [dev-packages] pylint = "2.6.0" diff --git a/Pipfile.lock b/Pipfile.lock index 161227b..de27008 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "a94bf33a7491abd7e9e5e360f96c4b865e39bfd74195cf178c753d0f7ecb95c0" + "sha256": "3a99f8c51257bbb8495eaa8f1b0ccd92dfbc18a5fffab846e50808da2f288951" }, "pipfile-spec": 6, "requires": {}, @@ -139,6 +139,15 @@ ], "version": "==1.2.1" }, + "html5lib": { + "hashes": [ + "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d", + "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f" + ], + "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==1.1" + }, "idna": { "hashes": [ "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", @@ -425,6 +434,13 @@ "markers": "python_version >= '3.7'", "version": "==2.1.2" }, + "webencodings": { + "hashes": [ + "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", + "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" + ], + "version": "==0.5.1" + }, "websockets": { "hashes": [ "sha256:00213676a2e46b6ebf6045bc11d0f529d9120baa6f58d122b4021ad92adabd41", From 8c8c7e10aefd66285e8263203e24483492c5d444 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 26 Aug 2023 05:37:45 -0300 Subject: [PATCH 020/147] refactor: get multiple html data tables in one request --- worldometer/scraper/controller.py | 15 ++++++++------- worldometer/scraper/parser.py | 17 +++++++++-------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/worldometer/scraper/controller.py b/worldometer/scraper/controller.py index 5badee1..041b0aa 100644 --- a/worldometer/scraper/controller.py +++ b/worldometer/scraper/controller.py @@ -2,7 +2,7 @@ from worldometer.scraper.browser import Browser from worldometer.scraper.parser import get_rts_counters_only_with_last_value_key -from worldometer.scraper.parser import get_html_table_data +from worldometer.scraper.parser import get_html_tables_data from worldometer.scraper.utils import make_url @@ -19,15 +19,16 @@ def get_rts_counters_object() -> Dict[str, Optional[int]]: return rts_counters -def get_data_table( +def get_data_tables( path_url: str, - new_headers: List[str], - table_position: int, - render: bool = False -) -> List[dict]: + new_headers: List[List[str]], + render: bool = False, + use_attrs: Optional[bool] = True +) -> List[List[dict]]: + attrs = {'class': 'table'} if use_attrs else None url = make_url(BASE_URL, path_url) html = browser.get_page_content(url) if render: browser.render_page(html) - data = get_html_table_data(html.html, new_headers, table_position) + data = get_html_tables_data(html.html, new_headers, attrs) return data diff --git a/worldometer/scraper/parser.py b/worldometer/scraper/parser.py index d38e9f1..d04b24d 100644 --- a/worldometer/scraper/parser.py +++ b/worldometer/scraper/parser.py @@ -7,13 +7,14 @@ def get_rts_counters_only_with_last_value_key(rts_counters: Dict[str, dict]) -> return {key: val.get('last_value') for key, val in rts_counters.items()} -def get_html_table_data( +def get_html_tables_data( html: str, - new_headers: List[str], - table_position: int = 0 -) -> List[dict]: - dfs = pd.read_html(html) - df = dfs[table_position] - df.columns = new_headers - data = df.to_dict(orient='records') + new_headers: List[List[str]], + attrs: Optional[Dict[str, str]] +) -> List[List[dict]]: + data = [] + dfs = pd.read_html(html, attrs=attrs) + for idx, df in enumerate(dfs): + df.columns = new_headers[idx] + data.append(df.to_dict(orient='records')) return data From b761be8bf032f0e33c19dc27e8bb69a9c532e930 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 26 Aug 2023 05:38:41 -0300 Subject: [PATCH 021/147] refactor: use bs4 as parsing engine --- worldometer/scraper/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldometer/scraper/parser.py b/worldometer/scraper/parser.py index d04b24d..c3ef87a 100644 --- a/worldometer/scraper/parser.py +++ b/worldometer/scraper/parser.py @@ -13,7 +13,7 @@ def get_html_tables_data( attrs: Optional[Dict[str, str]] ) -> List[List[dict]]: data = [] - dfs = pd.read_html(html, attrs=attrs) + dfs = pd.read_html(html, attrs=attrs, flavor='bs4') for idx, df in enumerate(dfs): df.columns = new_headers[idx] data.append(df.to_dict(orient='records')) From 63f4bc0b94b189d107a722ee1a697263eb832d4e Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 27 Aug 2023 21:05:35 -0300 Subject: [PATCH 022/147] refactor: support make_url for a root route (url/) --- worldometer/scraper/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldometer/scraper/utils.py b/worldometer/scraper/utils.py index a992ca3..95b32f1 100644 --- a/worldometer/scraper/utils.py +++ b/worldometer/scraper/utils.py @@ -5,6 +5,6 @@ def make_url(base_url: str, path_url: Optional[str] = None) -> str: url = base_url - if path_url and re.match(r'^/{1}.+', path_url): + if path_url and re.match(r'^/{1}.*', path_url): url += path_url return url From a227c5f3806bf00523eb60dca651b4aeaca170f9 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 27 Aug 2023 21:11:05 -0300 Subject: [PATCH 023/147] feat: define source_path class attr in WorldCounters and CountryCodes --- worldometer/world/counters.py | 3 +++ worldometer/world/country_codes.py | 2 ++ 2 files changed, 5 insertions(+) diff --git a/worldometer/world/counters.py b/worldometer/world/counters.py index c4aa60a..a88e692 100644 --- a/worldometer/world/counters.py +++ b/worldometer/world/counters.py @@ -3,6 +3,9 @@ class WorldCounters: + + source_path = '/' + def __init__(self) -> None: self._data = self._load_data() self._init_counters() diff --git a/worldometer/world/country_codes.py b/worldometer/world/country_codes.py index 4adfb9d..155e048 100644 --- a/worldometer/world/country_codes.py +++ b/worldometer/world/country_codes.py @@ -14,6 +14,8 @@ class CountryCodesData: class CountryCodes: + source_path = '/country-codes' + def __init__(self) -> None: self._data = self._load_data() From 3194f91d6cce7cf607dc35eef7bcd1de2fb13ca2 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 27 Aug 2023 22:18:12 -0300 Subject: [PATCH 024/147] refactor: update rts_counters typehint and improve parser code --- worldometer/scraper/controller.py | 4 ++-- worldometer/scraper/parser.py | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/worldometer/scraper/controller.py b/worldometer/scraper/controller.py index 041b0aa..af0ba98 100644 --- a/worldometer/scraper/controller.py +++ b/worldometer/scraper/controller.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Optional +from typing import Dict, List, Optional, Union from worldometer.scraper.browser import Browser from worldometer.scraper.parser import get_rts_counters_only_with_last_value_key @@ -11,7 +11,7 @@ browser = Browser() -def get_rts_counters_object() -> Dict[str, Optional[int]]: +def get_rts_counters_object() -> Dict[str, Union[int, float, None]]: url = make_url(BASE_URL) html = browser.get_page_content(url) script_return = browser.run_js_script(html, script='() => rts_counters') diff --git a/worldometer/scraper/parser.py b/worldometer/scraper/parser.py index c3ef87a..a0ad659 100644 --- a/worldometer/scraper/parser.py +++ b/worldometer/scraper/parser.py @@ -1,10 +1,15 @@ -from typing import Dict, List, Optional +from typing import Dict, List, Optional, Union import pandas as pd -def get_rts_counters_only_with_last_value_key(rts_counters: Dict[str, dict]) -> Dict[str, Optional[int]]: - return {key: val.get('last_value') for key, val in rts_counters.items()} +def get_rts_counters_only_with_last_value_key( + rts_counters: Dict[str, dict] +) -> Dict[str, Union[int, float, None]]: + return { + key: subdict.get('last_value') or None + for key, subdict in rts_counters.items() + } def get_html_tables_data( From e2c0cc23c3d0bc882807d848a8667f8580ffbda0 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 27 Aug 2023 22:21:50 -0300 Subject: [PATCH 025/147] fix: define correct type hint of counters dataclasses --- worldometer/world/counters.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/worldometer/world/counters.py b/worldometer/world/counters.py index a88e692..4464f8e 100644 --- a/worldometer/world/counters.py +++ b/worldometer/world/counters.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import Dict +from typing import Dict, Union class WorldCounters: @@ -10,7 +10,7 @@ def __init__(self) -> None: self._data = self._load_data() self._init_counters() - def _load_data(self) -> Dict[str, int]: + def _load_data(self) -> Dict[str, Union[int, float, None]]: return {} def _init_counters(self) -> None: @@ -30,7 +30,7 @@ def reload_data(self): @dataclass class WorldPopulation: - _data: Dict[str, int] = field(repr=False) + _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: self.current_population = self._data.get('current_population') @@ -44,7 +44,7 @@ def __post_init__(self) -> None: @dataclass class GovernmentAndEconomics: - _data: Dict[str, int] = field(repr=False) + _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: self.public_healthcare_expenditure_today = self._data.get('gov_expenditures_health') @@ -57,7 +57,7 @@ def __post_init__(self) -> None: @dataclass class SocietyAndMedia: - _data: Dict[str, int] = field(repr=False) + _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: self.new_book_titles_published_this_year = self._data.get('books_published') @@ -74,7 +74,7 @@ def __post_init__(self) -> None: @dataclass class Environment: - _data: Dict[str, int] = field(repr=False) + _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: self.forest_loss_this_year = self._data.get('forest_loss') @@ -86,7 +86,7 @@ def __post_init__(self) -> None: @dataclass class Food: - _data: Dict[str, int] = field(repr=False) + _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: self.undernourished_people_in_the_world = self._data.get('undernourished') @@ -99,7 +99,7 @@ def __post_init__(self) -> None: @dataclass class Water: - _data: Dict[str, int] + _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: self.water_used_this_year = self._data.get('water_consumed') @@ -109,7 +109,7 @@ def __post_init__(self) -> None: @dataclass class Energy: - _data: Dict[str, int] = field(repr=False) + _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: self.energy_used_today = self._data.get('energy_used') @@ -127,7 +127,7 @@ def __post_init__(self) -> None: @dataclass class Health: - _data: Dict[str, int] = field(repr=False) + _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: self.communicable_disease_deaths_this_year = self._data.get('dth1s_communicable_disaxs') From a11d8214c4ebb7b03dfc995eb310bf99fe2991b2 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 27 Aug 2023 22:31:38 -0300 Subject: [PATCH 026/147] feat: implement load data in WorldCounters --- worldometer/world/counters.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/worldometer/world/counters.py b/worldometer/world/counters.py index 4464f8e..b84e653 100644 --- a/worldometer/world/counters.py +++ b/worldometer/world/counters.py @@ -1,6 +1,8 @@ from dataclasses import dataclass, field from typing import Dict, Union +from worldometer.scraper.controller import get_rts_counters_object + class WorldCounters: @@ -11,7 +13,8 @@ def __init__(self) -> None: self._init_counters() def _load_data(self) -> Dict[str, Union[int, float, None]]: - return {} + rts_counters = get_rts_counters_object() + return rts_counters def _init_counters(self) -> None: self.world_population = WorldPopulation(self._data) From 6af9f5ecbc5e6396d49c8202e17969e0615e37e0 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 27 Aug 2023 23:54:56 -0300 Subject: [PATCH 027/147] refactor: change argument name and update type hint changes: - new_headers arg to new_column_names - upd type hint of new_column_names arg from nested list to nested tuple --- worldometer/scraper/controller.py | 10 +++++++--- worldometer/scraper/parser.py | 8 ++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/worldometer/scraper/controller.py b/worldometer/scraper/controller.py index af0ba98..9992b39 100644 --- a/worldometer/scraper/controller.py +++ b/worldometer/scraper/controller.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Optional, Union +from typing import Dict, List, Optional, Tuple, Union from worldometer.scraper.browser import Browser from worldometer.scraper.parser import get_rts_counters_only_with_last_value_key @@ -21,7 +21,7 @@ def get_rts_counters_object() -> Dict[str, Union[int, float, None]]: def get_data_tables( path_url: str, - new_headers: List[List[str]], + new_column_names: List[Tuple[str, ...]], render: bool = False, use_attrs: Optional[bool] = True ) -> List[List[dict]]: @@ -30,5 +30,9 @@ def get_data_tables( html = browser.get_page_content(url) if render: browser.render_page(html) - data = get_html_tables_data(html.html, new_headers, attrs) + data = get_html_tables_data( + html=html.html, + new_column_names=new_column_names, + attrs=attrs + ) return data diff --git a/worldometer/scraper/parser.py b/worldometer/scraper/parser.py index a0ad659..182982b 100644 --- a/worldometer/scraper/parser.py +++ b/worldometer/scraper/parser.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Optional, Union +from typing import Dict, List, Optional, Tuple, Union import pandas as pd @@ -14,12 +14,12 @@ def get_rts_counters_only_with_last_value_key( def get_html_tables_data( html: str, - new_headers: List[List[str]], - attrs: Optional[Dict[str, str]] + attrs: Optional[Dict[str, str]], + new_column_names: List[Tuple[str, ...]] ) -> List[List[dict]]: data = [] dfs = pd.read_html(html, attrs=attrs, flavor='bs4') for idx, df in enumerate(dfs): - df.columns = new_headers[idx] + df.columns = new_column_names[idx] data.append(df.to_dict(orient='records')) return data From 651255de26b82fa799b3eebfdeb0cb943357efe6 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 28 Aug 2023 00:33:01 -0300 Subject: [PATCH 028/147] feat: implement load data in CountryCodes --- worldometer/world/country_codes.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/worldometer/world/country_codes.py b/worldometer/world/country_codes.py index 155e048..59e773f 100644 --- a/worldometer/world/country_codes.py +++ b/worldometer/world/country_codes.py @@ -2,6 +2,8 @@ from dataclasses import dataclass from typing import List +from worldometer.scraper.controller import get_data_tables + @dataclass class CountryCodesData: @@ -15,12 +17,29 @@ class CountryCodesData: class CountryCodes: source_path = '/country-codes' + table_position = 0 + column_names = ( + 'country', + 'calling_code', + 'three_letter_iso', + 'two_letter_iso', + 'three_digit_iso_numeric' + ) def __init__(self) -> None: self._data = self._load_data() def _load_data(self) -> List[CountryCodesData]: - return [] + dts = get_data_tables( + path_url=self.source_path, + new_column_names=[ + self.column_names + ] + ) + return [ + CountryCodesData(**data_line) + for data_line in dts[self.table_position] + ] def data(self) -> List[CountryCodesData]: return deepcopy(self._data) From e1d593888bc8c743852c8c59f9050dfa4d124da7 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 28 Aug 2023 00:38:57 -0300 Subject: [PATCH 029/147] refactor: change CountryCodes.data method to a property --- worldometer/world/country_codes.py | 1 + 1 file changed, 1 insertion(+) diff --git a/worldometer/world/country_codes.py b/worldometer/world/country_codes.py index 59e773f..7875736 100644 --- a/worldometer/world/country_codes.py +++ b/worldometer/world/country_codes.py @@ -41,5 +41,6 @@ def _load_data(self) -> List[CountryCodesData]: for data_line in dts[self.table_position] ] + @property def data(self) -> List[CountryCodesData]: return deepcopy(self._data) From 8dc978d6de7b279299afb7a2a244dc0d1560425f Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Tue, 29 Aug 2023 00:50:55 -0300 Subject: [PATCH 030/147] refactor: define default value to attrs argument in get_data_tables --- worldometer/scraper/controller.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/worldometer/scraper/controller.py b/worldometer/scraper/controller.py index 9992b39..78cfc81 100644 --- a/worldometer/scraper/controller.py +++ b/worldometer/scraper/controller.py @@ -23,13 +23,14 @@ def get_data_tables( path_url: str, new_column_names: List[Tuple[str, ...]], render: bool = False, - use_attrs: Optional[bool] = True + attrs: Optional[Dict[str, str]] = {'class': 'table'} ) -> List[List[dict]]: - attrs = {'class': 'table'} if use_attrs else None url = make_url(BASE_URL, path_url) html = browser.get_page_content(url) + if render: browser.render_page(html) + data = get_html_tables_data( html=html.html, new_column_names=new_column_names, From f7ba8c3ad58aafdd3c3b77bd998e97838487814e Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Tue, 29 Aug 2023 04:05:39 -0300 Subject: [PATCH 031/147] feat: implement html table parser error handling cases: - No tables found - No tuples for new column names - Lengths of new column names different than expected in the table created: - scraper.exceptions module --- worldometer/scraper/exceptions.py | 14 +++++++++++ worldometer/scraper/parser.py | 42 ++++++++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 worldometer/scraper/exceptions.py diff --git a/worldometer/scraper/exceptions.py b/worldometer/scraper/exceptions.py new file mode 100644 index 0000000..d5aa9f8 --- /dev/null +++ b/worldometer/scraper/exceptions.py @@ -0,0 +1,14 @@ +class ScraperException(Exception): + """Base exception of the scraper package.""" + + +class ParserError(ScraperException): + """Generic parser error.""" + + +class HTMLTablesNotFoundError(ParserError): + """No HTML tables found by the parsing engine.""" + + +class ColumnNamesLengthError(ParserError): + """Length of column names different than expected.""" diff --git a/worldometer/scraper/parser.py b/worldometer/scraper/parser.py index 182982b..0dcbc59 100644 --- a/worldometer/scraper/parser.py +++ b/worldometer/scraper/parser.py @@ -2,6 +2,11 @@ import pandas as pd +from worldometer.scraper.exceptions import ( + ColumnNamesLengthError, + HTMLTablesNotFoundError +) + def get_rts_counters_only_with_last_value_key( rts_counters: Dict[str, dict] @@ -18,8 +23,37 @@ def get_html_tables_data( new_column_names: List[Tuple[str, ...]] ) -> List[List[dict]]: data = [] - dfs = pd.read_html(html, attrs=attrs, flavor='bs4') - for idx, df in enumerate(dfs): - df.columns = new_column_names[idx] - data.append(df.to_dict(orient='records')) + + try: + dfs = pd.read_html(html, attrs=attrs, flavor='bs4') + + dfs_len = len(dfs) + col_names_len = len(new_column_names) + + if dfs_len != col_names_len: + raise ColumnNamesLengthError( + f'{col_names_len} tuples of column names for {dfs_len} table' + ) + + for idx, df in enumerate(dfs): + + col_len = len(df.columns) + new_col_len = len(new_column_names[idx]) + + if col_len != new_col_len: + raise ColumnNamesLengthError( + f'Table in position {idx} expected {col_len} columns but received {new_col_len}' + ) + + df.columns = new_column_names[idx] + data.append(df.to_dict(orient='records')) + + except ValueError as err: + expected_error_message = 'No tables found' + + if expected_error_message in err.args: + raise HTMLTablesNotFoundError('No HTML tables found') from err + + raise + return data From 34241b29fdddf1654d0ff0d100466247fe79603b Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Tue, 29 Aug 2023 16:29:13 -0300 Subject: [PATCH 032/147] refactor: run_js_script method require a script --- worldometer/scraper/browser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldometer/scraper/browser.py b/worldometer/scraper/browser.py index 32d4064..49dbb44 100644 --- a/worldometer/scraper/browser.py +++ b/worldometer/scraper/browser.py @@ -20,6 +20,6 @@ def get_page_content(self, url: str, timeout: int = 30) -> HTML: def render_page(self, html_obj: HTML) -> None: html_obj.render() - def run_js_script(self, html_obj: HTML, script: str = '') -> Dict[str, dict]: + def run_js_script(self, html_obj: HTML, script: str) -> Dict[str, dict]: script_return = html_obj.render(script=script) return script_return # type: ignore From 31a7a4ec4fe4cd91e3102c2276371c703499d64a Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Tue, 29 Aug 2023 17:06:58 -0300 Subject: [PATCH 033/147] feat: implement error handler for runner script --- worldometer/scraper/browser.py | 12 +++++++++++- worldometer/scraper/exceptions.py | 8 ++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/worldometer/scraper/browser.py b/worldometer/scraper/browser.py index 49dbb44..b6876df 100644 --- a/worldometer/scraper/browser.py +++ b/worldometer/scraper/browser.py @@ -2,6 +2,11 @@ from requests_html import HTML, HTMLSession +# pyppeteer is used by requests_html internally +from pyppeteer.errors import ElementHandleError + +from worldometer.scraper.exceptions import ScriptRunnerError + class Browser: @@ -21,5 +26,10 @@ def render_page(self, html_obj: HTML) -> None: html_obj.render() def run_js_script(self, html_obj: HTML, script: str) -> Dict[str, dict]: - script_return = html_obj.render(script=script) + try: + script_return = html_obj.render(script=script) + + except ElementHandleError as err: + raise ScriptRunnerError('Could not evaluate provided js script in HTML.') from err + return script_return # type: ignore diff --git a/worldometer/scraper/exceptions.py b/worldometer/scraper/exceptions.py index d5aa9f8..91b171f 100644 --- a/worldometer/scraper/exceptions.py +++ b/worldometer/scraper/exceptions.py @@ -2,6 +2,14 @@ class ScraperException(Exception): """Base exception of the scraper package.""" +class BrowserError(ScraperException): + """Generic browser error.""" + + +class ScriptRunnerError(BrowserError): + """Could not evaluate provided js script.""" + + class ParserError(ScraperException): """Generic parser error.""" From d420813959cd9ffac44077b8bd2ab9f9933b0507 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Tue, 29 Aug 2023 23:15:31 -0300 Subject: [PATCH 034/147] fix: run_js_script return type varies with script evaluation outcome --- worldometer/scraper/browser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldometer/scraper/browser.py b/worldometer/scraper/browser.py index b6876df..971e60a 100644 --- a/worldometer/scraper/browser.py +++ b/worldometer/scraper/browser.py @@ -1,4 +1,4 @@ -from typing import Dict +from typing import Any from requests_html import HTML, HTMLSession @@ -25,7 +25,7 @@ def get_page_content(self, url: str, timeout: int = 30) -> HTML: def render_page(self, html_obj: HTML) -> None: html_obj.render() - def run_js_script(self, html_obj: HTML, script: str) -> Dict[str, dict]: + def run_js_script(self, html_obj: HTML, script: str) -> Any: try: script_return = html_obj.render(script=script) From 57f427cc8c4a45cd7f95dda37836df0d9a20da0d Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 30 Aug 2023 22:39:27 -0300 Subject: [PATCH 035/147] chore: install pytest as a dev dependency --- Pipfile | 1 + Pipfile.lock | 93 ++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 65 insertions(+), 29 deletions(-) diff --git a/Pipfile b/Pipfile index adbd09d..a3a6b97 100644 --- a/Pipfile +++ b/Pipfile @@ -11,3 +11,4 @@ html5lib = "*" [dev-packages] pylint = "2.6.0" sphinx = "3.5.0" +pytest = "*" diff --git a/Pipfile.lock b/Pipfile.lock index de27008..5ba714e 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "3a99f8c51257bbb8495eaa8f1b0ccd92dfbc18a5fffab846e50808da2f288951" + "sha256": "f3279bba3bd0a3343d0e16c0aa19211d1d887c799bafb7cb1b45195ba9f4e628" }, "pipfile-spec": 6, "requires": {}, @@ -290,40 +290,34 @@ "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357", "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760" ], - "markers": "python_version >= '3.10'", + "markers": "python_version < '3.11'", "version": "==1.25.2" }, "pandas": { "hashes": [ - "sha256:04dbdbaf2e4d46ca8da896e1805bc04eb85caa9a82e259e8eed00254d5e0c682", - "sha256:1168574b036cd8b93abc746171c9b4f1b83467438a5e45909fed645cf8692dbc", - "sha256:1994c789bf12a7c5098277fb43836ce090f1073858c10f9220998ac74f37c69b", - "sha256:258d3624b3ae734490e4d63c430256e716f488c4fcb7c8e9bde2d3aa46c29089", - "sha256:32fca2ee1b0d93dd71d979726b12b61faa06aeb93cf77468776287f41ff8fdc5", - "sha256:37673e3bdf1551b95bf5d4ce372b37770f9529743d2498032439371fc7b7eb26", - "sha256:3ef285093b4fe5058eefd756100a367f27029913760773c8bf1d2d8bebe5d210", - "sha256:5247fb1ba347c1261cbbf0fcfba4a3121fbb4029d95d9ef4dc45406620b25c8b", - "sha256:5ec591c48e29226bcbb316e0c1e9423622bc7a4eaf1ef7c3c9fa1a3981f89641", - "sha256:694888a81198786f0e164ee3a581df7d505024fbb1f15202fc7db88a71d84ebd", - "sha256:69d7f3884c95da3a31ef82b7618af5710dba95bb885ffab339aad925c3e8ce78", - "sha256:6a21ab5c89dcbd57f78d0ae16630b090eec626360085a4148693def5452d8a6b", - "sha256:81af086f4543c9d8bb128328b5d32e9986e0c84d3ee673a2ac6fb57fd14f755e", - "sha256:9e4da0d45e7f34c069fe4d522359df7d23badf83abc1d1cef398895822d11061", - "sha256:9eae3dc34fa1aa7772dd3fc60270d13ced7346fcbcfee017d3132ec625e23bb0", - "sha256:9ee1a69328d5c36c98d8e74db06f4ad518a1840e8ccb94a4ba86920986bb617e", - "sha256:b084b91d8d66ab19f5bb3256cbd5ea661848338301940e17f4492b2ce0801fe8", - "sha256:b9cb1e14fdb546396b7e1b923ffaeeac24e4cedd14266c3497216dd4448e4f2d", - "sha256:ba619e410a21d8c387a1ea6e8a0e49bb42216474436245718d7f2e88a2f8d7c0", - "sha256:c02f372a88e0d17f36d3093a644c73cfc1788e876a7c4bcb4020a77512e2043c", - "sha256:ce0c6f76a0f1ba361551f3e6dceaff06bde7514a374aa43e33b588ec10420183", - "sha256:d9cd88488cceb7635aebb84809d087468eb33551097d600c6dad13602029c2df", - "sha256:e4c7c9f27a4185304c7caf96dc7d91bc60bc162221152de697c98eb0b2648dd8", - "sha256:f167beed68918d62bffb6ec64f2e1d8a7d297a038f86d4aed056b9493fca407f", - "sha256:f3421a7afb1a43f7e38e82e844e2bca9a6d793d66c1a7f9f0ff39a795bbc5e02" + "sha256:0164b85937707ec7f70b34a6c3a578dbf0f50787f910f21ca3b26a7fd3363437", + "sha256:28f330845ad21c11db51e02d8d69acc9035edfd1116926ff7245c7215db57957", + "sha256:38f74ef7ebc0ffb43b3d633e23d74882bce7e27bfa09607f3c5d3e03ffd9a4a5", + "sha256:40dd20439ff94f1b2ed55b393ecee9cb6f3b08104c2c40b0cb7186a2f0046242", + "sha256:629124923bcf798965b054a540f9ccdfd60f71361255c81fa1ecd94a904b9dd3", + "sha256:62c24c7fc59e42b775ce0679cfa7b14a5f9bfb7643cfbe708c960699e05fb918", + "sha256:6e6a0fe052cf27ceb29be9429428b4918f3740e37ff185658f40d8702f0b3e09", + "sha256:70cf866af3ab346a10debba8ea78077cf3a8cd14bd5e4bed3d41555a3280041c", + "sha256:86f100b3876b8c6d1a2c66207288ead435dc71041ee4aea789e55ef0e06408cb", + "sha256:9d81e1813191070440d4c7a413cb673052b3b4a984ffd86b8dd468c45742d3cc", + "sha256:b31da36d376d50a1a492efb18097b9101bdbd8b3fbb3f49006e02d4495d4c644", + "sha256:b9a6ccf0963db88f9b12df6720e55f337447aea217f426a22d71f4213a3099a6", + "sha256:cda72cc8c4761c8f1d97b169661f23a86b16fdb240bdc341173aee17e4d6cedd", + "sha256:d4f38e4fedeba580285eaac7ede4f686c6701a9e618d8a857b138a126d067f2f", + "sha256:d53c8c1001f6a192ff1de1efe03b31a423d0eee2e9e855e69d004308e046e694", + "sha256:d8c58b1113892e0c8078f006a167cc210a92bdae23322bb4614f2f0b7a4b510f", + "sha256:d97daeac0db8c993420b10da4f5f5b39b01fc9ca689a17844e07c0a35ac96b4b", + "sha256:d99e678180bc59b0c9443314297bddce4ad35727a1a2656dbe585fd78710b3b9", + "sha256:eb20252720b1cc1b7d0b2879ffc7e0542dd568f24d7c4b2347cb035206936421" ], "index": "pypi", - "markers": "python_version >= '3.8'", - "version": "==2.0.3" + "markers": "python_version >= '3.9'", + "version": "==2.1.0" }, "parse": { "hashes": [ @@ -647,6 +641,14 @@ "markers": "python_version >= '3.7'", "version": "==0.20.1" }, + "exceptiongroup": { + "hashes": [ + "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9", + "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3" + ], + "markers": "python_version < '3.11'", + "version": "==1.1.3" + }, "idna": { "hashes": [ "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", @@ -663,6 +665,14 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.4.1" }, + "iniconfig": { + "hashes": [ + "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", + "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" + ], + "markers": "python_version >= '3.7'", + "version": "==2.0.0" + }, "isort": { "hashes": [ "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504", @@ -793,6 +803,14 @@ "markers": "python_version >= '3.7'", "version": "==23.1" }, + "pluggy": { + "hashes": [ + "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12", + "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7" + ], + "markers": "python_version >= '3.8'", + "version": "==1.3.0" + }, "pygments": { "hashes": [ "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692", @@ -810,6 +828,15 @@ "markers": "python_version >= '3.5'", "version": "==2.6.0" }, + "pytest": { + "hashes": [ + "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32", + "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a" + ], + "index": "pypi", + "markers": "python_version >= '3.7'", + "version": "==7.4.0" + }, "requests": { "hashes": [ "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", @@ -898,6 +925,14 @@ "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==0.10.2" }, + "tomli": { + "hashes": [ + "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", + "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" + ], + "markers": "python_version < '3.11'", + "version": "==2.0.1" + }, "urllib3": { "hashes": [ "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f", From 24cd26883e87537114b426d41bd527a536f01837 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 11 Sep 2023 02:43:40 -0300 Subject: [PATCH 036/147] refactor: use public functions in scraper module instead of controller directly --- worldometer/scraper/__init__.py | 9 +++++++++ worldometer/scraper/browser.py | 2 +- worldometer/world/counters.py | 2 +- worldometer/world/country_codes.py | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/worldometer/scraper/__init__.py b/worldometer/scraper/__init__.py index e69de29..0d44c6b 100644 --- a/worldometer/scraper/__init__.py +++ b/worldometer/scraper/__init__.py @@ -0,0 +1,9 @@ +__all__ = [ + 'get_data_tables', + 'get_rts_counters_object' +] + +from worldometer.scraper.controller import ( + get_data_tables, + get_rts_counters_object +) diff --git a/worldometer/scraper/browser.py b/worldometer/scraper/browser.py index 971e60a..ea53042 100644 --- a/worldometer/scraper/browser.py +++ b/worldometer/scraper/browser.py @@ -3,7 +3,7 @@ from requests_html import HTML, HTMLSession # pyppeteer is used by requests_html internally -from pyppeteer.errors import ElementHandleError +from pyppeteer.errors import ElementHandleError, time from worldometer.scraper.exceptions import ScriptRunnerError diff --git a/worldometer/world/counters.py b/worldometer/world/counters.py index b84e653..ca8ed03 100644 --- a/worldometer/world/counters.py +++ b/worldometer/world/counters.py @@ -1,7 +1,7 @@ from dataclasses import dataclass, field from typing import Dict, Union -from worldometer.scraper.controller import get_rts_counters_object +from worldometer.scraper import get_rts_counters_object class WorldCounters: diff --git a/worldometer/world/country_codes.py b/worldometer/world/country_codes.py index 7875736..3da247a 100644 --- a/worldometer/world/country_codes.py +++ b/worldometer/world/country_codes.py @@ -2,7 +2,7 @@ from dataclasses import dataclass from typing import List -from worldometer.scraper.controller import get_data_tables +from worldometer.scraper import get_data_tables @dataclass From ec4c27d3e965187c9c3ee4cf28723ca0c928e727 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 11 Sep 2023 03:01:43 -0300 Subject: [PATCH 037/147] refactor: handle TimeoutError in run_js_script function --- worldometer/scraper/browser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldometer/scraper/browser.py b/worldometer/scraper/browser.py index ea53042..4eede75 100644 --- a/worldometer/scraper/browser.py +++ b/worldometer/scraper/browser.py @@ -3,7 +3,7 @@ from requests_html import HTML, HTMLSession # pyppeteer is used by requests_html internally -from pyppeteer.errors import ElementHandleError, time +from pyppeteer.errors import ElementHandleError, TimeoutError from worldometer.scraper.exceptions import ScriptRunnerError @@ -29,7 +29,7 @@ def run_js_script(self, html_obj: HTML, script: str) -> Any: try: script_return = html_obj.render(script=script) - except ElementHandleError as err: + except (ElementHandleError, TimeoutError) as err: raise ScriptRunnerError('Could not evaluate provided js script in HTML.') from err return script_return # type: ignore From 7665e8112327b6fe8dd9496d3614149009bca387 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 13 Sep 2023 16:04:10 -0300 Subject: [PATCH 038/147] test: implement tests in the rts_counters object parser --- tests/__init__.py | 0 tests/test_scraper/__init__.py | 0 tests/test_scraper/test_parser.py | 45 +++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 tests/__init__.py create mode 100644 tests/test_scraper/__init__.py create mode 100644 tests/test_scraper/test_parser.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_scraper/__init__.py b/tests/test_scraper/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_scraper/test_parser.py b/tests/test_scraper/test_parser.py new file mode 100644 index 0000000..e896321 --- /dev/null +++ b/tests/test_scraper/test_parser.py @@ -0,0 +1,45 @@ +import pytest + +from worldometer.scraper.parser import get_rts_counters_only_with_last_value_key + + +@pytest.fixture +def fake_rts_counters_object(): + return { + 'a': { + 'k1': {}, + 'k2': 'test', + 'last_value': 1 + }, + 'b': { + 'k1': {}, + 'k2': 'test', + 'last_value': 1.0 + }, + 'c': { + 'k1': {}, + 'k2': 'test', + 'last_value': None + } + } + + +def test_get_rts_counters_only_with_last_value_key(fake_rts_counters_object: dict): + + rts_counters = get_rts_counters_only_with_last_value_key(fake_rts_counters_object) + + assert isinstance(rts_counters, dict) + assert set(rts_counters.keys()) == set(fake_rts_counters_object.keys()) + assert all( + isinstance(v, (int, float, type(None))) + for v in rts_counters.values() + ) + + +def test_empty_rts_counters_object_passed(): + empty_rts_counters = {} + + rts_counters = get_rts_counters_only_with_last_value_key(empty_rts_counters) + + assert isinstance(rts_counters, dict) + assert len(rts_counters) == 0 From dffcbef479ef94ce111456dceb29035ce9125afc Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 13 Sep 2023 18:11:55 -0300 Subject: [PATCH 039/147] refactor: replace nan values in dataframe to n/a --- worldometer/scraper/parser.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/worldometer/scraper/parser.py b/worldometer/scraper/parser.py index 0dcbc59..94f474a 100644 --- a/worldometer/scraper/parser.py +++ b/worldometer/scraper/parser.py @@ -46,6 +46,8 @@ def get_html_tables_data( ) df.columns = new_column_names[idx] + df.fillna('n/a', inplace=True) + data.append(df.to_dict(orient='records')) except ValueError as err: From 58ac3826a5ab736d09bcee96186b7fe9f09f944e Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 13 Sep 2023 19:46:55 -0300 Subject: [PATCH 040/147] test: implement tests in the get_html_tables_data parser --- tests/test_scraper/test_parser.py | 111 +++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/tests/test_scraper/test_parser.py b/tests/test_scraper/test_parser.py index e896321..aaddbda 100644 --- a/tests/test_scraper/test_parser.py +++ b/tests/test_scraper/test_parser.py @@ -1,6 +1,9 @@ import pytest -from worldometer.scraper.parser import get_rts_counters_only_with_last_value_key +from worldometer.scraper.parser import ( + get_rts_counters_only_with_last_value_key, + get_html_tables_data +) @pytest.fixture @@ -24,6 +27,69 @@ def fake_rts_counters_object(): } +@pytest.fixture +def fake_html(): + return """ + + + + HTML to Tests + + + + + + + + + + + + + + + + + + + + + + + + + +
ABCD
test11.0
test11.0
+ + + + + + + + + + + + + + + + + + + + + + + + +
ABCD
test11.0
test11.0
+ + +""" + + def test_get_rts_counters_only_with_last_value_key(fake_rts_counters_object: dict): rts_counters = get_rts_counters_only_with_last_value_key(fake_rts_counters_object) @@ -43,3 +109,46 @@ def test_empty_rts_counters_object_passed(): assert isinstance(rts_counters, dict) assert len(rts_counters) == 0 + + +def test_get_html_tables_data(fake_html: str): + num_expected_tables = 2 + attrs = None + new_column_names = [('A1', 'B1', 'C1', 'D1'), ('A2', 'B2', 'C2', 'D2')] + + data = get_html_tables_data( + html=fake_html, + attrs=attrs, + new_column_names=new_column_names + ) + + assert isinstance(data, list) + assert len(data) == num_expected_tables + + all_table_data = [td for td in data] + assert all(isinstance(td, list) for td in all_table_data) + + data_lines = [ + data_line + for td in all_table_data + for data_line in td + ] + assert all( + isinstance(dl, dict) + for dl in data_lines + ) + + assert all( + tuple(dl.keys()) in new_column_names + for dl in data_lines + ) + + data_lines_values = [ + value + for dl in data_lines + for value in dl.values() + ] + assert all( + isinstance(value, (int, float, str)) + for value in data_lines_values + ) From ba47044a62f75ddfde0ed89e06ec3c653b1cd9e7 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 14 Sep 2023 05:07:52 -0300 Subject: [PATCH 041/147] test: write assert message to tables parser tests --- tests/test_scraper/test_parser.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/test_scraper/test_parser.py b/tests/test_scraper/test_parser.py index aaddbda..1e117d7 100644 --- a/tests/test_scraper/test_parser.py +++ b/tests/test_scraper/test_parser.py @@ -126,7 +126,9 @@ def test_get_html_tables_data(fake_html: str): assert len(data) == num_expected_tables all_table_data = [td for td in data] - assert all(isinstance(td, list) for td in all_table_data) + assert all( + isinstance(td, list) for td in all_table_data + ), 'Table with wrong type. Each data table must be a list.' data_lines = [ data_line @@ -136,12 +138,12 @@ def test_get_html_tables_data(fake_html: str): assert all( isinstance(dl, dict) for dl in data_lines - ) + ), 'Data line with wrong type. Each row of data must be a dict.' assert all( tuple(dl.keys()) in new_column_names for dl in data_lines - ) + ), 'The column names are wrong. They are expected to match the column names passed.' data_lines_values = [ value @@ -151,4 +153,4 @@ def test_get_html_tables_data(fake_html: str): assert all( isinstance(value, (int, float, str)) for value in data_lines_values - ) + ), 'The column value is not of a supported type. It is expected to be int, float or str.' From 8e23b0048f171444ec70fda3b8d031c4e2bb6edb Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 14 Sep 2023 05:19:21 -0300 Subject: [PATCH 042/147] test: rename occurrences of 'line' to 'row' in table parser test --- tests/test_scraper/test_parser.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/test_scraper/test_parser.py b/tests/test_scraper/test_parser.py index 1e117d7..6c89b55 100644 --- a/tests/test_scraper/test_parser.py +++ b/tests/test_scraper/test_parser.py @@ -130,27 +130,27 @@ def test_get_html_tables_data(fake_html: str): isinstance(td, list) for td in all_table_data ), 'Table with wrong type. Each data table must be a list.' - data_lines = [ - data_line + data_rows = [ + data_row for td in all_table_data - for data_line in td + for data_row in td ] assert all( - isinstance(dl, dict) - for dl in data_lines - ), 'Data line with wrong type. Each row of data must be a dict.' + isinstance(dr, dict) + for dr in data_rows + ), 'Data row with wrong type. Each row of data must be a dict.' assert all( - tuple(dl.keys()) in new_column_names - for dl in data_lines + tuple(dr.keys()) in new_column_names + for dr in data_rows ), 'The column names are wrong. They are expected to match the column names passed.' - data_lines_values = [ + data_rows_values = [ value - for dl in data_lines - for value in dl.values() + for dr in data_rows + for value in dr.values() ] assert all( isinstance(value, (int, float, str)) - for value in data_lines_values + for value in data_rows_values ), 'The column value is not of a supported type. It is expected to be int, float or str.' From 6542f28a8c4f2ced98e2c543b290ca1afcb99b86 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 14 Sep 2023 05:44:09 -0300 Subject: [PATCH 043/147] test: implement test to get_html_tables_data with attrs param --- tests/test_scraper/test_parser.py | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/test_scraper/test_parser.py b/tests/test_scraper/test_parser.py index 6c89b55..c500dea 100644 --- a/tests/test_scraper/test_parser.py +++ b/tests/test_scraper/test_parser.py @@ -154,3 +154,41 @@ def test_get_html_tables_data(fake_html: str): isinstance(value, (int, float, str)) for value in data_rows_values ), 'The column value is not of a supported type. It is expected to be int, float or str.' + + +def test_get_html_tables_data_with_attrs(fake_html: str): + num_expected_tables = 1 + attrs = {'class': 'table'} + new_column_names = [('A1', 'B1', 'C1', 'D1')] + + data = get_html_tables_data( + html=fake_html, + attrs=attrs, + new_column_names=new_column_names # type: ignore + ) + + assert isinstance(data, list) + assert len(data) == num_expected_tables + + table_data = data[0] + assert isinstance(table_data, list) + + assert all( + isinstance(data_row, dict) + for data_row in table_data + ), 'Data row with wrong type. Each row of data must be a dict.' + + assert all( + tuple(dr.keys()) in new_column_names + for dr in table_data + ), 'The column names are wrong. They are expected to match the column names passed.' + + data_rows_values = [ + value + for dr in table_data + for value in dr.values() + ] + assert all( + isinstance(value, (int, float, str)) + for value in data_rows_values + ), 'The column value is not of a supported type. It is expected to be int, float or str.' From b8c01e9864630ba84491a6e36ac1d54efd83eac4 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 14 Sep 2023 06:04:42 -0300 Subject: [PATCH 044/147] fix: mention 'column names' instead of 'columns' in ColumnNamesLengthError --- worldometer/scraper/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldometer/scraper/parser.py b/worldometer/scraper/parser.py index 94f474a..382f534 100644 --- a/worldometer/scraper/parser.py +++ b/worldometer/scraper/parser.py @@ -42,7 +42,7 @@ def get_html_tables_data( if col_len != new_col_len: raise ColumnNamesLengthError( - f'Table in position {idx} expected {col_len} columns but received {new_col_len}' + f'Table in position {idx} expected {col_len} column names but received {new_col_len}' ) df.columns = new_column_names[idx] From 9b31acae7dbd1d8747e646c6ada9230104d7ccd5 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 14 Sep 2023 06:23:45 -0300 Subject: [PATCH 045/147] test: implement test to html tables parser with wrong length column names --- tests/test_scraper/test_parser.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/test_scraper/test_parser.py b/tests/test_scraper/test_parser.py index c500dea..30afd61 100644 --- a/tests/test_scraper/test_parser.py +++ b/tests/test_scraper/test_parser.py @@ -4,6 +4,9 @@ get_rts_counters_only_with_last_value_key, get_html_tables_data ) +from worldometer.scraper.exceptions import ( + ColumnNamesLengthError +) @pytest.fixture @@ -192,3 +195,23 @@ def test_get_html_tables_data_with_attrs(fake_html: str): isinstance(value, (int, float, str)) for value in data_rows_values ), 'The column value is not of a supported type. It is expected to be int, float or str.' + + +def test_get_html_tables_data_with_wrong_lenght_of_new_column_names(fake_html): + + with pytest.raises(ColumnNamesLengthError): + get_html_tables_data(fake_html, attrs=None, new_column_names=[]) + + get_html_tables_data(fake_html, attrs=None, new_column_names=[('A1', 'B1', 'C1', 'D1')]) + + get_html_tables_data(fake_html, attrs=None, new_column_names=[('A1',), ('A2',), ('A3',)]) + + get_html_tables_data(fake_html, attrs=None, new_column_names=[tuple(), tuple()]) + + get_html_tables_data(fake_html, attrs=None, new_column_names=[('A1', 'B1'), ('A2', 'B2')]) + + get_html_tables_data( + fake_html, + attrs=None, + new_column_names=[('A1', 'B1', 'C1', 'D1', 'E1'), ('A2', 'B2', 'C2', 'D2', 'E2')] + ) From 85bc500e2c1d059307eb3d84cf2b7b5c854b7cea Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 14 Sep 2023 06:26:30 -0300 Subject: [PATCH 046/147] test: fix occurrences of 'lenght' to 'length' --- tests/test_scraper/test_parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_scraper/test_parser.py b/tests/test_scraper/test_parser.py index 30afd61..74c801f 100644 --- a/tests/test_scraper/test_parser.py +++ b/tests/test_scraper/test_parser.py @@ -197,7 +197,7 @@ def test_get_html_tables_data_with_attrs(fake_html: str): ), 'The column value is not of a supported type. It is expected to be int, float or str.' -def test_get_html_tables_data_with_wrong_lenght_of_new_column_names(fake_html): +def test_get_html_tables_data_with_wrong_length_of_new_column_names(fake_html): with pytest.raises(ColumnNamesLengthError): get_html_tables_data(fake_html, attrs=None, new_column_names=[]) From 9a4cab576455ab0c3c65842304c230066917124f Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 14 Sep 2023 06:35:39 -0300 Subject: [PATCH 047/147] test: implement test to html tables parser when there is no html table --- tests/test_scraper/test_parser.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/test_scraper/test_parser.py b/tests/test_scraper/test_parser.py index 74c801f..a0ceaf0 100644 --- a/tests/test_scraper/test_parser.py +++ b/tests/test_scraper/test_parser.py @@ -5,7 +5,8 @@ get_html_tables_data ) from worldometer.scraper.exceptions import ( - ColumnNamesLengthError + ColumnNamesLengthError, + HTMLTablesNotFoundError ) @@ -215,3 +216,19 @@ def test_get_html_tables_data_with_wrong_length_of_new_column_names(fake_html): attrs=None, new_column_names=[('A1', 'B1', 'C1', 'D1', 'E1'), ('A2', 'B2', 'C2', 'D2', 'E2')] ) + + +def test_get_html_tables_data_when_there_is_no_html_table(): + html = """ + + + + HTML to Tests + + + + + """ + + with pytest.raises(HTMLTablesNotFoundError): + get_html_tables_data(html, attrs=None, new_column_names=[]) From a480eeea02a2fe8115f51c1361053748570c0803 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 14 Sep 2023 06:48:59 -0300 Subject: [PATCH 048/147] test: html tables parser when there is no html document --- tests/test_scraper/test_parser.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_scraper/test_parser.py b/tests/test_scraper/test_parser.py index a0ceaf0..0ea5fee 100644 --- a/tests/test_scraper/test_parser.py +++ b/tests/test_scraper/test_parser.py @@ -232,3 +232,8 @@ def test_get_html_tables_data_when_there_is_no_html_table(): with pytest.raises(HTMLTablesNotFoundError): get_html_tables_data(html, attrs=None, new_column_names=[]) + + +def test_get_html_tables_data_when_there_is_no_html_document(): + with pytest.raises(ValueError): + get_html_tables_data(html='', attrs=None, new_column_names=[]) From 73dfddfee6e616368fcd11716d09bb36642053db Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 14 Sep 2023 19:47:01 -0300 Subject: [PATCH 049/147] refactor: value 'n/a' has dtype incompatible with float64, keep default replace 'nan' --- worldometer/scraper/parser.py | 1 - 1 file changed, 1 deletion(-) diff --git a/worldometer/scraper/parser.py b/worldometer/scraper/parser.py index 382f534..58de7dc 100644 --- a/worldometer/scraper/parser.py +++ b/worldometer/scraper/parser.py @@ -46,7 +46,6 @@ def get_html_tables_data( ) df.columns = new_column_names[idx] - df.fillna('n/a', inplace=True) data.append(df.to_dict(orient='records')) From 86eb4e76221d36fd42cdd698b951c8c00c9c7e93 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 14 Sep 2023 20:33:53 -0300 Subject: [PATCH 050/147] refactor: passing literal html to 'read_html' is deprecated, use StringIO instead --- worldometer/scraper/parser.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/worldometer/scraper/parser.py b/worldometer/scraper/parser.py index 58de7dc..d1996d0 100644 --- a/worldometer/scraper/parser.py +++ b/worldometer/scraper/parser.py @@ -1,5 +1,7 @@ from typing import Dict, List, Optional, Tuple, Union +from io import StringIO + import pandas as pd from worldometer.scraper.exceptions import ( @@ -25,7 +27,7 @@ def get_html_tables_data( data = [] try: - dfs = pd.read_html(html, attrs=attrs, flavor='bs4') + dfs = pd.read_html(io=StringIO(html), attrs=attrs, flavor='bs4') dfs_len = len(dfs) col_names_len = len(new_column_names) From 8f070fcc4ba3fc51d26055b9997b049edc06dcff Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 14 Sep 2023 20:38:05 -0300 Subject: [PATCH 051/147] test: use parametrize to many new column names --- tests/test_scraper/test_parser.py | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/tests/test_scraper/test_parser.py b/tests/test_scraper/test_parser.py index 0ea5fee..74d033f 100644 --- a/tests/test_scraper/test_parser.py +++ b/tests/test_scraper/test_parser.py @@ -198,24 +198,20 @@ def test_get_html_tables_data_with_attrs(fake_html: str): ), 'The column value is not of a supported type. It is expected to be int, float or str.' -def test_get_html_tables_data_with_wrong_length_of_new_column_names(fake_html): - +@pytest.mark.parametrize( + 'new_column_names', + [ + [], + [('A1', 'B1', 'C1', 'D1')], + [('A1',), ('A2',), ('A3',)], + [tuple(), tuple()], + [('A1', 'B1'), ('A2', 'B2')], + [('A1', 'B1', 'C1', 'D1', 'E1'), ('A2', 'B2', 'C2', 'D2', 'E2')] + ] +) +def test_get_html_tables_data_with_wrong_length_of_new_column_names(fake_html, new_column_names): with pytest.raises(ColumnNamesLengthError): - get_html_tables_data(fake_html, attrs=None, new_column_names=[]) - - get_html_tables_data(fake_html, attrs=None, new_column_names=[('A1', 'B1', 'C1', 'D1')]) - - get_html_tables_data(fake_html, attrs=None, new_column_names=[('A1',), ('A2',), ('A3',)]) - - get_html_tables_data(fake_html, attrs=None, new_column_names=[tuple(), tuple()]) - - get_html_tables_data(fake_html, attrs=None, new_column_names=[('A1', 'B1'), ('A2', 'B2')]) - - get_html_tables_data( - fake_html, - attrs=None, - new_column_names=[('A1', 'B1', 'C1', 'D1', 'E1'), ('A2', 'B2', 'C2', 'D2', 'E2')] - ) + get_html_tables_data(fake_html, attrs=None, new_column_names=new_column_names) def test_get_html_tables_data_when_there_is_no_html_table(): From 553c9521425e61ab869e55d07d66f010bec45dbf Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 14 Sep 2023 21:09:28 -0300 Subject: [PATCH 052/147] refactor: create consts module and change import style --- worldometer/scraper/consts.py | 1 + worldometer/scraper/controller.py | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 worldometer/scraper/consts.py diff --git a/worldometer/scraper/consts.py b/worldometer/scraper/consts.py new file mode 100644 index 0000000..3e8212c --- /dev/null +++ b/worldometer/scraper/consts.py @@ -0,0 +1 @@ +BASE_URL = 'https://www.worldometers.info' diff --git a/worldometer/scraper/controller.py b/worldometer/scraper/controller.py index 78cfc81..95c0359 100644 --- a/worldometer/scraper/controller.py +++ b/worldometer/scraper/controller.py @@ -1,12 +1,16 @@ from typing import Dict, List, Optional, Tuple, Union from worldometer.scraper.browser import Browser -from worldometer.scraper.parser import get_rts_counters_only_with_last_value_key -from worldometer.scraper.parser import get_html_tables_data + +from worldometer.scraper.parser import ( + get_rts_counters_only_with_last_value_key, + get_html_tables_data +) from worldometer.scraper.utils import make_url -BASE_URL = 'https://www.worldometers.info' +from worldometer.scraper.consts import BASE_URL + browser = Browser() From f52b6d0ab39f3543954eb0479ac6bc8ce9f74dae Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 14 Sep 2023 21:39:24 -0300 Subject: [PATCH 053/147] test: implement tests to the make_url function --- tests/test_scraper/test_utils.py | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/test_scraper/test_utils.py diff --git a/tests/test_scraper/test_utils.py b/tests/test_scraper/test_utils.py new file mode 100644 index 0000000..7f448a3 --- /dev/null +++ b/tests/test_scraper/test_utils.py @@ -0,0 +1,36 @@ +import pytest + +from worldometer.scraper.utils import make_url + + +@pytest.fixture +def base_url(): + return 'https://www.example.com' + + +def test_make_url(base_url): + url = make_url(base_url) + + assert url == base_url + + +@pytest.mark.parametrize( + 'path_url', + ['/', '/a', '/a/b', '/a/b/', '/a1', '/a2/', '/a?arg=1'] +) +def test_make_url_with_path_url_param(base_url, path_url): + url = make_url(base_url, path_url) + + expected_url = base_url + path_url + + assert url == expected_url + + +@pytest.mark.parametrize( + 'path_url', + ['', 'a', 'a/', 'a/b/', 'a?arg=1'] +) +def test_make_url_with_invalid_path_url_param(base_url, path_url): + url = make_url(base_url, path_url) + + assert url == base_url From 0880aee64a973df73e8aff02f55b0bc96cf55397 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 18 Sep 2023 18:42:21 -0300 Subject: [PATCH 054/147] refactor: rename column_names attr to new_column_names --- worldometer/world/country_codes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worldometer/world/country_codes.py b/worldometer/world/country_codes.py index 3da247a..4d5b17d 100644 --- a/worldometer/world/country_codes.py +++ b/worldometer/world/country_codes.py @@ -18,7 +18,7 @@ class CountryCodes: source_path = '/country-codes' table_position = 0 - column_names = ( + new_column_names = ( 'country', 'calling_code', 'three_letter_iso', @@ -33,7 +33,7 @@ def _load_data(self) -> List[CountryCodesData]: dts = get_data_tables( path_url=self.source_path, new_column_names=[ - self.column_names + self.new_column_names ] ) return [ From 35f5c0f7f2fc2bbb05054a865f29e0356931e024 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 18 Sep 2023 20:00:12 -0300 Subject: [PATCH 055/147] feat: create population package and CountriesByPopulation --- worldometer/world/population/__init__.py | 5 ++ .../population/countries_by_population.py | 60 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 worldometer/world/population/__init__.py create mode 100644 worldometer/world/population/countries_by_population.py diff --git a/worldometer/world/population/__init__.py b/worldometer/world/population/__init__.py new file mode 100644 index 0000000..49a6922 --- /dev/null +++ b/worldometer/world/population/__init__.py @@ -0,0 +1,5 @@ +__all__ = [ + 'CountriesByPopulation' +] + +from worldometer.world.population.countries_by_population import CountriesByPopulation diff --git a/worldometer/world/population/countries_by_population.py b/worldometer/world/population/countries_by_population.py new file mode 100644 index 0000000..497d11c --- /dev/null +++ b/worldometer/world/population/countries_by_population.py @@ -0,0 +1,60 @@ +from copy import deepcopy +from dataclasses import dataclass +from typing import List + +from worldometer.scraper import get_data_tables + + +@dataclass +class CountriesByPopulationData: + position: int + country: str + population: int + yearly_change: str + net_change: int + density: int + land_area: int + migrants: int + fertility_rate: float + median_age: float + urban_population: str + world_share: str + + +class CountriesByPopulation: + + source_path = '/world-population/population-by-country' + table_position = 0 + new_column_names = ( + 'position', + 'country', + 'population', + 'yearly_change', + 'net_change', + 'density', + 'land_area', + 'migrants', + 'fertility_rate', + 'median_age', + 'urban_population', + 'world_share' + ) + + def __init__(self) -> None: + self._data = self._load_data() + + def _load_data(self) -> List[CountriesByPopulationData]: + dts = get_data_tables( + path_url=self.source_path, + new_column_names=[ + self.new_column_names + ] + ) + return [ + CountriesByPopulationData(**data_line) + for data_line in dts[self.table_position] + ] + + @property + def data(self) -> List[CountriesByPopulationData]: + return deepcopy(self._data) From 1e46660ab91592b3b4da3b7830a579dbf50e5739 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 18 Sep 2023 22:00:24 -0300 Subject: [PATCH 056/147] feat: implement api to get the most populous countries --- worldometer/world/population/__init__.py | 4 +- .../population/most_populous_countries.py | 110 ++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 worldometer/world/population/most_populous_countries.py diff --git a/worldometer/world/population/__init__.py b/worldometer/world/population/__init__.py index 49a6922..b219767 100644 --- a/worldometer/world/population/__init__.py +++ b/worldometer/world/population/__init__.py @@ -1,5 +1,7 @@ __all__ = [ - 'CountriesByPopulation' + 'CountriesByPopulation', + 'MostPopulousCountries' ] from worldometer.world.population.countries_by_population import CountriesByPopulation +from worldometer.world.population.most_populous_countries import MostPopulousCountries diff --git a/worldometer/world/population/most_populous_countries.py b/worldometer/world/population/most_populous_countries.py new file mode 100644 index 0000000..3408fac --- /dev/null +++ b/worldometer/world/population/most_populous_countries.py @@ -0,0 +1,110 @@ +from copy import deepcopy +from dataclasses import dataclass +from typing import List, Tuple + +from worldometer.scraper import get_data_tables + + +@dataclass +class CurrentMostPopulousCountriesData: + position: int + country: str + population: int + yearly_change: str + world_share: str + + table_position = 0 + new_column_names = ( + 'position', + 'country', + 'population', + 'yearly_change', + 'world_share' + ) + + +@dataclass +class PastMostPopulousCountriesData: + position: int + country: str + population: int + world_share: str + rank: str + + table_position = 1 + new_column_names = ( + 'position', + 'country', + 'population', + 'world_share', + 'rank' + ) + + +@dataclass +class FutureMostPopulousCountriesData: + position: int + country: str + population: int + world_share: str + rank: str + + table_position = 2 + new_column_names = ( + 'position', + 'country', + 'population', + 'world_share', + 'rank' + ) + + +class MostPopulousCountries: + + source_path = '/population/most-populous-countries' + new_column_names = ( + CurrentMostPopulousCountriesData.new_column_names, + PastMostPopulousCountriesData.new_column_names, + FutureMostPopulousCountriesData.new_column_names + ) + + def __init__(self) -> None: + self._data = self._load_data() + + def _load_data( + self + ) -> Tuple[ + List[CurrentMostPopulousCountriesData], + List[PastMostPopulousCountriesData], + List[FutureMostPopulousCountriesData] + ]: + dts = get_data_tables( + path_url=self.source_path, + new_column_names=[ + *self.new_column_names + ] + ) + + return ( + [ + CurrentMostPopulousCountriesData(**data_line) + for data_line in dts[CurrentMostPopulousCountriesData.table_position] + ], + [ + PastMostPopulousCountriesData(**data_line) + for data_line in dts[PastMostPopulousCountriesData.table_position] + ], + [ + FutureMostPopulousCountriesData(**data_line) + for data_line in dts[FutureMostPopulousCountriesData.table_position] + ] + ) + + def current(self) -> List[CurrentMostPopulousCountriesData]: + return deepcopy(self._data[0]) + + def past(self) -> List[PastMostPopulousCountriesData]: + return deepcopy(self._data[1]) + + def future(self) -> List[FutureMostPopulousCountriesData]: + return deepcopy(self._data[2]) From edccd2272d055b2734c26bf834d858ac04ad1885 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 18 Sep 2023 22:05:42 -0300 Subject: [PATCH 057/147] refactor: rename data_line to data_row in all mentions --- worldometer/world/country_codes.py | 4 ++-- .../world/population/countries_by_population.py | 4 ++-- .../world/population/most_populous_countries.py | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/worldometer/world/country_codes.py b/worldometer/world/country_codes.py index 4d5b17d..5058e5e 100644 --- a/worldometer/world/country_codes.py +++ b/worldometer/world/country_codes.py @@ -37,8 +37,8 @@ def _load_data(self) -> List[CountryCodesData]: ] ) return [ - CountryCodesData(**data_line) - for data_line in dts[self.table_position] + CountryCodesData(**data_row) + for data_row in dts[self.table_position] ] @property diff --git a/worldometer/world/population/countries_by_population.py b/worldometer/world/population/countries_by_population.py index 497d11c..e0dae7d 100644 --- a/worldometer/world/population/countries_by_population.py +++ b/worldometer/world/population/countries_by_population.py @@ -51,8 +51,8 @@ def _load_data(self) -> List[CountriesByPopulationData]: ] ) return [ - CountriesByPopulationData(**data_line) - for data_line in dts[self.table_position] + CountriesByPopulationData(**data_row) + for data_row in dts[self.table_position] ] @property diff --git a/worldometer/world/population/most_populous_countries.py b/worldometer/world/population/most_populous_countries.py index 3408fac..5d45a2e 100644 --- a/worldometer/world/population/most_populous_countries.py +++ b/worldometer/world/population/most_populous_countries.py @@ -87,16 +87,16 @@ def _load_data( return ( [ - CurrentMostPopulousCountriesData(**data_line) - for data_line in dts[CurrentMostPopulousCountriesData.table_position] + CurrentMostPopulousCountriesData(**data_row) + for data_row in dts[CurrentMostPopulousCountriesData.table_position] ], [ - PastMostPopulousCountriesData(**data_line) - for data_line in dts[PastMostPopulousCountriesData.table_position] + PastMostPopulousCountriesData(**data_row) + for data_row in dts[PastMostPopulousCountriesData.table_position] ], [ - FutureMostPopulousCountriesData(**data_line) - for data_line in dts[FutureMostPopulousCountriesData.table_position] + FutureMostPopulousCountriesData(**data_row) + for data_row in dts[FutureMostPopulousCountriesData.table_position] ] ) From ab85423929a243c17cd7509c98a0f6f05a3a1d75 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 18 Sep 2023 22:11:29 -0300 Subject: [PATCH 058/147] refactor: move literal new_column_names to MostPopulousCountries --- .../population/most_populous_countries.py | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/worldometer/world/population/most_populous_countries.py b/worldometer/world/population/most_populous_countries.py index 5d45a2e..a9e359c 100644 --- a/worldometer/world/population/most_populous_countries.py +++ b/worldometer/world/population/most_populous_countries.py @@ -14,13 +14,6 @@ class CurrentMostPopulousCountriesData: world_share: str table_position = 0 - new_column_names = ( - 'position', - 'country', - 'population', - 'yearly_change', - 'world_share' - ) @dataclass @@ -32,13 +25,6 @@ class PastMostPopulousCountriesData: rank: str table_position = 1 - new_column_names = ( - 'position', - 'country', - 'population', - 'world_share', - 'rank' - ) @dataclass @@ -50,22 +36,33 @@ class FutureMostPopulousCountriesData: rank: str table_position = 2 - new_column_names = ( - 'position', - 'country', - 'population', - 'world_share', - 'rank' - ) class MostPopulousCountries: source_path = '/population/most-populous-countries' new_column_names = ( - CurrentMostPopulousCountriesData.new_column_names, - PastMostPopulousCountriesData.new_column_names, - FutureMostPopulousCountriesData.new_column_names + ( + 'position', + 'country', + 'population', + 'yearly_change', + 'world_share' + ), + ( + 'position', + 'country', + 'population', + 'world_share', + 'rank' + ), + ( + 'position', + 'country', + 'population', + 'world_share', + 'rank' + ) ) def __init__(self) -> None: From 7a4d2b06e345ff720d7cfc87028668bfad7ad574 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 18 Sep 2023 22:14:22 -0300 Subject: [PATCH 059/147] refactor: move table_position attr to dataclass representation --- worldometer/world/country_codes.py | 5 +++-- worldometer/world/population/countries_by_population.py | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/worldometer/world/country_codes.py b/worldometer/world/country_codes.py index 5058e5e..f724205 100644 --- a/worldometer/world/country_codes.py +++ b/worldometer/world/country_codes.py @@ -13,11 +13,12 @@ class CountryCodesData: two_letter_iso: str three_digit_iso_numeric: str + table_position = 0 + class CountryCodes: source_path = '/country-codes' - table_position = 0 new_column_names = ( 'country', 'calling_code', @@ -38,7 +39,7 @@ def _load_data(self) -> List[CountryCodesData]: ) return [ CountryCodesData(**data_row) - for data_row in dts[self.table_position] + for data_row in dts[CountryCodesData.table_position] ] @property diff --git a/worldometer/world/population/countries_by_population.py b/worldometer/world/population/countries_by_population.py index e0dae7d..cae858f 100644 --- a/worldometer/world/population/countries_by_population.py +++ b/worldometer/world/population/countries_by_population.py @@ -20,11 +20,12 @@ class CountriesByPopulationData: urban_population: str world_share: str + table_position = 0 + class CountriesByPopulation: source_path = '/world-population/population-by-country' - table_position = 0 new_column_names = ( 'position', 'country', @@ -52,7 +53,7 @@ def _load_data(self) -> List[CountriesByPopulationData]: ) return [ CountriesByPopulationData(**data_row) - for data_row in dts[self.table_position] + for data_row in dts[CountriesByPopulationData.table_position] ] @property From cd8f5dc67c8c1181e6fee2e2339ad3f5a828f4f1 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 18 Sep 2023 22:18:53 -0300 Subject: [PATCH 060/147] refactor: table_position is private class attr now --- worldometer/world/country_codes.py | 4 ++-- .../world/population/countries_by_population.py | 4 ++-- .../world/population/most_populous_countries.py | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/worldometer/world/country_codes.py b/worldometer/world/country_codes.py index f724205..fd924bc 100644 --- a/worldometer/world/country_codes.py +++ b/worldometer/world/country_codes.py @@ -13,7 +13,7 @@ class CountryCodesData: two_letter_iso: str three_digit_iso_numeric: str - table_position = 0 + _table_position = 0 class CountryCodes: @@ -39,7 +39,7 @@ def _load_data(self) -> List[CountryCodesData]: ) return [ CountryCodesData(**data_row) - for data_row in dts[CountryCodesData.table_position] + for data_row in dts[CountryCodesData._table_position] ] @property diff --git a/worldometer/world/population/countries_by_population.py b/worldometer/world/population/countries_by_population.py index cae858f..734b435 100644 --- a/worldometer/world/population/countries_by_population.py +++ b/worldometer/world/population/countries_by_population.py @@ -20,7 +20,7 @@ class CountriesByPopulationData: urban_population: str world_share: str - table_position = 0 + _table_position = 0 class CountriesByPopulation: @@ -53,7 +53,7 @@ def _load_data(self) -> List[CountriesByPopulationData]: ) return [ CountriesByPopulationData(**data_row) - for data_row in dts[CountriesByPopulationData.table_position] + for data_row in dts[CountriesByPopulationData._table_position] ] @property diff --git a/worldometer/world/population/most_populous_countries.py b/worldometer/world/population/most_populous_countries.py index a9e359c..f093119 100644 --- a/worldometer/world/population/most_populous_countries.py +++ b/worldometer/world/population/most_populous_countries.py @@ -13,7 +13,7 @@ class CurrentMostPopulousCountriesData: yearly_change: str world_share: str - table_position = 0 + _table_position = 0 @dataclass @@ -24,7 +24,7 @@ class PastMostPopulousCountriesData: world_share: str rank: str - table_position = 1 + _table_position = 1 @dataclass @@ -35,7 +35,7 @@ class FutureMostPopulousCountriesData: world_share: str rank: str - table_position = 2 + _table_position = 2 class MostPopulousCountries: @@ -85,15 +85,15 @@ def _load_data( return ( [ CurrentMostPopulousCountriesData(**data_row) - for data_row in dts[CurrentMostPopulousCountriesData.table_position] + for data_row in dts[CurrentMostPopulousCountriesData._table_position] ], [ PastMostPopulousCountriesData(**data_row) - for data_row in dts[PastMostPopulousCountriesData.table_position] + for data_row in dts[PastMostPopulousCountriesData._table_position] ], [ FutureMostPopulousCountriesData(**data_row) - for data_row in dts[FutureMostPopulousCountriesData.table_position] + for data_row in dts[FutureMostPopulousCountriesData._table_position] ] ) From 2220af564b6b78d661ea94ec2acadddb22d0007b Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 18 Sep 2023 22:32:33 -0300 Subject: [PATCH 061/147] feat: implement api to get largest cities in the world --- worldometer/world/population/__init__.py | 2 + .../world/population/largest_cities.py | 50 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 worldometer/world/population/largest_cities.py diff --git a/worldometer/world/population/__init__.py b/worldometer/world/population/__init__.py index b219767..3cc9dd3 100644 --- a/worldometer/world/population/__init__.py +++ b/worldometer/world/population/__init__.py @@ -1,7 +1,9 @@ __all__ = [ 'CountriesByPopulation', + 'LargestCities', 'MostPopulousCountries' ] from worldometer.world.population.countries_by_population import CountriesByPopulation +from worldometer.world.population.largest_cities import LargestCities from worldometer.world.population.most_populous_countries import MostPopulousCountries diff --git a/worldometer/world/population/largest_cities.py b/worldometer/world/population/largest_cities.py new file mode 100644 index 0000000..0b115d4 --- /dev/null +++ b/worldometer/world/population/largest_cities.py @@ -0,0 +1,50 @@ +from copy import deepcopy +from dataclasses import dataclass +from typing import List + +from worldometer.scraper import get_data_tables + + +@dataclass +class LargestCitiesData: + rank: int + urban_area: str + population_estimate: str + country: str + land_area: int + density: int + + _table_position = 0 + + +class LargestCities: + + source_path = '/population/largest-cities-in-the-world' + new_column_names = ( + 'rank', + 'urban_area', + 'population_estimate', + 'country', + 'land_area', + 'density' + ) + + def __init__(self) -> None: + self._data = self._load_data() + + def _load_data(self) -> List[LargestCitiesData]: + dts = get_data_tables( + path_url=self.source_path, + new_column_names=[ + self.new_column_names + ], + attrs=None + ) + return [ + LargestCitiesData(**data_row) + for data_row in dts[LargestCitiesData._table_position] + ] + + @property + def data(self) -> List[LargestCitiesData]: + return deepcopy(self._data) From af3564f4518de541b2b99e707c993e9b932c6c56 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Mon, 18 Sep 2023 22:41:59 -0300 Subject: [PATCH 062/147] feat: implement api to get world population projections --- worldometer/world/population/__init__.py | 4 +- .../world_population_projections.py | 47 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 worldometer/world/population/world_population_projections.py diff --git a/worldometer/world/population/__init__.py b/worldometer/world/population/__init__.py index 3cc9dd3..9e90ce7 100644 --- a/worldometer/world/population/__init__.py +++ b/worldometer/world/population/__init__.py @@ -1,9 +1,11 @@ __all__ = [ 'CountriesByPopulation', 'LargestCities', - 'MostPopulousCountries' + 'MostPopulousCountries', + 'WorldPopulationProjections' ] from worldometer.world.population.countries_by_population import CountriesByPopulation from worldometer.world.population.largest_cities import LargestCities from worldometer.world.population.most_populous_countries import MostPopulousCountries +from worldometer.world.population.world_population_projections import WorldPopulationProjections diff --git a/worldometer/world/population/world_population_projections.py b/worldometer/world/population/world_population_projections.py new file mode 100644 index 0000000..0bdddd6 --- /dev/null +++ b/worldometer/world/population/world_population_projections.py @@ -0,0 +1,47 @@ +from copy import deepcopy +from dataclasses import dataclass +from typing import List + +from worldometer.scraper import get_data_tables + + +@dataclass +class WorldPopulationProjectionsData: + year: int + world_population: int + yearly_change: str + net_change: int + density: int + + _table_position = 0 + + +class WorldPopulationProjections: + + source_path = '/world-population/world-population-projections' + new_column_names = ( + 'year', + 'world_population', + 'yearly_change', + 'net_change', + 'density' + ) + + def __init__(self) -> None: + self._data = self._load_data() + + def _load_data(self) -> List[WorldPopulationProjectionsData]: + dts = get_data_tables( + path_url=self.source_path, + new_column_names=[ + self.new_column_names + ] + ) + return [ + WorldPopulationProjectionsData(**data_row) + for data_row in dts[WorldPopulationProjectionsData._table_position] + ] + + @property + def data(self) -> List[WorldPopulationProjectionsData]: + return deepcopy(self._data) From c60640bc2befa32e7c6d60aba6f56cde68f3b740 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Tue, 19 Sep 2023 01:15:08 -0300 Subject: [PATCH 063/147] feat: implement api to get world population by year --- worldometer/world/population/__init__.py | 2 + .../population/world_population_by_year.py | 47 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 worldometer/world/population/world_population_by_year.py diff --git a/worldometer/world/population/__init__.py b/worldometer/world/population/__init__.py index 9e90ce7..4b04584 100644 --- a/worldometer/world/population/__init__.py +++ b/worldometer/world/population/__init__.py @@ -2,10 +2,12 @@ 'CountriesByPopulation', 'LargestCities', 'MostPopulousCountries', + 'WorldPopulationByYear', 'WorldPopulationProjections' ] from worldometer.world.population.countries_by_population import CountriesByPopulation from worldometer.world.population.largest_cities import LargestCities from worldometer.world.population.most_populous_countries import MostPopulousCountries +from worldometer.world.population.world_population_by_year import WorldPopulationByYear from worldometer.world.population.world_population_projections import WorldPopulationProjections diff --git a/worldometer/world/population/world_population_by_year.py b/worldometer/world/population/world_population_by_year.py new file mode 100644 index 0000000..23b98ae --- /dev/null +++ b/worldometer/world/population/world_population_by_year.py @@ -0,0 +1,47 @@ +from copy import deepcopy +from dataclasses import dataclass +from typing import List + +from worldometer.scraper import get_data_tables + + +@dataclass +class WorldPopulationByYearData: + year: int + world_population: int + yearly_change: str + net_change: float + density: float + + _table_position = 0 + + +class WorldPopulationByYear: + + source_path = '/world-population/world-population-by-year' + new_column_names = ( + 'year', + 'world_population', + 'yearly_change', + 'net_change', + 'density' + ) + + def __init__(self) -> None: + self._data = self._load_data() + + def _load_data(self) -> List[WorldPopulationByYearData]: + dts = get_data_tables( + path_url=self.source_path, + new_column_names=[ + self.new_column_names + ] + ) + return [ + WorldPopulationByYearData(**data_row) + for data_row in dts[WorldPopulationByYearData._table_position] + ] + + @property + def data(self) -> List[WorldPopulationByYearData]: + return deepcopy(self._data) From 8421903615502d1395e9d8921da6e4471f984f26 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Tue, 19 Sep 2023 01:41:54 -0300 Subject: [PATCH 064/147] feat: implement api to get world population by region --- worldometer/world/population/__init__.py | 2 + .../population/world_population_by_region.py | 117 ++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 worldometer/world/population/world_population_by_region.py diff --git a/worldometer/world/population/__init__.py b/worldometer/world/population/__init__.py index 4b04584..0ff7fc0 100644 --- a/worldometer/world/population/__init__.py +++ b/worldometer/world/population/__init__.py @@ -2,6 +2,7 @@ 'CountriesByPopulation', 'LargestCities', 'MostPopulousCountries', + 'WorldPopulationByRegion', 'WorldPopulationByYear', 'WorldPopulationProjections' ] @@ -9,5 +10,6 @@ from worldometer.world.population.countries_by_population import CountriesByPopulation from worldometer.world.population.largest_cities import LargestCities from worldometer.world.population.most_populous_countries import MostPopulousCountries +from worldometer.world.population.world_population_by_region import WorldPopulationByRegion from worldometer.world.population.world_population_by_year import WorldPopulationByYear from worldometer.world.population.world_population_projections import WorldPopulationProjections diff --git a/worldometer/world/population/world_population_by_region.py b/worldometer/world/population/world_population_by_region.py new file mode 100644 index 0000000..a92baa2 --- /dev/null +++ b/worldometer/world/population/world_population_by_region.py @@ -0,0 +1,117 @@ +from copy import deepcopy +from dataclasses import dataclass +from typing import List, Tuple + +from worldometer.scraper import get_data_tables + + +@dataclass +class CurrentWorldPopulationByRegionData: + position: int + region: str + population: int + yearly_change: str + net_change: int + density: int + area: int + migrants: int + fertility_rate: float + median_age: int + urban_population: str + world_share: str + + _table_position = 0 + + +@dataclass +class PastWorldPopulationByRegionData: + position: int + region: str + population: int + world_share: str + + _table_position = 1 + + +@dataclass +class FutureWorldPopulationByRegionData: + position: int + region: str + population: int + world_share: str + + _table_position = 2 + + +class WorldPopulationByRegion: + + source_path = '/world-population/population-by-region' + new_column_names = ( + ( + 'position', + 'region', + 'population', + 'yearly_change', + 'net_change', + 'density', + 'area', + 'migrants', + 'fertility_rate', + 'median_age', + 'urban_population', + 'world_share' + ), + ( + 'position', + 'region', + 'population', + 'world_share' + ), + ( + 'position', + 'region', + 'population', + 'world_share' + ) + ) + + def __init__(self) -> None: + self._data = self._load_data() + + def _load_data( + self + ) -> Tuple[ + List[CurrentWorldPopulationByRegionData], + List[PastWorldPopulationByRegionData], + List[FutureWorldPopulationByRegionData] + ]: + dts = get_data_tables( + path_url=self.source_path, + new_column_names=[ + *self.new_column_names + ] + ) + + return ( + [ + CurrentWorldPopulationByRegionData(**data_row) + for data_row in dts[CurrentWorldPopulationByRegionData._table_position] + ], + [ + PastWorldPopulationByRegionData(**data_row) + for data_row in dts[PastWorldPopulationByRegionData._table_position] + ], + [ + FutureWorldPopulationByRegionData(**data_row) + for data_row in dts[FutureWorldPopulationByRegionData._table_position] + ] + ) + + def current(self) -> List[CurrentWorldPopulationByRegionData]: + return deepcopy(self._data[0]) + + def past(self) -> List[PastWorldPopulationByRegionData]: + return deepcopy(self._data[1]) + + def future(self) -> List[FutureWorldPopulationByRegionData]: + return deepcopy(self._data[2]) From 927e2d12c4b469e06632bf455653a14c2cb382e4 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Tue, 19 Sep 2023 01:49:25 -0300 Subject: [PATCH 065/147] refactor: simplify module names in population package --- worldometer/world/population/__init__.py | 6 +++--- .../{world_population_by_region.py => by_region.py} | 0 .../population/{world_population_by_year.py => by_year.py} | 0 .../{world_population_projections.py => projections.py} | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename worldometer/world/population/{world_population_by_region.py => by_region.py} (100%) rename worldometer/world/population/{world_population_by_year.py => by_year.py} (100%) rename worldometer/world/population/{world_population_projections.py => projections.py} (100%) diff --git a/worldometer/world/population/__init__.py b/worldometer/world/population/__init__.py index 0ff7fc0..b38004d 100644 --- a/worldometer/world/population/__init__.py +++ b/worldometer/world/population/__init__.py @@ -10,6 +10,6 @@ from worldometer.world.population.countries_by_population import CountriesByPopulation from worldometer.world.population.largest_cities import LargestCities from worldometer.world.population.most_populous_countries import MostPopulousCountries -from worldometer.world.population.world_population_by_region import WorldPopulationByRegion -from worldometer.world.population.world_population_by_year import WorldPopulationByYear -from worldometer.world.population.world_population_projections import WorldPopulationProjections +from worldometer.world.population.by_region import WorldPopulationByRegion +from worldometer.world.population.by_year import WorldPopulationByYear +from worldometer.world.population.projections import WorldPopulationProjections diff --git a/worldometer/world/population/world_population_by_region.py b/worldometer/world/population/by_region.py similarity index 100% rename from worldometer/world/population/world_population_by_region.py rename to worldometer/world/population/by_region.py diff --git a/worldometer/world/population/world_population_by_year.py b/worldometer/world/population/by_year.py similarity index 100% rename from worldometer/world/population/world_population_by_year.py rename to worldometer/world/population/by_year.py diff --git a/worldometer/world/population/world_population_projections.py b/worldometer/world/population/projections.py similarity index 100% rename from worldometer/world/population/world_population_projections.py rename to worldometer/world/population/projections.py From e783e7463174f0add51b6746c5fb1fdd8a15c95a Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Tue, 19 Sep 2023 02:47:24 -0300 Subject: [PATCH 066/147] feat: implement api to get asia population data --- worldometer/world/population/__init__.py | 4 +- worldometer/world/population/asia.py | 133 +++++++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 worldometer/world/population/asia.py diff --git a/worldometer/world/population/__init__.py b/worldometer/world/population/__init__.py index b38004d..6aca065 100644 --- a/worldometer/world/population/__init__.py +++ b/worldometer/world/population/__init__.py @@ -4,7 +4,8 @@ 'MostPopulousCountries', 'WorldPopulationByRegion', 'WorldPopulationByYear', - 'WorldPopulationProjections' + 'WorldPopulationProjections', + 'AsiaPopulation' ] from worldometer.world.population.countries_by_population import CountriesByPopulation @@ -13,3 +14,4 @@ from worldometer.world.population.by_region import WorldPopulationByRegion from worldometer.world.population.by_year import WorldPopulationByYear from worldometer.world.population.projections import WorldPopulationProjections +from worldometer.world.population.asia import AsiaPopulation diff --git a/worldometer/world/population/asia.py b/worldometer/world/population/asia.py new file mode 100644 index 0000000..860bc09 --- /dev/null +++ b/worldometer/world/population/asia.py @@ -0,0 +1,133 @@ +from copy import deepcopy +from dataclasses import dataclass +from typing import List, Tuple + +from worldometer.scraper import get_data_tables + + +@dataclass +class SubregionsData: + area: int + population: str + + _table_position = 0 + + +@dataclass +class HistoricalData: + year: int + population: int + yearly_change_percent: str + yearly_change: int + migrants: int + median_age: float + fertility_rate: float + density: int + urban_population_percent: str + urban_population: int + world_share: str + world_population: int + rank: int + + _table_position = 1 + + +@dataclass +class ForecastData: + year: int + population: int + yearly_change_percent: str + yearly_change: int + migrants: int + median_age: float + fertility_rate: float + density: int + urban_population_percent: str + urban_population: int + world_share: str + world_population: int + rank: int + + _table_position = 2 + + +class AsiaPopulation: + + source_path = '/world-population/asia-population' + new_column_names = ( + ( + 'area', + 'population' + ), + ( + 'year', + 'population', + 'yearly_change_percent', + 'yearly_change', + 'migrants', + 'median_age', + 'fertility_rate', + 'density', + 'urban_population_percent', + 'urban_population', + 'world_share', + 'world_population', + 'rank' + ), + ( + 'year', + 'population', + 'yearly_change_percent', + 'yearly_change', + 'migrants', + 'median_age', + 'fertility_rate', + 'density', + 'urban_population_percent', + 'urban_population', + 'world_share', + 'world_population', + 'rank' + ) + ) + + def __init__(self) -> None: + self._data = self._load_data() + + def _load_data( + self + ) -> Tuple[ + List[SubregionsData], + List[HistoricalData], + List[ForecastData] + ]: + dts = get_data_tables( + path_url=self.source_path, + new_column_names=[ + *self.new_column_names + ] + ) + + return ( + [ + SubregionsData(**data_row) + for data_row in dts[SubregionsData._table_position] + ], + [ + HistoricalData(**data_row) + for data_row in dts[HistoricalData._table_position] + ], + [ + ForecastData(**data_row) + for data_row in dts[ForecastData._table_position] + ] + ) + + def subregions(self) -> List[SubregionsData]: + return deepcopy(self._data[0]) + + def historical(self) -> List[HistoricalData]: + return deepcopy(self._data[1]) + + def forecast(self) -> List[ForecastData]: + return deepcopy(self._data[2]) From e3bbd1e346da2ae2518fc978e3662efc8f5269fe Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Tue, 19 Sep 2023 02:57:04 -0300 Subject: [PATCH 067/147] refactor: get rts counters object on any specified page --- worldometer/scraper/controller.py | 6 ++++-- worldometer/world/counters.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/worldometer/scraper/controller.py b/worldometer/scraper/controller.py index 95c0359..1233127 100644 --- a/worldometer/scraper/controller.py +++ b/worldometer/scraper/controller.py @@ -15,8 +15,10 @@ browser = Browser() -def get_rts_counters_object() -> Dict[str, Union[int, float, None]]: - url = make_url(BASE_URL) +def get_rts_counters_object( + path_url: Optional[str] = None +) -> Dict[str, Union[int, float, None]]: + url = make_url(BASE_URL, path_url) html = browser.get_page_content(url) script_return = browser.run_js_script(html, script='() => rts_counters') rts_counters = get_rts_counters_only_with_last_value_key(rts_counters=script_return) diff --git a/worldometer/world/counters.py b/worldometer/world/counters.py index ca8ed03..a0be0da 100644 --- a/worldometer/world/counters.py +++ b/worldometer/world/counters.py @@ -13,7 +13,7 @@ def __init__(self) -> None: self._init_counters() def _load_data(self) -> Dict[str, Union[int, float, None]]: - rts_counters = get_rts_counters_object() + rts_counters = get_rts_counters_object(path_url=self.source_path) return rts_counters def _init_counters(self) -> None: From 5361149e02b3c3b2833c8dde469c819c4e40dee7 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Tue, 19 Sep 2023 03:11:45 -0300 Subject: [PATCH 068/147] feat: implement live method to get current asia population --- worldometer/world/population/asia.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/worldometer/world/population/asia.py b/worldometer/world/population/asia.py index 860bc09..4933264 100644 --- a/worldometer/world/population/asia.py +++ b/worldometer/world/population/asia.py @@ -1,8 +1,8 @@ from copy import deepcopy from dataclasses import dataclass -from typing import List, Tuple +from typing import List, Tuple, Union -from worldometer.scraper import get_data_tables +from worldometer.scraper import get_data_tables, get_rts_counters_object @dataclass @@ -123,6 +123,10 @@ def _load_data( ] ) + def live(self) -> Union[int, float, None]: + rts_counters = get_rts_counters_object(path_url=self.source_path) + return rts_counters.get('asia-population') + def subregions(self) -> List[SubregionsData]: return deepcopy(self._data[0]) From ade32b86df42fd25d6b536c9b0b85bd012466054 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 20 Sep 2023 04:27:18 -0300 Subject: [PATCH 069/147] refactor: delete asia module --- worldometer/world/population/asia.py | 137 --------------------------- 1 file changed, 137 deletions(-) delete mode 100644 worldometer/world/population/asia.py diff --git a/worldometer/world/population/asia.py b/worldometer/world/population/asia.py deleted file mode 100644 index 4933264..0000000 --- a/worldometer/world/population/asia.py +++ /dev/null @@ -1,137 +0,0 @@ -from copy import deepcopy -from dataclasses import dataclass -from typing import List, Tuple, Union - -from worldometer.scraper import get_data_tables, get_rts_counters_object - - -@dataclass -class SubregionsData: - area: int - population: str - - _table_position = 0 - - -@dataclass -class HistoricalData: - year: int - population: int - yearly_change_percent: str - yearly_change: int - migrants: int - median_age: float - fertility_rate: float - density: int - urban_population_percent: str - urban_population: int - world_share: str - world_population: int - rank: int - - _table_position = 1 - - -@dataclass -class ForecastData: - year: int - population: int - yearly_change_percent: str - yearly_change: int - migrants: int - median_age: float - fertility_rate: float - density: int - urban_population_percent: str - urban_population: int - world_share: str - world_population: int - rank: int - - _table_position = 2 - - -class AsiaPopulation: - - source_path = '/world-population/asia-population' - new_column_names = ( - ( - 'area', - 'population' - ), - ( - 'year', - 'population', - 'yearly_change_percent', - 'yearly_change', - 'migrants', - 'median_age', - 'fertility_rate', - 'density', - 'urban_population_percent', - 'urban_population', - 'world_share', - 'world_population', - 'rank' - ), - ( - 'year', - 'population', - 'yearly_change_percent', - 'yearly_change', - 'migrants', - 'median_age', - 'fertility_rate', - 'density', - 'urban_population_percent', - 'urban_population', - 'world_share', - 'world_population', - 'rank' - ) - ) - - def __init__(self) -> None: - self._data = self._load_data() - - def _load_data( - self - ) -> Tuple[ - List[SubregionsData], - List[HistoricalData], - List[ForecastData] - ]: - dts = get_data_tables( - path_url=self.source_path, - new_column_names=[ - *self.new_column_names - ] - ) - - return ( - [ - SubregionsData(**data_row) - for data_row in dts[SubregionsData._table_position] - ], - [ - HistoricalData(**data_row) - for data_row in dts[HistoricalData._table_position] - ], - [ - ForecastData(**data_row) - for data_row in dts[ForecastData._table_position] - ] - ) - - def live(self) -> Union[int, float, None]: - rts_counters = get_rts_counters_object(path_url=self.source_path) - return rts_counters.get('asia-population') - - def subregions(self) -> List[SubregionsData]: - return deepcopy(self._data[0]) - - def historical(self) -> List[HistoricalData]: - return deepcopy(self._data[1]) - - def forecast(self) -> List[ForecastData]: - return deepcopy(self._data[2]) From 854d238dfdb3c81ad11fbbf50adf1fa18ce6a526 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 20 Sep 2023 04:28:50 -0300 Subject: [PATCH 070/147] feat: implement api to get all regions population data regions: Asia Africa Europe Latin American And The Caribbean Northern American Oceania --- worldometer/world/population/__init__.py | 16 ++- worldometer/world/population/regions.py | 168 +++++++++++++++++++++++ 2 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 worldometer/world/population/regions.py diff --git a/worldometer/world/population/__init__.py b/worldometer/world/population/__init__.py index 6aca065..da335d4 100644 --- a/worldometer/world/population/__init__.py +++ b/worldometer/world/population/__init__.py @@ -5,7 +5,12 @@ 'WorldPopulationByRegion', 'WorldPopulationByYear', 'WorldPopulationProjections', - 'AsiaPopulation' + 'AsiaPopulation', + 'AfricaPopulation', + 'EuropePopulation', + 'LatinAmericanAndTheCaribbeanPopulation', + 'NorthernAmericanPopulation', + 'OceaniaPopulation' ] from worldometer.world.population.countries_by_population import CountriesByPopulation @@ -14,4 +19,11 @@ from worldometer.world.population.by_region import WorldPopulationByRegion from worldometer.world.population.by_year import WorldPopulationByYear from worldometer.world.population.projections import WorldPopulationProjections -from worldometer.world.population.asia import AsiaPopulation +from worldometer.world.population.regions import ( + AsiaPopulation, + AfricaPopulation, + EuropePopulation, + LatinAmericanAndTheCaribbeanPopulation, + NorthernAmericanPopulation, + OceaniaPopulation +) diff --git a/worldometer/world/population/regions.py b/worldometer/world/population/regions.py new file mode 100644 index 0000000..86f178f --- /dev/null +++ b/worldometer/world/population/regions.py @@ -0,0 +1,168 @@ +from copy import deepcopy +from dataclasses import dataclass +from typing import List, Tuple, Union + +from worldometer.scraper import get_data_tables, get_rts_counters_object + + +@dataclass +class SubregionData: + area: int + population: str + + _table_position = 0 + + +@dataclass +class HistoricalData: + year: int + population: int + yearly_change_percent: str + yearly_change: int + migrants: int + median_age: float + fertility_rate: float + density: int + urban_population_percent: str + urban_population: int + world_share: str + world_population: int + rank: int + + _table_position = 1 + + +@dataclass +class ForecastData: + year: int + population: int + yearly_change_percent: str + yearly_change: int + migrants: int + median_age: float + fertility_rate: float + density: int + urban_population_percent: str + urban_population: int + world_share: str + world_population: int + rank: int + + _table_position = 2 + + +class _RegionPopulation: + + _key_rts_counters = '[override]' + source_path = '[override]' + new_column_names = ( + ( + 'area', + 'population' + ), + ( + 'year', + 'population', + 'yearly_change_percent', + 'yearly_change', + 'migrants', + 'median_age', + 'fertility_rate', + 'density', + 'urban_population_percent', + 'urban_population', + 'world_share', + 'world_population', + 'rank' + ), + ( + 'year', + 'population', + 'yearly_change_percent', + 'yearly_change', + 'migrants', + 'median_age', + 'fertility_rate', + 'density', + 'urban_population_percent', + 'urban_population', + 'world_share', + 'world_population', + 'rank' + ) + ) + + def __init__(self) -> None: + self._data = self._load_data() + + def _load_data( + self + ) -> Tuple[ + List[SubregionData], + List[HistoricalData], + List[ForecastData] + ]: + dts = get_data_tables( + path_url=self.source_path, + new_column_names=[ + *self.new_column_names + ] + ) + + return ( + [ + SubregionData(**data_row) + for data_row in dts[SubregionData._table_position] + ], + [ + HistoricalData(**data_row) + for data_row in dts[HistoricalData._table_position] + ], + [ + ForecastData(**data_row) + for data_row in dts[ForecastData._table_position] + ] + ) + + def live(self) -> Union[int, float, None]: + rts_counters = get_rts_counters_object(path_url=self.source_path) + return rts_counters.get(self._key_rts_counters) + + def subregions(self) -> List[SubregionData]: + return deepcopy(self._data[SubregionData._table_position]) # type: ignore + + def historical(self) -> List[HistoricalData]: + return deepcopy(self._data[HistoricalData._table_position]) # type: ignore + + def forecast(self) -> List[ForecastData]: + return deepcopy(self._data[ForecastData._table_position]) # type: ignore + + +class AsiaPopulation(_RegionPopulation): + _key_rts_counters = 'asia-population' + source_path = '/world-population/asia-population' + + +class AfricaPopulation(_RegionPopulation): + _key_rts_counters = 'africa-population' + source_path = '/world-population/africa-population' + + +class EuropePopulation(_RegionPopulation): + _key_rts_counters = 'europe-population' + source_path = '/world-population/europe-population' + + +class LatinAmericanAndTheCaribbeanPopulation(_RegionPopulation): + _key_rts_counters = 'latin-america-and-the-caribbean-population' + source_path = '/world-population/latin-america-and-the-caribbean-population' + + +class NorthernAmericanPopulation(_RegionPopulation): + _key_rts_counters = 'northern-america-population' + source_path = '/world-population/northern-america-population' + + +class OceaniaPopulation(_RegionPopulation): + _key_rts_counters = 'oceania-population' + source_path = '/world-population/oceania-population' From 5a8245ee1c5429c2982a35423b63f79a1cba5a72 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 20 Sep 2023 15:25:12 -0300 Subject: [PATCH 071/147] refactor: use the table position defined in your dataclasses --- worldometer/world/population/by_region.py | 6 +++--- worldometer/world/population/most_populous_countries.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/worldometer/world/population/by_region.py b/worldometer/world/population/by_region.py index a92baa2..98a6518 100644 --- a/worldometer/world/population/by_region.py +++ b/worldometer/world/population/by_region.py @@ -108,10 +108,10 @@ def _load_data( ) def current(self) -> List[CurrentWorldPopulationByRegionData]: - return deepcopy(self._data[0]) + return deepcopy(self._data[CurrentWorldPopulationByRegionData._table_position]) # type: ignore def past(self) -> List[PastWorldPopulationByRegionData]: - return deepcopy(self._data[1]) + return deepcopy(self._data[PastWorldPopulationByRegionData._table_position]) # type: ignore def future(self) -> List[FutureWorldPopulationByRegionData]: - return deepcopy(self._data[2]) + return deepcopy(self._data[FutureWorldPopulationByRegionData._table_position]) # type: ignore diff --git a/worldometer/world/population/most_populous_countries.py b/worldometer/world/population/most_populous_countries.py index f093119..4a7f59a 100644 --- a/worldometer/world/population/most_populous_countries.py +++ b/worldometer/world/population/most_populous_countries.py @@ -98,10 +98,10 @@ def _load_data( ) def current(self) -> List[CurrentMostPopulousCountriesData]: - return deepcopy(self._data[0]) + return deepcopy(self._data[CurrentMostPopulousCountriesData._table_position]) # type: ignore def past(self) -> List[PastMostPopulousCountriesData]: - return deepcopy(self._data[1]) + return deepcopy(self._data[PastMostPopulousCountriesData._table_position]) # type: ignore def future(self) -> List[FutureMostPopulousCountriesData]: - return deepcopy(self._data[2]) + return deepcopy(self._data[FutureMostPopulousCountriesData._table_position]) # type: ignore From 3c26cbb2d486317db9852efa98c19a124e2f4f0c Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 20 Sep 2023 15:28:34 -0300 Subject: [PATCH 072/147] feat: define population package as a public api --- worldometer/world/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/worldometer/world/__init__.py b/worldometer/world/__init__.py index db967d8..c397753 100644 --- a/worldometer/world/__init__.py +++ b/worldometer/world/__init__.py @@ -1,7 +1,9 @@ __all__ = [ 'WorldCounters', - 'CountryCodes' + 'CountryCodes', + 'population' ] from worldometer.world.counters import WorldCounters from worldometer.world.country_codes import CountryCodes +from worldometer.world import population From 92041c4a2676e02343af682afb40c7ea7768e936 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 20 Sep 2023 16:46:29 -0300 Subject: [PATCH 073/147] feat: create geography package and implement new APIs Implemented APIs to get countries from all regions of the world: - World Countries; - Asia Countries; - Africa Countries; - Europe Countries; - Latin American And The Caribbean Countries; - Northern American Countries; - Oceania Countries. --- worldometer/world/geography/__init__.py | 19 +++ worldometer/world/geography/countries.py | 144 +++++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 worldometer/world/geography/__init__.py create mode 100644 worldometer/world/geography/countries.py diff --git a/worldometer/world/geography/__init__.py b/worldometer/world/geography/__init__.py new file mode 100644 index 0000000..eb0d04a --- /dev/null +++ b/worldometer/world/geography/__init__.py @@ -0,0 +1,19 @@ +__all__ = [ + 'WorldCountries', + 'AsiaCountries', + 'AfricaCountries', + 'EuropeCountries', + 'LatinAmericanAndTheCaribbeanCountries', + 'NorthernAmericanCountries', + 'OceaniaCountries' +] + +from worldometer.world.geography.countries import ( + WorldCountries, + AsiaCountries, + AfricaCountries, + EuropeCountries, + LatinAmericanAndTheCaribbeanCountries, + NorthernAmericanCountries, + OceaniaCountries +) diff --git a/worldometer/world/geography/countries.py b/worldometer/world/geography/countries.py new file mode 100644 index 0000000..abfdf38 --- /dev/null +++ b/worldometer/world/geography/countries.py @@ -0,0 +1,144 @@ +from copy import deepcopy +from dataclasses import dataclass +from typing import List, Tuple + +from worldometer.scraper import get_data_tables + + +@dataclass +class WorldCountriesData: + position: int + country: str + population: int + world_share: str + land_area: int + + _table_position = 0 + + +@dataclass +class CountryData: + position: int + country: str + population: int + subregion: str + + _table_position = 0 + + +@dataclass +class DependencyData: + position: int + territory: str + population: int + dependency_of: str + + _table_position = 1 + + +class WorldCountries: + + source_path = '/geography/how-many-countries-are-there-in-the-world' + new_column_names = ( + 'position', + 'country', + 'population', + 'world_share', + 'land_area' + ) + + def __init__(self) -> None: + self._data = self._load_data() + self.total = len(self._data) + + def _load_data(self) -> List[WorldCountriesData]: + dts = get_data_tables( + path_url=self.source_path, + new_column_names=[ + self.new_column_names + ] + ) + return [ + WorldCountriesData(**data_row) + for data_row in dts[WorldCountriesData._table_position] + ] + + def countries(self) -> List[WorldCountriesData]: + return deepcopy(self._data) + + +class _RegionCountries: + + source_path = '[override]' + new_column_names = ( + ( + 'position', + 'country', + 'population', + 'subregion' + ), + ( + 'position', + 'territory', + 'population', + 'dependency_of' + ) + ) + + def __init__(self) -> None: + self._data = self._load_data() + self.total = len(self._data[CountryData._table_position]) + + def _load_data( + self + ) -> Tuple[ + List[CountryData], + List[DependencyData] + ]: + dts = get_data_tables( + path_url=self.source_path, + new_column_names=[ + *self.new_column_names + ] + ) + + return ( + [ + CountryData(**data_row) + for data_row in dts[CountryData._table_position] + ], + [ + DependencyData(**data_row) + for data_row in dts[DependencyData._table_position] + ] + ) + + def countries(self) -> List[CountryData]: + return deepcopy(self._data[CountryData._table_position]) # type: ignore + + def dependencies(self) -> List[DependencyData]: + return deepcopy(self._data[DependencyData._table_position]) # type: ignore + + +class AsiaCountries(_RegionCountries): + source_path = '/geography/how-many-countries-in-asia' + + +class AfricaCountries(_RegionCountries): + source_path = '/geography/how-many-countries-in-africa' + + +class EuropeCountries(_RegionCountries): + source_path = '/geography/how-many-countries-in-europe' + + +class LatinAmericanAndTheCaribbeanCountries(_RegionCountries): + source_path = '/geography/how-many-countries-in-latin-america' + + +class NorthernAmericanCountries(_RegionCountries): + source_path = '/geography/how-many-countries-in-northern-america' + + +class OceaniaCountries(_RegionCountries): + source_path = '/geography/how-many-countries-in-oceania' From a8c2d932ad979f101d024d0e86b832a60c4ac584 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 20 Sep 2023 18:34:03 -0300 Subject: [PATCH 074/147] feat: implement api to get largest countries by area --- worldometer/world/geography/__init__.py | 2 + .../world/geography/largest_countries.py | 51 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 worldometer/world/geography/largest_countries.py diff --git a/worldometer/world/geography/__init__.py b/worldometer/world/geography/__init__.py index eb0d04a..8027de3 100644 --- a/worldometer/world/geography/__init__.py +++ b/worldometer/world/geography/__init__.py @@ -1,4 +1,5 @@ __all__ = [ + 'LargestCountries', 'WorldCountries', 'AsiaCountries', 'AfricaCountries', @@ -8,6 +9,7 @@ 'OceaniaCountries' ] +from worldometer.world.geography.largest_countries import LargestCountries from worldometer.world.geography.countries import ( WorldCountries, AsiaCountries, diff --git a/worldometer/world/geography/largest_countries.py b/worldometer/world/geography/largest_countries.py new file mode 100644 index 0000000..743d1e5 --- /dev/null +++ b/worldometer/world/geography/largest_countries.py @@ -0,0 +1,51 @@ +from copy import deepcopy +from dataclasses import dataclass +from typing import List + +from worldometer.scraper import get_data_tables + + +@dataclass +class LargestCountriesData: + position: int + country: str + total_area_km2: int + total_area_mi2: int + land_area_km2: int + land_area_mi2: int + percentage_of_world_landmass: str + + _table_position = 0 + + +class LargestCountries: + + source_path = '/geography/largest-countries-in-the-world' + new_column_names = ( + 'position', + 'country', + 'total_area_km2', + 'total_area_mi2', + 'land_area_km2', + 'land_area_mi2', + 'percentage_of_world_landmass' + ) + + def __init__(self) -> None: + self._data = self._load_data() + + def _load_data(self) -> List[LargestCountriesData]: + dts = get_data_tables( + path_url=self.source_path, + new_column_names=[ + self.new_column_names + ] + ) + return [ + LargestCountriesData(**data_row) + for data_row in dts[LargestCountriesData._table_position] + ] + + @property + def data(self) -> List[LargestCountriesData]: + return deepcopy(self._data) From cd891ce49c9faa2397ce913fccfbcb50b8b66bae Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 20 Sep 2023 18:36:35 -0300 Subject: [PATCH 075/147] feat: define geography package as a public api --- worldometer/world/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/worldometer/world/__init__.py b/worldometer/world/__init__.py index c397753..a41c515 100644 --- a/worldometer/world/__init__.py +++ b/worldometer/world/__init__.py @@ -1,9 +1,11 @@ __all__ = [ 'WorldCounters', 'CountryCodes', - 'population' + 'population', + 'geography' ] from worldometer.world.counters import WorldCounters from worldometer.world.country_codes import CountryCodes from worldometer.world import population +from worldometer.world import geography From cdfe44dc9f27a2cfb47bdee597037d37204a442a Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 20 Sep 2023 18:37:29 -0300 Subject: [PATCH 076/147] style: reorder imports in world.__init__ --- worldometer/world/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/worldometer/world/__init__.py b/worldometer/world/__init__.py index a41c515..ba1426f 100644 --- a/worldometer/world/__init__.py +++ b/worldometer/world/__init__.py @@ -1,11 +1,11 @@ __all__ = [ - 'WorldCounters', - 'CountryCodes', + 'geography', 'population', - 'geography' + 'CountryCodes', + 'WorldCounters' ] -from worldometer.world.counters import WorldCounters -from worldometer.world.country_codes import CountryCodes -from worldometer.world import population from worldometer.world import geography +from worldometer.world import population +from worldometer.world.country_codes import CountryCodes +from worldometer.world.counters import WorldCounters From 2f46cc68be9c9e03f7e845d9b51c97eac7dbccf7 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Tue, 26 Sep 2023 02:15:23 -0300 Subject: [PATCH 077/147] refactor: rename all occurrences of position by idx --- worldometer/world/geography/countries.py | 12 ++++++------ worldometer/world/geography/largest_countries.py | 4 ++-- worldometer/world/population/by_region.py | 12 ++++++------ .../world/population/countries_by_population.py | 4 ++-- .../world/population/most_populous_countries.py | 12 ++++++------ 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/worldometer/world/geography/countries.py b/worldometer/world/geography/countries.py index abfdf38..5d6d2c7 100644 --- a/worldometer/world/geography/countries.py +++ b/worldometer/world/geography/countries.py @@ -7,7 +7,7 @@ @dataclass class WorldCountriesData: - position: int + idx: int country: str population: int world_share: str @@ -18,7 +18,7 @@ class WorldCountriesData: @dataclass class CountryData: - position: int + idx: int country: str population: int subregion: str @@ -28,7 +28,7 @@ class CountryData: @dataclass class DependencyData: - position: int + idx: int territory: str population: int dependency_of: str @@ -40,7 +40,7 @@ class WorldCountries: source_path = '/geography/how-many-countries-are-there-in-the-world' new_column_names = ( - 'position', + 'idx', 'country', 'population', 'world_share', @@ -72,13 +72,13 @@ class _RegionCountries: source_path = '[override]' new_column_names = ( ( - 'position', + 'idx', 'country', 'population', 'subregion' ), ( - 'position', + 'idx', 'territory', 'population', 'dependency_of' diff --git a/worldometer/world/geography/largest_countries.py b/worldometer/world/geography/largest_countries.py index 743d1e5..24a9dcd 100644 --- a/worldometer/world/geography/largest_countries.py +++ b/worldometer/world/geography/largest_countries.py @@ -7,7 +7,7 @@ @dataclass class LargestCountriesData: - position: int + idx: int country: str total_area_km2: int total_area_mi2: int @@ -22,7 +22,7 @@ class LargestCountries: source_path = '/geography/largest-countries-in-the-world' new_column_names = ( - 'position', + 'idx', 'country', 'total_area_km2', 'total_area_mi2', diff --git a/worldometer/world/population/by_region.py b/worldometer/world/population/by_region.py index 98a6518..5169d82 100644 --- a/worldometer/world/population/by_region.py +++ b/worldometer/world/population/by_region.py @@ -7,7 +7,7 @@ @dataclass class CurrentWorldPopulationByRegionData: - position: int + idx: int region: str population: int yearly_change: str @@ -25,7 +25,7 @@ class CurrentWorldPopulationByRegionData: @dataclass class PastWorldPopulationByRegionData: - position: int + idx: int region: str population: int world_share: str @@ -35,7 +35,7 @@ class PastWorldPopulationByRegionData: @dataclass class FutureWorldPopulationByRegionData: - position: int + idx: int region: str population: int world_share: str @@ -48,7 +48,7 @@ class WorldPopulationByRegion: source_path = '/world-population/population-by-region' new_column_names = ( ( - 'position', + 'idx', 'region', 'population', 'yearly_change', @@ -62,13 +62,13 @@ class WorldPopulationByRegion: 'world_share' ), ( - 'position', + 'idx', 'region', 'population', 'world_share' ), ( - 'position', + 'idx', 'region', 'population', 'world_share' diff --git a/worldometer/world/population/countries_by_population.py b/worldometer/world/population/countries_by_population.py index 734b435..8ae7648 100644 --- a/worldometer/world/population/countries_by_population.py +++ b/worldometer/world/population/countries_by_population.py @@ -7,7 +7,7 @@ @dataclass class CountriesByPopulationData: - position: int + idx: int country: str population: int yearly_change: str @@ -27,7 +27,7 @@ class CountriesByPopulation: source_path = '/world-population/population-by-country' new_column_names = ( - 'position', + 'idx', 'country', 'population', 'yearly_change', diff --git a/worldometer/world/population/most_populous_countries.py b/worldometer/world/population/most_populous_countries.py index 4a7f59a..809dbd1 100644 --- a/worldometer/world/population/most_populous_countries.py +++ b/worldometer/world/population/most_populous_countries.py @@ -7,7 +7,7 @@ @dataclass class CurrentMostPopulousCountriesData: - position: int + idx: int country: str population: int yearly_change: str @@ -18,7 +18,7 @@ class CurrentMostPopulousCountriesData: @dataclass class PastMostPopulousCountriesData: - position: int + idx: int country: str population: int world_share: str @@ -29,7 +29,7 @@ class PastMostPopulousCountriesData: @dataclass class FutureMostPopulousCountriesData: - position: int + idx: int country: str population: int world_share: str @@ -43,21 +43,21 @@ class MostPopulousCountries: source_path = '/population/most-populous-countries' new_column_names = ( ( - 'position', + 'idx', 'country', 'population', 'yearly_change', 'world_share' ), ( - 'position', + 'idx', 'country', 'population', 'world_share', 'rank' ), ( - 'position', + 'idx', 'country', 'population', 'world_share', From 79525b90163714108cf2675d720d2da84595750c Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Fri, 6 Oct 2023 20:49:12 -0300 Subject: [PATCH 078/147] docs: add docstrings to WorldCounters and related classes --- worldometer/world/counters.py | 48 +++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/worldometer/world/counters.py b/worldometer/world/counters.py index a0be0da..ae2ed32 100644 --- a/worldometer/world/counters.py +++ b/worldometer/world/counters.py @@ -5,7 +5,42 @@ class WorldCounters: - + """Contains a reference to each section of the home page counters. + + Attributes + ---------- + source_path : str + The source path for the counters. + world_population : WorldPopulation + An instance of the `WorldPopulation` class that stores all counters + related to population data. + government_and_economics : GovernmentAndEconomics + An instance of the `GovernmentAndEconomics` class that stores all + counters related to government and economic data. + society_and_media : SocietyAndMedia + An instance of the `SocietyAndMedia` class that stores all counters + related to society and media data. + environment : Environment + An instance of the `Environment` class that stores all counters related + to environmental data. + food : Food + An instance of the `Food` class that stores all counters related to + food data. + water : Water + An instance of the `Water` class that stores all counters related to + water data. + energy : Energy + An instance of the `Energy` class that stores all counters related to + energy data. + health : Health + An instance of the `Health` class that stores all counters related to + health data. + + Notes + ----- + For precise and up-to-date information on each section and its counters, + please check the `worldometers homepage `_. + """ source_path = '/' def __init__(self) -> None: @@ -26,13 +61,15 @@ def _init_counters(self) -> None: self.energy = Energy(self._data) self.health = Health(self._data) - def reload_data(self): + def reload_data(self) -> None: + """Reload all counters data. This loads the available updated data.""" self._data = self._load_data() self._init_counters() @dataclass class WorldPopulation: + """Counters related to world population data.""" _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: @@ -47,6 +84,7 @@ def __post_init__(self) -> None: @dataclass class GovernmentAndEconomics: + """Counters related to government and economic data.""" _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: @@ -60,6 +98,7 @@ def __post_init__(self) -> None: @dataclass class SocietyAndMedia: + """Counters related to society and media data.""" _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: @@ -77,6 +116,7 @@ def __post_init__(self) -> None: @dataclass class Environment: + """Counters related to environmental data.""" _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: @@ -89,6 +129,7 @@ def __post_init__(self) -> None: @dataclass class Food: + """Counters related to food data.""" _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: @@ -102,6 +143,7 @@ def __post_init__(self) -> None: @dataclass class Water: + """Counters related to water data.""" _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: @@ -112,6 +154,7 @@ def __post_init__(self) -> None: @dataclass class Energy: + """Counters related to energy data.""" _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: @@ -130,6 +173,7 @@ def __post_init__(self) -> None: @dataclass class Health: + """Counters related to health data.""" _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: From 75e9f05e53166dc5a9a59e7a98720ae6b950ffd3 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Fri, 6 Oct 2023 21:28:41 -0300 Subject: [PATCH 079/147] docs: add docstrings to CountryCodes and related classes --- worldometer/world/country_codes.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/worldometer/world/country_codes.py b/worldometer/world/country_codes.py index fd924bc..5268b9a 100644 --- a/worldometer/world/country_codes.py +++ b/worldometer/world/country_codes.py @@ -7,6 +7,7 @@ @dataclass class CountryCodesData: + """Represents a data row from the respective table.""" country: str calling_code: str three_letter_iso: str @@ -17,7 +18,21 @@ class CountryCodesData: class CountryCodes: + """Represents the data table of some codes used by each country. + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original table. + + Notes + ----- + Check the source table in + `Worldometers Country Codes `_. + """ source_path = '/country-codes' new_column_names = ( 'country', @@ -44,4 +59,8 @@ def _load_data(self) -> List[CountryCodesData]: @property def data(self) -> List[CountryCodesData]: + """Get a list of all the data from the table. + + Each index in the list contains an object representing a data row of the table. + """ return deepcopy(self._data) From e610a030456372c7af502d9b97affb848104f837 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 7 Oct 2023 03:43:31 -0300 Subject: [PATCH 080/147] docs: add docstrings to CountriesByPopulation and related classes --- worldometer/world/country_codes.py | 3 ++- .../population/countries_by_population.py | 20 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/worldometer/world/country_codes.py b/worldometer/world/country_codes.py index 5268b9a..5a1f14e 100644 --- a/worldometer/world/country_codes.py +++ b/worldometer/world/country_codes.py @@ -61,6 +61,7 @@ def _load_data(self) -> List[CountryCodesData]: def data(self) -> List[CountryCodesData]: """Get a list of all the data from the table. - Each index in the list contains an object representing a data row of the table. + Each index in the list contains an object representing + a data row of the table. """ return deepcopy(self._data) diff --git a/worldometer/world/population/countries_by_population.py b/worldometer/world/population/countries_by_population.py index 8ae7648..bf9beee 100644 --- a/worldometer/world/population/countries_by_population.py +++ b/worldometer/world/population/countries_by_population.py @@ -7,6 +7,7 @@ @dataclass class CountriesByPopulationData: + """Represents a data row from the respective table.""" idx: int country: str population: int @@ -24,7 +25,21 @@ class CountriesByPopulationData: class CountriesByPopulation: + """Represents the data table of countries in the world by population. + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original table. + + Notes + ----- + Check the source table in + `Countries in the world by population `_. + """ source_path = '/world-population/population-by-country' new_column_names = ( 'idx', @@ -58,4 +73,9 @@ def _load_data(self) -> List[CountriesByPopulationData]: @property def data(self) -> List[CountriesByPopulationData]: + """Get a list of all the data from the table. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data) From 3ef0c7cbfa61a7760258aeae1f3764593e755f9b Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 7 Oct 2023 03:47:57 -0300 Subject: [PATCH 081/147] fix: upd source URL in CountriesByPopulation notes --- worldometer/world/population/countries_by_population.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldometer/world/population/countries_by_population.py b/worldometer/world/population/countries_by_population.py index bf9beee..a08a1e0 100644 --- a/worldometer/world/population/countries_by_population.py +++ b/worldometer/world/population/countries_by_population.py @@ -38,7 +38,7 @@ class CountriesByPopulation: Notes ----- Check the source table in - `Countries in the world by population `_. + `Countries in the world by population `_. """ source_path = '/world-population/population-by-country' new_column_names = ( From 91f5bd3797cbc99d30dc9ef759a1b4d5efbc8ffd Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 7 Oct 2023 04:20:48 -0300 Subject: [PATCH 082/147] docs: add docstrings to WorldPopulationByRegion and related classes --- worldometer/world/population/by_region.py | 40 ++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/worldometer/world/population/by_region.py b/worldometer/world/population/by_region.py index 5169d82..2096fba 100644 --- a/worldometer/world/population/by_region.py +++ b/worldometer/world/population/by_region.py @@ -7,6 +7,7 @@ @dataclass class CurrentWorldPopulationByRegionData: + """Represents a data row from the respective table.""" idx: int region: str population: int @@ -25,6 +26,7 @@ class CurrentWorldPopulationByRegionData: @dataclass class PastWorldPopulationByRegionData: + """Represents a data row from the respective table.""" idx: int region: str population: int @@ -35,6 +37,7 @@ class PastWorldPopulationByRegionData: @dataclass class FutureWorldPopulationByRegionData: + """Represents a data row from the respective table.""" idx: int region: str population: int @@ -44,7 +47,21 @@ class FutureWorldPopulationByRegionData: class WorldPopulationByRegion: - + """Represents the data table of regions in the world by population. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original table. + + Notes + ----- + Check the source table in + `Regions in the world by population `_. + """ source_path = '/world-population/population-by-region' new_column_names = ( ( @@ -108,10 +125,31 @@ def _load_data( ) def current(self) -> List[CurrentWorldPopulationByRegionData]: + """Get a list of all the current data from the table. + + These data are related to the current year. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data[CurrentWorldPopulationByRegionData._table_position]) # type: ignore def past(self) -> List[PastWorldPopulationByRegionData]: + """Get a list of all historical data from the table. + + These data pertain to the year 1950. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data[PastWorldPopulationByRegionData._table_position]) # type: ignore def future(self) -> List[FutureWorldPopulationByRegionData]: + """Get a list of all future data from the table. + + These data are an estimate for the year 2050. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data[FutureWorldPopulationByRegionData._table_position]) # type: ignore From a2fc3874a22f4699a83e544f0ba692e7f45ac563 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 7 Oct 2023 04:26:11 -0300 Subject: [PATCH 083/147] docs: add docstrings to WorldPopulationByYear and related classes --- worldometer/world/population/by_year.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/worldometer/world/population/by_year.py b/worldometer/world/population/by_year.py index 23b98ae..b27736b 100644 --- a/worldometer/world/population/by_year.py +++ b/worldometer/world/population/by_year.py @@ -7,6 +7,7 @@ @dataclass class WorldPopulationByYearData: + """Represents a data row from the respective table.""" year: int world_population: int yearly_change: str @@ -17,7 +18,21 @@ class WorldPopulationByYearData: class WorldPopulationByYear: + """Represents the data table of the world population by year. + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original table. + + Notes + ----- + Check the source table in the + `world population by year `_. + """ source_path = '/world-population/world-population-by-year' new_column_names = ( 'year', @@ -44,4 +59,9 @@ def _load_data(self) -> List[WorldPopulationByYearData]: @property def data(self) -> List[WorldPopulationByYearData]: + """Get a list of all the data from the table. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data) From c8dfbb8a5223de9abe41362d4a14f12368377508 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 7 Oct 2023 04:32:52 -0300 Subject: [PATCH 084/147] docs: add docstrings to LargestCities and related classes --- .../world/population/largest_cities.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/worldometer/world/population/largest_cities.py b/worldometer/world/population/largest_cities.py index 0b115d4..571035f 100644 --- a/worldometer/world/population/largest_cities.py +++ b/worldometer/world/population/largest_cities.py @@ -7,6 +7,7 @@ @dataclass class LargestCitiesData: + """Represents a data row from the respective table.""" rank: int urban_area: str population_estimate: str @@ -18,7 +19,21 @@ class LargestCitiesData: class LargestCities: + """Represents the data table of the largest cities in the world. + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original table. + + Notes + ----- + Check the source table in the + `largest cities in the world `_. + """ source_path = '/population/largest-cities-in-the-world' new_column_names = ( 'rank', @@ -47,4 +62,9 @@ def _load_data(self) -> List[LargestCitiesData]: @property def data(self) -> List[LargestCitiesData]: + """Get a list of all the data from the table. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data) From 5e2ed72d9db70377751b2fcef3faa63f08f6cee8 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 7 Oct 2023 04:46:42 -0300 Subject: [PATCH 085/147] docs: add docstrings to MostPopulousCountries and related classes --- .../population/most_populous_countries.py | 40 ++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/worldometer/world/population/most_populous_countries.py b/worldometer/world/population/most_populous_countries.py index 809dbd1..01455d8 100644 --- a/worldometer/world/population/most_populous_countries.py +++ b/worldometer/world/population/most_populous_countries.py @@ -7,6 +7,7 @@ @dataclass class CurrentMostPopulousCountriesData: + """Represents a data row from the respective table.""" idx: int country: str population: int @@ -18,6 +19,7 @@ class CurrentMostPopulousCountriesData: @dataclass class PastMostPopulousCountriesData: + """Represents a data row from the respective table.""" idx: int country: str population: int @@ -29,6 +31,7 @@ class PastMostPopulousCountriesData: @dataclass class FutureMostPopulousCountriesData: + """Represents a data row from the respective table.""" idx: int country: str population: int @@ -39,7 +42,21 @@ class FutureMostPopulousCountriesData: class MostPopulousCountries: - + """Represents the data table of most populous countries in the world. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original table. + + Notes + ----- + Check the source table in + `Most populous countries in the world `_. + """ source_path = '/population/most-populous-countries' new_column_names = ( ( @@ -98,10 +115,31 @@ def _load_data( ) def current(self) -> List[CurrentMostPopulousCountriesData]: + """Get a list of all the current data from the table. + + These data are related to the current year. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data[CurrentMostPopulousCountriesData._table_position]) # type: ignore def past(self) -> List[PastMostPopulousCountriesData]: + """Get a list of all historical data from the table. + + These data pertain to the year 1950. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data[PastMostPopulousCountriesData._table_position]) # type: ignore def future(self) -> List[FutureMostPopulousCountriesData]: + """Get a list of all future data from the table. + + These data are an estimate for the year 2050. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data[FutureMostPopulousCountriesData._table_position]) # type: ignore From a30673bb701f1e525280c15cca68427aa5f72d8c Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 7 Oct 2023 04:52:32 -0300 Subject: [PATCH 086/147] docs: add docstrings to WorldPopulationProjections and related classes --- worldometer/world/population/projections.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/worldometer/world/population/projections.py b/worldometer/world/population/projections.py index 0bdddd6..d83089e 100644 --- a/worldometer/world/population/projections.py +++ b/worldometer/world/population/projections.py @@ -7,6 +7,7 @@ @dataclass class WorldPopulationProjectionsData: + """Represents a data row from the respective table.""" year: int world_population: int yearly_change: str @@ -17,7 +18,21 @@ class WorldPopulationProjectionsData: class WorldPopulationProjections: + """Represents the data table of the world population projections. + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original table. + + Notes + ----- + Check the source table in + `World Population Projections `_. + """ source_path = '/world-population/world-population-projections' new_column_names = ( 'year', @@ -44,4 +59,9 @@ def _load_data(self) -> List[WorldPopulationProjectionsData]: @property def data(self) -> List[WorldPopulationProjectionsData]: + """Get a list of all the data from the table. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data) From 84a79bd1826f62e27e03212cd100322b6b0a1426 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 7 Oct 2023 05:28:55 -0300 Subject: [PATCH 087/147] docs: add docstrings to _RegionPopulation and related classes --- worldometer/world/population/regions.py | 110 ++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/worldometer/world/population/regions.py b/worldometer/world/population/regions.py index 86f178f..b3513c7 100644 --- a/worldometer/world/population/regions.py +++ b/worldometer/world/population/regions.py @@ -7,6 +7,7 @@ @dataclass class SubregionData: + """Represents a data row from the respective table.""" area: int population: str @@ -15,6 +16,7 @@ class SubregionData: @dataclass class HistoricalData: + """Represents a data row from the respective table.""" year: int population: int yearly_change_percent: str @@ -34,6 +36,7 @@ class HistoricalData: @dataclass class ForecastData: + """Represents a data row from the respective table.""" year: int population: int yearly_change_percent: str @@ -125,44 +128,151 @@ def _load_data( ) def live(self) -> Union[int, float, None]: + """Get a live population counter for the respective region.""" rts_counters = get_rts_counters_object(path_url=self.source_path) return rts_counters.get(self._key_rts_counters) def subregions(self) -> List[SubregionData]: + """Get a list of all the subregions' data from the table. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data[SubregionData._table_position]) # type: ignore def historical(self) -> List[HistoricalData]: + """Get a list of all historical data from the table. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data[HistoricalData._table_position]) # type: ignore def forecast(self) -> List[ForecastData]: + """Get a list of all forecast data from the table. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data[ForecastData._table_position]) # type: ignore class AsiaPopulation(_RegionPopulation): + """Represents the data tables of Asia's populations. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original tables. + + Notes + ----- + Check the source tables in + `Asia Population `_. + """ _key_rts_counters = 'asia-population' source_path = '/world-population/asia-population' class AfricaPopulation(_RegionPopulation): + """Represents the data tables of Africa's populations. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original tables. + + Notes + ----- + Check the source tables in + `Africa Population `_. + """ _key_rts_counters = 'africa-population' source_path = '/world-population/africa-population' class EuropePopulation(_RegionPopulation): + """Represents the data tables of Europe's populations. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original tables. + + Notes + ----- + Check the source tables in + `Europe Population `_. + """ _key_rts_counters = 'europe-population' source_path = '/world-population/europe-population' class LatinAmericanAndTheCaribbeanPopulation(_RegionPopulation): + """Represents the data tables of Latin American and Caribbean populations. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original tables. + + Notes + ----- + Check the source tables in + `Latin America and the Caribbean + Population `_. + """ _key_rts_counters = 'latin-america-and-the-caribbean-population' source_path = '/world-population/latin-america-and-the-caribbean-population' class NorthernAmericanPopulation(_RegionPopulation): + """Represents the data tables of Northern American populations. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original tables. + + Notes + ----- + Check the source tables in + `Northern American Population `_. + """ _key_rts_counters = 'northern-america-population' source_path = '/world-population/northern-america-population' class OceaniaPopulation(_RegionPopulation): + """Represents the data tables of the Oceania populations. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original tables. + + Notes + ----- + Check the source tables in + `Oceania Population `_. + """ _key_rts_counters = 'oceania-population' source_path = '/world-population/oceania-population' From 10b7d3ff97c7de8fd9a871fc6238ac93ff4fab15 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 7 Oct 2023 05:36:32 -0300 Subject: [PATCH 088/147] docs: add docstrings to LargestCountries and related classes --- .../world/geography/largest_countries.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/worldometer/world/geography/largest_countries.py b/worldometer/world/geography/largest_countries.py index 24a9dcd..9f7526f 100644 --- a/worldometer/world/geography/largest_countries.py +++ b/worldometer/world/geography/largest_countries.py @@ -7,6 +7,7 @@ @dataclass class LargestCountriesData: + """Represents a data row from the respective table.""" idx: int country: str total_area_km2: int @@ -19,7 +20,21 @@ class LargestCountriesData: class LargestCountries: + """Represents the data table of the largest countries in the world (by area). + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original table. + + Notes + ----- + Check the source table in the + `Largest Countries in the World `_. + """ source_path = '/geography/largest-countries-in-the-world' new_column_names = ( 'idx', @@ -48,4 +63,9 @@ def _load_data(self) -> List[LargestCountriesData]: @property def data(self) -> List[LargestCountriesData]: + """Get a list of all the data from the table. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data) From 68a898ac72c7aac26c57caa4a24aa227894db8ab Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 7 Oct 2023 06:05:13 -0300 Subject: [PATCH 089/147] docs: add docstrings to WorldCountries, _RegionCountries and related classes --- worldometer/world/geography/countries.py | 142 ++++++++++++++++++++++- 1 file changed, 141 insertions(+), 1 deletion(-) diff --git a/worldometer/world/geography/countries.py b/worldometer/world/geography/countries.py index 5d6d2c7..9bbb87f 100644 --- a/worldometer/world/geography/countries.py +++ b/worldometer/world/geography/countries.py @@ -7,6 +7,7 @@ @dataclass class WorldCountriesData: + """Represents a data row from the respective table.""" idx: int country: str population: int @@ -18,6 +19,7 @@ class WorldCountriesData: @dataclass class CountryData: + """Represents a data row from the respective table.""" idx: int country: str population: int @@ -28,6 +30,7 @@ class CountryData: @dataclass class DependencyData: + """Represents a data row from the respective table.""" idx: int territory: str population: int @@ -37,7 +40,24 @@ class DependencyData: class WorldCountries: - + """Represents the data table of a list of countries in the world. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original table. + total : int + The total number of countries in the world. + + + Notes + ----- + Check the source table in + `List of countries `_. + """ source_path = '/geography/how-many-countries-are-there-in-the-world' new_column_names = ( 'idx', @@ -64,6 +84,11 @@ def _load_data(self) -> List[WorldCountriesData]: ] def countries(self) -> List[WorldCountriesData]: + """Get a list of all the countries' data from the table. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data) @@ -114,31 +139,146 @@ def _load_data( ) def countries(self) -> List[CountryData]: + """Get a list of all the data for countries in the + region from the table. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data[CountryData._table_position]) # type: ignore def dependencies(self) -> List[DependencyData]: + """Get a list of all the data for dependencies in the + region from the table. + + Each index in the list contains an object representing + a data row of the table. + """ return deepcopy(self._data[DependencyData._table_position]) # type: ignore class AsiaCountries(_RegionCountries): + """Represents the data tables of Asia's countries. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original tables. + total : int + The total number of countries in the region. + + Notes + ----- + Check the source tables in + `Countries in Asia `_. + """ source_path = '/geography/how-many-countries-in-asia' class AfricaCountries(_RegionCountries): + """Represents the data tables of Africa's countries. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original tables. + total : int + The total number of countries in the region. + + Notes + ----- + Check the source tables in + `Countries in Africa `_. + """ source_path = '/geography/how-many-countries-in-africa' class EuropeCountries(_RegionCountries): + """Represents the data tables of Europe's countries. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original tables. + total : int + The total number of countries in the region. + + Notes + ----- + Check the source tables in + `Countries in Europe `_. + """ source_path = '/geography/how-many-countries-in-europe' class LatinAmericanAndTheCaribbeanCountries(_RegionCountries): + """Represents the data tables of Latin American And The Caribbean countries. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original tables. + total : int + The total number of countries in the region. + + Notes + ----- + Check the source tables in + `Countries in Latin American And The + Caribbean `_. + """ source_path = '/geography/how-many-countries-in-latin-america' class NorthernAmericanCountries(_RegionCountries): + """Represents the data tables of Northern American countries. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original tables. + total : int + The total number of countries in the region. + + Notes + ----- + Check the source tables in + `Countries in Northern American `_. + """ source_path = '/geography/how-many-countries-in-northern-america' class OceaniaCountries(_RegionCountries): + """Represents the data tables of the Oceania countries. + + Attributes + ---------- + source_path : str + The data source path. + new_column_names : tuple + The new column names that will be used to replace those + of the original tables. + total : int + The total number of countries in the region. + + Notes + ----- + Check the source tables in + `Countries in Oceania `_. + """ source_path = '/geography/how-many-countries-in-oceania' From deb3373bf5dcd65c50c920726f27e5e497d38435 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 8 Oct 2023 01:34:53 -0300 Subject: [PATCH 090/147] docs: add docstrings to world api --- worldometer/world/__init__.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/worldometer/world/__init__.py b/worldometer/world/__init__.py index ba1426f..8c2fe42 100644 --- a/worldometer/world/__init__.py +++ b/worldometer/world/__init__.py @@ -1,3 +1,13 @@ +""" +world +----- + +`world` is the main API of the `worldometer` package, +where you can access various live counters and data +available on the https://www.worldometers.info website +through self-descriptive classes, methods, and attributes. +""" + __all__ = [ 'geography', 'population', From 25dbb082ece7fb8b7f79c42e43087d84608baed2 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 8 Oct 2023 01:56:11 -0300 Subject: [PATCH 091/147] docs: add docstrings to population api --- worldometer/world/population/__init__.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/worldometer/world/population/__init__.py b/worldometer/world/population/__init__.py index da335d4..b3c6e3b 100644 --- a/worldometer/world/population/__init__.py +++ b/worldometer/world/population/__init__.py @@ -1,3 +1,17 @@ +""" +population +---------- + +The `population` package provides access to various data related +to world populations, regions, and their countries. Additionally, +it includes historical data ranging from 1950 to the present day +and future projections extending to 2050. + +To understand the significance of each of these data sets, +their sources, and any other related information, +please visit the official page at https://www.worldometers.info/population +""" + __all__ = [ 'CountriesByPopulation', 'LargestCities', From f8e2ab9eab344009ebab837409137f01a92b13ff Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 8 Oct 2023 02:06:11 -0300 Subject: [PATCH 092/147] docs: add docstrings to geography api --- worldometer/world/geography/__init__.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/worldometer/world/geography/__init__.py b/worldometer/world/geography/__init__.py index 8027de3..5b049e4 100644 --- a/worldometer/world/geography/__init__.py +++ b/worldometer/world/geography/__init__.py @@ -1,3 +1,15 @@ +""" +geography +--------- + +The `geography` package provides access to various data related +to geographic information about the world, regions, and their countries. + +To understand the significance of each of these data sets, +their sources, and any other related information, +please visit the official page at https://www.worldometers.info/geography/how-many-countries-are-there-in-the-world +""" + __all__ = [ 'LargestCountries', 'WorldCountries', From f59ea88db140cac1210a5c830cbc690e41b09656 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 8 Oct 2023 02:09:37 -0300 Subject: [PATCH 093/147] docs: mention 'package' in all titles --- worldometer/world/__init__.py | 4 ++-- worldometer/world/geography/__init__.py | 4 ++-- worldometer/world/population/__init__.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/worldometer/world/__init__.py b/worldometer/world/__init__.py index 8c2fe42..670fa16 100644 --- a/worldometer/world/__init__.py +++ b/worldometer/world/__init__.py @@ -1,6 +1,6 @@ """ -world ------ +world package +------------- `world` is the main API of the `worldometer` package, where you can access various live counters and data diff --git a/worldometer/world/geography/__init__.py b/worldometer/world/geography/__init__.py index 5b049e4..da75559 100644 --- a/worldometer/world/geography/__init__.py +++ b/worldometer/world/geography/__init__.py @@ -1,6 +1,6 @@ """ -geography ---------- +geography package +----------------- The `geography` package provides access to various data related to geographic information about the world, regions, and their countries. diff --git a/worldometer/world/population/__init__.py b/worldometer/world/population/__init__.py index b3c6e3b..9f44edb 100644 --- a/worldometer/world/population/__init__.py +++ b/worldometer/world/population/__init__.py @@ -1,6 +1,6 @@ """ -population ----------- +population package +------------------ The `population` package provides access to various data related to world populations, regions, and their countries. Additionally, From 6e57a13dafb881d2f6c26cad1b17590ff6ee8661 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 8 Oct 2023 03:17:04 -0300 Subject: [PATCH 094/147] docs: rewrite worldometer package docstrings --- worldometer/__init__.py | 82 ++++++++++++----------------------------- 1 file changed, 24 insertions(+), 58 deletions(-) diff --git a/worldometer/__init__.py b/worldometer/__init__.py index 8eba56a..9d8207b 100644 --- a/worldometer/__init__.py +++ b/worldometer/__init__.py @@ -1,78 +1,44 @@ -# -*- coding: utf-8 -*- - """ -worldometer module ------------------- +worldometer package +------------------- -Get metrics from around the world in multiple categories. +The `worldometer` package accesses various counters and live data available +throughout the https://www.worldometers.info website and provides them +through self-describing classes, methods and attributes. Examples -------- -You can use the simplified API to collect the data: - ->>> import worldometer +Get the data from the live counters available on the homepage: ->>> worldometer.current_world_population() -{'current_world_population': 7845085923} +>>> from worldometer.world import WorldCounters ->>> worldometer.tweets_sent_today() -{'tweets_sent_today': 4539558} +>>> wc = WorldCounters() ->>> worldometer.get_metric_of(label='computers_produced_this_year') -{'computers_produced_this_year': 27760858} +>>> wc.world_population.current_population +8065299074 -Or using Worldometer Class: +>>> wc.government_and_economics.computers_produced_this_year +180248430 ->>> from worldometer import Worldometer ->>> w = Worldometer() +>>> wc.society_and_media.internet_users_in_the_world_today +5895566559 ->>> w.what_is_here() -{'categories': 8, 'labels': 63, 'metrics': 63} +Reload data to get the latest: ->>> w.categories() -[ - 'world_population', - 'government_and_economics', - 'society_and_media', - ... -] +>>> wc.reload_data() +>>> wc.world_population.current_population +8065300592 ->>> w.metrics_labels() -[ - 'current_world_population', - 'births_this_year', - 'births_today', - 'deaths_this_year', - 'deaths_today', - 'net_population_growth_this_year', - ... -] +Get help and view information about mapped sections: ->>> w.metrics() -[ - 7845087963, - 15741371, - 5676, - 6608605, - 2383, - 9132766, - ... -] +>>> help(wc) ->>> w.metrics_with_labels() -{ - 'abortions_this_year': 4785492, - 'bicycles_produced_this_year': 17070566, - 'births_this_year': 15741371, - 'births_today': 5676, - 'blog_posts_written_today': 110171, - 'cars_produced_this_year': 8999185, - 'cellular_phones_sold_today': 98846, - ...: ... -} +Notes +----- +Check https://www.worldometers.info/about for more information about +the data source, how live counters work, and more related information. """ - __all__ = [ 'core', 'api' From c7bec226265ef2f104c95eb3ce1d3860244e274e Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 18 Oct 2023 03:13:57 -0300 Subject: [PATCH 095/147] docs: update README.md file --- README.md | 165 ++++++++++++++++++++++-------------------------------- 1 file changed, 66 insertions(+), 99 deletions(-) diff --git a/README.md b/README.md index cc6ad60..c49c6eb 100644 --- a/README.md +++ b/README.md @@ -4,156 +4,123 @@

+ Metadata +
- PyPI - Status + PyPI - Version - - PyPI + + License MIT - - GitHub release (latest by date) + + Total Downloads + +

+ +

+ Status +
+ + PyPI - Status Documentation Status - - License MIT -

-# Index +## Index - [About](#about) - [worldometers.info](#worldometersinfo) - - [How it works?](#how-it-works) + - [Sources](#sources) - [Install](#install) - [Demo](#demo) - [Contributions](#contributions) - [License](#license) -# About - -[Worldometer](https://github.com/matheusfelipeog/worldometer) is a python module that collects data from [worldometers.info](https://www.worldometers.info/) and provides a simple and self-explanatory interface for using the data. +## About -## worldometers.info +The [`worldometer`](https://github.com/matheusfelipeog/worldometer) package accesses various counters and live data available throughout the [worldometers.info](https://www.worldometers.info/) website and provides them through simple and self-describing classes, methods and attributes. -> Worldometer is run by an international team of developers, researchers, and volunteers with the goal of making world statistics available in a thought-provoking and time relevant format to a wide audience around the world. It is published by a small and independent digital media company based in the United States. We have no political, governmental, or corporate affiliation. Furthermore, we have no investors, donors, grants, or backers of any type. We are completely independent and self-financed through automated programmatic advertising sold in real time on multiple ad exchanges. +Access data on: -More info: [worldometers.info/about](https://www.worldometers.info/about/) +- The world 🌍 +- Population 👥 +- Geography 🗺️ +- Projections 🔮 +- Historical 📜 -## How it works? +### worldometers.info -> **[Adapted]:** For the data, is elaborate instead a real-time estimate through a proprietary algorithm which processes the latest data and projections provided by the most reputable organizations and statistical offices in the world. +> Worldometer is run by an international team of developers, researchers, and volunteers with the goal of making world statistics available in a thought-provoking and time relevant format to a wide audience around the world. It is published by a small and independent digital media company based in the United States. We have no political, governmental, or corporate affiliation. Furthermore, we have no investors, donors, grants, or backers of any type. We are completely independent and self-financed through automated programmatic advertising sold in real time on multiple ad exchanges. -More info about data source: [worldometers.info/sources](https://www.worldometers.info/sources/) +

+ worldometers.info/about +

+### Sources -# Install +> **[adapted]:** worldometers.info collects its statistics and data from the most reputable national and international organizations, including the United Nations, the World Health Organization, the Food and Agriculture Organization, OECD and others. +> +> Each Worldometer counter has its specific set of sources, which are listed on its dedicated page (accessible by clicking on the counter text link, when available). +> +> Data, estimates, and projections displayed on worldometers.info counters are for the most part provided by organizations included in the following list of United Nations Statistics Division's partners. -First, create a directory and enter it: +

+ worldometers.info/sources +

-```bash -$ mkdir my_project && cd my_project -``` -Create a virtual environment to avoid breaking dependence on other projects. +## Install -This project uses [`pipenv`](https://pipenv.pypa.io/en/latest/), it already does it alone ;) +Use `pip` to install the worldometer package: ```bash -$ pipenv install worldometer +$ pip install worldometer ``` -But you can use `virtualenv` + `pip` if you prefer: +## Demo -```bash -$ virtualenv venv && source venv/Scripts/activate -``` +> [!NOTE] +> The first time you run any function/method or class, it will download Chromium to `~/.local/share/pyppeteer` directory. It only happens once. After, it will only open the chromium to render the contents of worldometers.info. -Now install: +Get the data from the live counters available on the [homepage](https://www.worldometers.info/): -```bash -$ pip install worldometer -``` +```python +>>> from worldometer.world import WorldCounters +>>> wc = WorldCounters() -# Demo +>>> wc.world_population.current_population +8065299074 -*The first time you run any function/method or class, it will download Chromium to its home directory (for example, `~/.pyppeteer/`). It only happens once.* +>>> wc.government_and_economics.computers_produced_this_year +180248430 -*After, it will only open the chromium to render the contents of worldometers.* +>>> wc.society_and_media.internet_users_in_the_world_today +5895566559 +``` -**Simple API usage:** +Reload data to get the latest: ```python ->>> import worldometer - ->>> worldometer.current_world_population() -{'current_world_population': 7845085923} - ->>> worldometer.tweets_sent_today() -{'tweets_sent_today': 4539558} - ->>> worldometer.get_metric_of(label='computers_produced_this_year') -{'computers_produced_this_year': 27760858} +>>> wc.reload_data() +>>> wc.world_population.current_population +8065300592 ``` -**Or complete use with Worldometer Class:** +Get help and view information about mapped sections: ```python ->>> from worldometer import Worldometer ->>> w = Worldometer() - ->>> w.what_is_here() -{'categories': 8, 'labels': 63, 'metrics': 63} - ->>> w.categories() -[ - 'world_population', - 'government_and_economics', - 'society_and_media', - ... # compressed -] - ->>> w.metrics_labels() -[ - 'current_world_population', - 'births_this_year', - 'births_today', - 'deaths_this_year', - 'deaths_today', - 'net_population_growth_this_year', - ... # compressed -] - ->>> w.metrics() -[ - 7845087963, - 15741371, - 5676, - 6608605, - 2383, - 9132766, - ... # compressed -] - ->>> w.metrics_with_labels() -{ - 'abortions_this_year': 4785492, - 'bicycles_produced_this_year': 17070566, - 'births_this_year': 15741371, - 'births_today': 5676, - 'blog_posts_written_today': 110171, - 'cars_produced_this_year': 8999185, - 'cellular_phones_sold_today': 98846, - ...: ... # compressed -} +>>> help(wc) ``` +See the documentation at [worldometer.readthedocs.io](worldometer.readthedocs.io/) + -# Contributions +## Contributions All contributions are welcome! @@ -164,6 +131,6 @@ Do you have a solution to the problem? [Send me a PR](https://github.com/matheus Did you like this project? [Click on the star ⭐](https://github.com/matheusfelipeog/worldometer/stargazers) -# License +## License This project is using the MIT license, see in [MIT LICENSE](https://github.com/matheusfelipeog/worldometer/blob/master/LICENSE). From 5d6b66f31a981dbefd83e5d624300627cbad69d5 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 18 Oct 2023 03:24:01 -0300 Subject: [PATCH 096/147] docs: use italic text in notes --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c49c6eb..a1bd4c8 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ $ pip install worldometer ## Demo > [!NOTE] -> The first time you run any function/method or class, it will download Chromium to `~/.local/share/pyppeteer` directory. It only happens once. After, it will only open the chromium to render the contents of worldometers.info. +> *The first time you run any function/method or class, it will download Chromium to `~/.local/share/pyppeteer` directory. It only happens once. After, it will only open the chromium to render the contents of worldometers.info.* Get the data from the live counters available on the [homepage](https://www.worldometers.info/): From c710d9281068e52ff664a61e1930b1847df8eb3a Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 18 Oct 2023 03:25:47 -0300 Subject: [PATCH 097/147] docs: fix documentation link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a1bd4c8..db2f1a7 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ Get help and view information about mapped sections: >>> help(wc) ``` -See the documentation at [worldometer.readthedocs.io](worldometer.readthedocs.io/) +See the documentation at [worldometer.readthedocs.io](https://worldometer.readthedocs.io/) ## Contributions From 8a39017e3def558ffbca6ee663d152ea9cc1f23a Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 18 Oct 2023 05:13:36 -0300 Subject: [PATCH 098/147] docs: use new worldometer logo --- .github/assets/images/worldometer.png | Bin 13110 -> 72192 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/.github/assets/images/worldometer.png b/.github/assets/images/worldometer.png index 89bd3bc75d2ad1e7f0bfc2233e6890c8ab27543f..88203b5212472559894830f8da8e7b1f4c701f95 100644 GIT binary patch literal 72192 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 literal 13110 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%0AnRW-Rz}Olq^Hc>9qz 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 Date: Wed, 18 Oct 2023 15:12:08 -0300 Subject: [PATCH 099/147] chore: use sphinx and pytest latest --- Pipfile | 4 +- Pipfile.lock | 686 +++++++++++++++++++++++++-------------------------- 2 files changed, 343 insertions(+), 347 deletions(-) diff --git a/Pipfile b/Pipfile index a3a6b97..34e8d7c 100644 --- a/Pipfile +++ b/Pipfile @@ -9,6 +9,6 @@ pandas = "*" html5lib = "*" [dev-packages] -pylint = "2.6.0" -sphinx = "3.5.0" +pylint = "*" +sphinx = "*" pytest = "*" diff --git a/Pipfile.lock b/Pipfile.lock index 5ba714e..cc1061e 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "f3279bba3bd0a3343d0e16c0aa19211d1d887c799bafb7cb1b45195ba9f4e628" + "sha256": "47c5034649fe3fcf79ef440e14154f3e1fe867f1bfe7432a3633f74e3906f939" }, "pipfile-spec": 6, "requires": {}, @@ -45,84 +45,99 @@ }, "charset-normalizer": { "hashes": [ - "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96", - "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c", - "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710", - "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706", - "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020", - "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252", - "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad", - "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329", - "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a", - "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f", - "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6", - "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4", - "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a", - "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46", - "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2", - "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23", - "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace", - "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd", - "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982", - "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10", - "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2", - "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea", - "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09", - "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5", - "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149", - "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489", - "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9", - "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80", - "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592", - "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3", - "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6", - "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed", - "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c", - "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200", - "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a", - "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e", - "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d", - "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6", - "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623", - "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669", - "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3", - "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa", - "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9", - "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2", - "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f", - "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1", - "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4", - "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a", - "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8", - "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3", - "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029", - "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f", - "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959", - "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22", - "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7", - "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952", - "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346", - "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e", - "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d", - "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299", - "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd", - "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a", - "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3", - "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037", - "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94", - "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c", - "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858", - "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a", - "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449", - "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c", - "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918", - "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1", - "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c", - "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac", - "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa" + "sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843", + "sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786", + "sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e", + "sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8", + "sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4", + "sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa", + "sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d", + "sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82", + "sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7", + "sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895", + "sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d", + "sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a", + "sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382", + "sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678", + "sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b", + "sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e", + "sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741", + "sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4", + "sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596", + "sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9", + "sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69", + "sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c", + "sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77", + "sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13", + "sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459", + "sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e", + "sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7", + "sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908", + "sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a", + "sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f", + "sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8", + "sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482", + "sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d", + "sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d", + "sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545", + "sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34", + "sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86", + "sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6", + "sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe", + "sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e", + "sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc", + "sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7", + "sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd", + "sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c", + "sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557", + "sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a", + "sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89", + "sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078", + "sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e", + "sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4", + "sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403", + "sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0", + "sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89", + "sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115", + "sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9", + "sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05", + "sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a", + "sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec", + "sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56", + "sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38", + "sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479", + "sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c", + "sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e", + "sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd", + "sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186", + "sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455", + "sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c", + "sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65", + "sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78", + "sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287", + "sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df", + "sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43", + "sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1", + "sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7", + "sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989", + "sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a", + "sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63", + "sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884", + "sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649", + "sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810", + "sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828", + "sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4", + "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2", + "sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd", + "sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5", + "sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe", + "sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293", + "sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e", + "sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e", + "sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8" ], "markers": "python_full_version >= '3.7.0'", - "version": "==3.2.0" + "version": "==3.3.0" }, "cssselect": { "hashes": [ @@ -134,10 +149,10 @@ }, "fake-useragent": { "hashes": [ - "sha256:ad2b5414d19493d0789572f04200d4f656f84d20b205cc805233212957fe385d", - "sha256:b411f903331f695e3840ccadcf011f745a405764e97c588f2b8fde9e400a5446" + "sha256:0b3a223b4c03e3df46b0e9ff53ad26cf4690f68871396b9c59a7fa6ee830c395", + "sha256:73cee1d10bcd1deb25a15e916f6674c537d2d9088ecb4d7af98c2619f83827d1" ], - "version": "==1.2.1" + "version": "==1.3.0" }, "html5lib": { "hashes": [ @@ -264,60 +279,73 @@ }, "numpy": { "hashes": [ - "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2", - "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55", - "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf", - "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01", - "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca", - "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901", - "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d", - "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4", - "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf", - "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380", - "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044", - "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545", - "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f", - "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f", - "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3", - "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364", - "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9", - "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418", - "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f", - "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295", - "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3", - "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187", - "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926", - "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357", - "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760" - ], - "markers": "python_version < '3.11'", - "version": "==1.25.2" + "sha256:06934e1a22c54636a059215d6da99e23286424f316fddd979f5071093b648668", + "sha256:1c59c046c31a43310ad0199d6299e59f57a289e22f0f36951ced1c9eac3665b9", + "sha256:1d1bd82d539607951cac963388534da3b7ea0e18b149a53cf883d8f699178c0f", + "sha256:1e11668d6f756ca5ef534b5be8653d16c5352cbb210a5c2a79ff288e937010d5", + "sha256:3649d566e2fc067597125428db15d60eb42a4e0897fc48d28cb75dc2e0454e53", + "sha256:59227c981d43425ca5e5c01094d59eb14e8772ce6975d4b2fc1e106a833d5ae2", + "sha256:6081aed64714a18c72b168a9276095ef9155dd7888b9e74b5987808f0dd0a974", + "sha256:6965888d65d2848e8768824ca8288db0a81263c1efccec881cb35a0d805fcd2f", + "sha256:76ff661a867d9272cd2a99eed002470f46dbe0943a5ffd140f49be84f68ffc42", + "sha256:78ca54b2f9daffa5f323f34cdf21e1d9779a54073f0018a3094ab907938331a2", + "sha256:82e871307a6331b5f09efda3c22e03c095d957f04bf6bc1804f30048d0e5e7af", + "sha256:8ab9163ca8aeb7fd32fe93866490654d2f7dda4e61bc6297bf72ce07fdc02f67", + "sha256:9696aa2e35cc41e398a6d42d147cf326f8f9d81befcb399bc1ed7ffea339b64e", + "sha256:97e5d6a9f0702c2863aaabf19f0d1b6c2628fbe476438ce0b5ce06e83085064c", + "sha256:9f42284ebf91bdf32fafac29d29d4c07e5e9d1af862ea73686581773ef9e73a7", + "sha256:a03fb25610ef560a6201ff06df4f8105292ba56e7cdd196ea350d123fc32e24e", + "sha256:a5b411040beead47a228bde3b2241100454a6abde9df139ed087bd73fc0a4908", + "sha256:af22f3d8e228d84d1c0c44c1fbdeb80f97a15a0abe4f080960393a00db733b66", + "sha256:afd5ced4e5a96dac6725daeb5242a35494243f2239244fad10a90ce58b071d24", + "sha256:b9d45d1dbb9de84894cc50efece5b09939752a2d75aab3a8b0cef6f3a35ecd6b", + "sha256:bb894accfd16b867d8643fc2ba6c8617c78ba2828051e9a69511644ce86ce83e", + "sha256:c8c6c72d4a9f831f328efb1312642a1cafafaa88981d9ab76368d50d07d93cbe", + "sha256:cd7837b2b734ca72959a1caf3309457a318c934abef7a43a14bb984e574bbb9a", + "sha256:cdd9ec98f0063d93baeb01aad472a1a0840dee302842a2746a7a8e92968f9575", + "sha256:d1cfc92db6af1fd37a7bb58e55c8383b4aa1ba23d012bdbba26b4bcca45ac297", + "sha256:d1d2c6b7dd618c41e202c59c1413ef9b2c8e8a15f5039e344af64195459e3104", + "sha256:d2984cb6caaf05294b8466966627e80bf6c7afd273279077679cb010acb0e5ab", + "sha256:d58e8c51a7cf43090d124d5073bc29ab2755822181fcad978b12e144e5e5a4b3", + "sha256:d78f269e0c4fd365fc2992c00353e4530d274ba68f15e968d8bc3c69ce5f5244", + "sha256:dcfaf015b79d1f9f9c9fd0731a907407dc3e45769262d657d754c3a028586124", + "sha256:e44ccb93f30c75dfc0c3aa3ce38f33486a75ec9abadabd4e59f114994a9c4617", + "sha256:e509cbc488c735b43b5ffea175235cec24bbc57b227ef1acc691725beb230d1c" + ], + "markers": "python_version == '3.11'", + "version": "==1.26.1" }, "pandas": { "hashes": [ - "sha256:0164b85937707ec7f70b34a6c3a578dbf0f50787f910f21ca3b26a7fd3363437", - "sha256:28f330845ad21c11db51e02d8d69acc9035edfd1116926ff7245c7215db57957", - "sha256:38f74ef7ebc0ffb43b3d633e23d74882bce7e27bfa09607f3c5d3e03ffd9a4a5", - "sha256:40dd20439ff94f1b2ed55b393ecee9cb6f3b08104c2c40b0cb7186a2f0046242", - "sha256:629124923bcf798965b054a540f9ccdfd60f71361255c81fa1ecd94a904b9dd3", - "sha256:62c24c7fc59e42b775ce0679cfa7b14a5f9bfb7643cfbe708c960699e05fb918", - "sha256:6e6a0fe052cf27ceb29be9429428b4918f3740e37ff185658f40d8702f0b3e09", - "sha256:70cf866af3ab346a10debba8ea78077cf3a8cd14bd5e4bed3d41555a3280041c", - "sha256:86f100b3876b8c6d1a2c66207288ead435dc71041ee4aea789e55ef0e06408cb", - "sha256:9d81e1813191070440d4c7a413cb673052b3b4a984ffd86b8dd468c45742d3cc", - "sha256:b31da36d376d50a1a492efb18097b9101bdbd8b3fbb3f49006e02d4495d4c644", - "sha256:b9a6ccf0963db88f9b12df6720e55f337447aea217f426a22d71f4213a3099a6", - "sha256:cda72cc8c4761c8f1d97b169661f23a86b16fdb240bdc341173aee17e4d6cedd", - "sha256:d4f38e4fedeba580285eaac7ede4f686c6701a9e618d8a857b138a126d067f2f", - "sha256:d53c8c1001f6a192ff1de1efe03b31a423d0eee2e9e855e69d004308e046e694", - "sha256:d8c58b1113892e0c8078f006a167cc210a92bdae23322bb4614f2f0b7a4b510f", - "sha256:d97daeac0db8c993420b10da4f5f5b39b01fc9ca689a17844e07c0a35ac96b4b", - "sha256:d99e678180bc59b0c9443314297bddce4ad35727a1a2656dbe585fd78710b3b9", - "sha256:eb20252720b1cc1b7d0b2879ffc7e0542dd568f24d7c4b2347cb035206936421" + "sha256:02304e11582c5d090e5a52aec726f31fe3f42895d6bfc1f28738f9b64b6f0614", + "sha256:0489b0e6aa3d907e909aef92975edae89b1ee1654db5eafb9be633b0124abe97", + "sha256:05674536bd477af36aa2effd4ec8f71b92234ce0cc174de34fd21e2ee99adbc2", + "sha256:25e8474a8eb258e391e30c288eecec565bfed3e026f312b0cbd709a63906b6f8", + "sha256:29deb61de5a8a93bdd033df328441a79fcf8dd3c12d5ed0b41a395eef9cd76f0", + "sha256:366da7b0e540d1b908886d4feb3d951f2f1e572e655c1160f5fde28ad4abb750", + "sha256:3bcad1e6fb34b727b016775bea407311f7721db87e5b409e6542f4546a4951ea", + "sha256:4c3f32fd7c4dccd035f71734df39231ac1a6ff95e8bdab8d891167197b7018d2", + "sha256:4cdb0fab0400c2cb46dafcf1a0fe084c8bb2480a1fa8d81e19d15e12e6d4ded2", + "sha256:4f99bebf19b7e03cf80a4e770a3e65eee9dd4e2679039f542d7c1ace7b7b1daa", + "sha256:58d997dbee0d4b64f3cb881a24f918b5f25dd64ddf31f467bb9b67ae4c63a1e4", + "sha256:75ce97667d06d69396d72be074f0556698c7f662029322027c226fd7a26965cb", + "sha256:84e7e910096416adec68075dc87b986ff202920fb8704e6d9c8c9897fe7332d6", + "sha256:9e2959720b70e106bb1d8b6eadd8ecd7c8e99ccdbe03ee03260877184bb2877d", + "sha256:9e50e72b667415a816ac27dfcfe686dc5a0b02202e06196b943d54c4f9c7693e", + "sha256:a0dbfea0dd3901ad4ce2306575c54348d98499c95be01b8d885a2737fe4d7a98", + "sha256:b407381258a667df49d58a1b637be33e514b07f9285feb27769cedb3ab3d0b3a", + "sha256:b8bd1685556f3374520466998929bade3076aeae77c3e67ada5ed2b90b4de7f0", + "sha256:c1f84c144dee086fe4f04a472b5cd51e680f061adf75c1ae4fc3a9275560f8f4", + "sha256:c747793c4e9dcece7bb20156179529898abf505fe32cb40c4052107a3c620b49", + "sha256:cc1ab6a25da197f03ebe6d8fa17273126120874386b4ac11c1d687df288542dd", + "sha256:dc3657869c7902810f32bd072f0740487f9e030c1a3ab03e0af093db35a9d14e", + "sha256:f5ec7740f9ccb90aec64edd71434711f58ee0ea7f5ed4ac48be11cfa9abf7317", + "sha256:fecb198dc389429be557cde50a2d46da8434a17fe37d7d41ff102e3987fd947b", + "sha256:ffa8f0966de2c22de408d0e322db2faed6f6e74265aa0856f3824813cf124363" ], "index": "pypi", "markers": "python_version >= '3.9'", - "version": "==2.1.0" + "version": "==2.1.1" }, "parse": { "hashes": [ @@ -353,15 +381,15 @@ "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==2.8.2" }, "pytz": { "hashes": [ - "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588", - "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb" + "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b", + "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7" ], - "version": "==2023.3" + "version": "==2023.3.post1" }, "requests": { "hashes": [ @@ -385,16 +413,16 @@ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", "version": "==1.16.0" }, "soupsieve": { "hashes": [ - "sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8", - "sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea" + "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690", + "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7" ], - "markers": "python_version >= '3.7'", - "version": "==2.4.1" + "markers": "python_version >= '3.8'", + "version": "==2.5" }, "tqdm": { "hashes": [ @@ -414,11 +442,11 @@ }, "urllib3": { "hashes": [ - "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f", - "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14" + "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07", + "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.16" + "version": "==1.26.18" }, "w3lib": { "hashes": [ @@ -512,11 +540,11 @@ }, "zipp": { "hashes": [ - "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0", - "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147" + "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31", + "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0" ], "markers": "python_version >= '3.8'", - "version": "==3.16.2" + "version": "==3.17.0" } }, "develop": { @@ -530,19 +558,19 @@ }, "astroid": { "hashes": [ - "sha256:87ae7f2398b8a0ae5638ddecf9987f081b756e0e9fc071aeebdca525671fc4dc", - "sha256:b31c92f545517dcc452f284bc9c044050862fbe6d93d2b3de4a215a6b384bf0d" + "sha256:7d5895c9825e18079c5aeac0572bc2e4c83205c95d416e0b4fee8bc361d2d9ca", + "sha256:86b0bb7d7da0be1a7c4aedb7974e391b32d4ed89e33de6ed6902b4b15c97577e" ], - "markers": "python_version >= '3.6'", - "version": "==2.5" + "markers": "python_full_version >= '3.8.0'", + "version": "==3.0.1" }, "babel": { "hashes": [ - "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610", - "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455" + "sha256:04c3e2d28d2b7681644508f836be388ae49e0cfe91465095340395b60d00f210", + "sha256:fbfcae1575ff78e26c7449136f1abbefc3c13ce542eeb13d43d50d8b047216ec" ], "markers": "python_version >= '3.7'", - "version": "==2.12.1" + "version": "==2.13.0" }, "certifi": { "hashes": [ @@ -554,84 +582,107 @@ }, "charset-normalizer": { "hashes": [ - "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96", - "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c", - "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710", - "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706", - "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020", - "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252", - "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad", - "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329", - "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a", - "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f", - "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6", - "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4", - "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a", - "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46", - "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2", - "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23", - "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace", - "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd", - "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982", - "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10", - "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2", - "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea", - "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09", - "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5", - "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149", - "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489", - "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9", - "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80", - "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592", - "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3", - "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6", - "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed", - "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c", - "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200", - "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a", - "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e", - "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d", - "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6", - "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623", - "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669", - "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3", - "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa", - "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9", - "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2", - "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f", - "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1", - "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4", - "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a", - "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8", - "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3", - "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029", - "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f", - "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959", - "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22", - "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7", - "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952", - "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346", - "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e", - "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d", - "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299", - "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd", - "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a", - "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3", - "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037", - "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94", - "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c", - "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858", - "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a", - "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449", - "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c", - "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918", - "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1", - "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c", - "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac", - "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa" + "sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843", + "sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786", + "sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e", + "sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8", + "sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4", + "sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa", + "sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d", + "sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82", + "sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7", + "sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895", + "sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d", + "sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a", + "sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382", + "sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678", + "sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b", + "sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e", + "sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741", + "sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4", + "sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596", + "sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9", + "sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69", + "sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c", + "sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77", + "sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13", + "sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459", + "sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e", + "sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7", + "sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908", + "sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a", + "sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f", + "sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8", + "sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482", + "sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d", + "sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d", + "sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545", + "sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34", + "sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86", + "sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6", + "sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe", + "sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e", + "sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc", + "sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7", + "sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd", + "sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c", + "sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557", + "sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a", + "sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89", + "sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078", + "sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e", + "sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4", + "sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403", + "sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0", + "sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89", + "sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115", + "sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9", + "sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05", + "sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a", + "sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec", + "sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56", + "sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38", + "sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479", + "sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c", + "sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e", + "sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd", + "sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186", + "sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455", + "sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c", + "sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65", + "sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78", + "sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287", + "sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df", + "sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43", + "sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1", + "sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7", + "sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989", + "sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a", + "sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63", + "sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884", + "sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649", + "sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810", + "sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828", + "sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4", + "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2", + "sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd", + "sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5", + "sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe", + "sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293", + "sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e", + "sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e", + "sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8" ], "markers": "python_full_version >= '3.7.0'", - "version": "==3.2.0" + "version": "==3.3.0" + }, + "dill": { + "hashes": [ + "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e", + "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03" + ], + "markers": "python_version >= '3.11'", + "version": "==0.3.7" }, "docutils": { "hashes": [ @@ -641,14 +692,6 @@ "markers": "python_version >= '3.7'", "version": "==0.20.1" }, - "exceptiongroup": { - "hashes": [ - "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9", - "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3" - ], - "markers": "python_version < '3.11'", - "version": "==1.1.3" - }, "idna": { "hashes": [ "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", @@ -689,56 +732,17 @@ "markers": "python_version >= '3.7'", "version": "==3.1.2" }, - "lazy-object-proxy": { - "hashes": [ - "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382", - "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82", - "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9", - "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494", - "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46", - "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30", - "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63", - "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4", - "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae", - "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be", - "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701", - "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd", - "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006", - "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a", - "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586", - "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8", - "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821", - "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07", - "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b", - "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171", - "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b", - "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2", - "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7", - "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4", - "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8", - "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e", - "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f", - "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda", - "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4", - "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e", - "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671", - "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11", - "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455", - "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734", - "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb", - "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59" - ], - "markers": "python_version >= '3.7'", - "version": "==1.9.0" - }, "markupsafe": { "hashes": [ "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e", "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", + "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c", "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", + "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb", + "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939", "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", @@ -746,6 +750,7 @@ "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", + "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd", "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", @@ -754,6 +759,7 @@ "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", + "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007", "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", @@ -761,9 +767,12 @@ "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", + "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1", "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", + "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c", "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", + "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823", "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", @@ -782,26 +791,36 @@ "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", - "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2" + "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc", + "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2", + "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11" ], "markers": "python_version >= '3.7'", "version": "==2.1.3" }, "mccabe": { "hashes": [ - "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", - "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f" + "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", + "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" ], "markers": "python_version >= '3.6'", - "version": "==0.6.1" + "version": "==0.7.0" }, "packaging": { "hashes": [ - "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61", - "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f" + "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", + "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" ], "markers": "python_version >= '3.7'", - "version": "==23.1" + "version": "==23.2" + }, + "platformdirs": { + "hashes": [ + "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3", + "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e" + ], + "markers": "python_version >= '3.7'", + "version": "==3.11.0" }, "pluggy": { "hashes": [ @@ -821,21 +840,21 @@ }, "pylint": { "hashes": [ - "sha256:bb4a908c9dadbc3aac18860550e870f58e1a02c9f2c204fdf5693d73be061210", - "sha256:bfe68f020f8a0fece830a22dd4d5dddb4ecc6137db04face4c3420a46a52239f" + "sha256:81c6125637be216b4652ae50cc42b9f8208dfb725cdc7e04c48f6902f4dbdf40", + "sha256:9c90b89e2af7809a1697f6f5f93f1d0e518ac566e2ac4d2af881a69c13ad01ea" ], "index": "pypi", - "markers": "python_version >= '3.5'", - "version": "==2.6.0" + "markers": "python_full_version >= '3.8.0'", + "version": "==3.0.1" }, "pytest": { "hashes": [ - "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32", - "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a" + "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002", + "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069" ], "index": "pypi", "markers": "python_version >= '3.7'", - "version": "==7.4.0" + "version": "==7.4.2" }, "requests": { "hashes": [ @@ -845,14 +864,6 @@ "markers": "python_version >= '3.7'", "version": "==2.31.0" }, - "setuptools": { - "hashes": [ - "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d", - "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b" - ], - "markers": "python_version >= '3.8'", - "version": "==68.1.2" - }, "snowballstemmer": { "hashes": [ "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", @@ -862,36 +873,36 @@ }, "sphinx": { "hashes": [ - "sha256:68da66ca3d6b35b22bea5c53d938d5f8988663dca042f0a46429a1eba1010051", - "sha256:deb468efb3abaa70d790add4147d18782d86fdeacf648d6e8afb7a99807f1546" + "sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560", + "sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5" ], "index": "pypi", - "markers": "python_version >= '3.5'", - "version": "==3.5.0" + "markers": "python_version >= '3.9'", + "version": "==7.2.6" }, "sphinxcontrib-applehelp": { "hashes": [ - "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228", - "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e" + "sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d", + "sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa" ], - "markers": "python_version >= '3.8'", - "version": "==1.0.4" + "markers": "python_version >= '3.9'", + "version": "==1.0.7" }, "sphinxcontrib-devhelp": { "hashes": [ - "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e", - "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4" + "sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212", + "sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f" ], - "markers": "python_version >= '3.5'", - "version": "==1.0.2" + "markers": "python_version >= '3.9'", + "version": "==1.0.5" }, "sphinxcontrib-htmlhelp": { "hashes": [ - "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff", - "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903" + "sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a", + "sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9" ], - "markers": "python_version >= '3.8'", - "version": "==2.0.1" + "markers": "python_version >= '3.9'", + "version": "==2.0.4" }, "sphinxcontrib-jsmath": { "hashes": [ @@ -903,50 +914,35 @@ }, "sphinxcontrib-qthelp": { "hashes": [ - "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72", - "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6" + "sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d", + "sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4" ], - "markers": "python_version >= '3.5'", - "version": "==1.0.3" + "markers": "python_version >= '3.9'", + "version": "==1.0.6" }, "sphinxcontrib-serializinghtml": { "hashes": [ - "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd", - "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952" - ], - "markers": "python_version >= '3.5'", - "version": "==1.1.5" - }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" + "sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54", + "sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.10.2" + "markers": "python_version >= '3.9'", + "version": "==1.1.9" }, - "tomli": { + "tomlkit": { "hashes": [ - "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", - "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" + "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86", + "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899" ], - "markers": "python_version < '3.11'", - "version": "==2.0.1" + "markers": "python_version >= '3.7'", + "version": "==0.12.1" }, "urllib3": { "hashes": [ - "sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f", - "sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14" + "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07", + "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.16" - }, - "wrapt": { - "hashes": [ - "sha256:b62ffa81fb85f4332a4f609cab4ac40709470da05643a082ec1eb88e6d9b97d7" - ], - "markers": "python_version < '3.11'", - "version": "==1.12.1" + "version": "==1.26.18" } } } From 800d611327605da04ec69d01b4cdba3458665b95 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 18 Oct 2023 18:13:06 -0300 Subject: [PATCH 100/147] docs: add worldometer description --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index db2f1a7..b79ef02 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@ -

- Logo Worldometer - Scraping & API -

+

+ Logo Worldometer - Scraping & API +
+ Get live, population, geography, projected, and historical data from around the world. +

+---

Metadata From 1bacc4da018829f41d2d348fdfdc67d8d25cdf9d Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 18 Oct 2023 18:19:39 -0300 Subject: [PATCH 101/147] docs: resize worldometer logo to 800px --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b79ef02..c3bd1be 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Logo Worldometer - Scraping & API + Worldometer package logo
Get live, population, geography, projected, and historical data from around the world.

From ab25c184567c18bbf0a816f713d0d0e6d0e8d775 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 18 Oct 2023 18:36:21 -0300 Subject: [PATCH 102/147] docs: update docs config file --- docs/source/conf.py | 317 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 290 insertions(+), 27 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 061d7fe..c2e9e20 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,10 +1,14 @@ -# Configuration file for the Sphinx documentation builder. +# test documentation build configuration file, created by +# sphinx-quickstart on Sun Jun 26 00:00:43 2016. # -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- +# This file is executed through importlib.import_module with +# the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -14,11 +18,39 @@ import sys sys.path.insert(0, os.path.abspath('../..')) +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.napoleon' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The encoding of source files. +# +# source_encoding = 'utf-8-sig' -# -- Project information ----------------------------------------------------- +# The master toctree document. +root_doc = 'index' +# General information about the project. project = 'worldometer' -copyright = '2021, Matheus Felipe' +copyright = '2023, Matheus Felipe' author = 'Matheus Felipe' # The version info for the project you're documenting, acts as replacement for @@ -30,20 +62,60 @@ # The full version, including alpha/beta/rc tags. release = 'v1.0.1' -# -- General configuration --------------------------------------------------- +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +# language = None -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.napoleon' -] +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +# +# today = '' +# +# Else, today_fmt is used as the format for a strftime call. +# +# today_fmt = '%B %d, %Y' -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# These patterns also affect html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +# +# default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +# +# add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +# +# add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +# +# show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +# modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +# keep_warnings = False -# -- Options for HTML output ------------------------------------------------- +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. @@ -52,20 +124,62 @@ # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the -# documentation . +# documentation. +# html_theme_options = { - 'logo': 'worldometer.png', - 'description': 'Get current metrics in the world with this python module.', + 'touch_icon': 'worldometer-icon.png', + 'description': 'Get live, population, geography, projected, and historical data from around the world.', 'fixed_sidebar': True, 'github_user': 'matheusfelipeog', 'github_repo': 'worldometer', 'github_banner': True, 'github_button': True, 'github_type': 'star', - 'show_powered_by': False + 'show_powered_by': False, } +# Add any paths that contain custom themes here, relative to this directory. +# html_theme_path = [] + +# The name for this set of Sphinx documents. +# " v documentation" by default. +# +# html_title = 'test vtest' + +# A shorter title for the navigation bar. Default is the same as html_title. +# +# html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +# +# html_logo = './path/to/logo' + +# The name of an image file (relative to this directory) to use as a favicon of +# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +# +# html_favicon = './path/to/favicon' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +# +# html_extra_path = [] + +# If not None, a 'Last updated on:' timestamp is inserted at every page +# bottom, using the given strftime format. +# The empty string is equivalent to '%b %d, %Y'. +# +# html_last_updated_fmt = None + # Custom sidebar templates, maps document names to template names. +# html_sidebars = { 'index': [ 'about.html', @@ -84,7 +198,156 @@ ] } -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] \ No newline at end of file +# Additional templates that should be rendered to pages, maps page names to +# template names. +# +# html_additional_pages = {} + +# If false, no module index is generated. +# +# html_domain_indices = True + +# If false, no index is generated. +# +# html_use_index = True + +# If true, the index is split into individual pages for each letter. +# +# html_split_index = False + +# If true, links to the reST sources are added to the pages. +# +# html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +# +# html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +# +# html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +# +# html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +# html_file_suffix = None + +# Language to be used for generating the HTML full-text search index. +# Sphinx supports the following languages: +# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' +# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' +# +# html_search_language = 'en' + +# A dictionary with options for the search language support, empty by default. +# 'ja' uses this config value. +# 'zh' user can custom change `jieba` dictionary path. +# +# html_search_options = {'type': 'default'} + +# The name of a javascript file (relative to the configuration directory) that +# implements a search results scorer. If empty, the default will be used. +# +# html_search_scorer = 'scorer.js' + +# Output file base name for HTML help builder. +# htmlhelp_basename = 'testdoc' + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +# latex_documents = [ +# (root_doc, 'test.tex', 'test Documentation', +# 'test', 'manual'), +# ] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +# +# latex_logo = None + +# If true, show page references after internal links. +# +# latex_show_pagerefs = False + +# If true, show URL addresses after external links. +# +# latex_show_urls = False + +# Documents to append as an appendix to all manuals. +# +# latex_appendices = [] + +# If false, no module index is generated. +# +# latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +# man_pages = [ +# (root_doc, 'test', 'test Documentation', +# [author], 1) +# ] + +# If true, show URL addresses after external links. +# +# man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +# texinfo_documents = [ +# (root_doc, 'test', 'test Documentation', +# author, 'test', 'One line description of project.', +# 'Miscellaneous'), +# ] + +# Documents to append as an appendix to all manuals. +# +# texinfo_appendices = [] + +# If false, no module index is generated. +# +# texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +# +# texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +# +# texinfo_no_detailmenu = False + +# If false, do not generate in manual @ref nodes. +# +# texinfo_cross_references = False \ No newline at end of file From 82a09afd7761067acddc63fde6995fb2f497fb1d Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 18 Oct 2023 19:31:46 -0300 Subject: [PATCH 103/147] docs: update rts docs - add new images and favicon - add style.css file - hide title on homepage - update docs config file --- docs/source/_static/favicon.ico | Bin 0 -> 15406 bytes docs/source/_static/style.css | 3 +++ docs/source/_static/worldometer-icon.png | Bin 0 -> 8977 bytes docs/source/_static/worldometer.png | Bin 13110 -> 72192 bytes docs/source/conf.py | 7 +++++++ docs/source/index.rst | 12 ++++++++++-- 6 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 docs/source/_static/favicon.ico create mode 100644 docs/source/_static/style.css create mode 100644 docs/source/_static/worldometer-icon.png diff --git a/docs/source/_static/favicon.ico b/docs/source/_static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..aa370fceb51bb6d419bb4b59444565d0b808b1f3 GIT binary patch literal 15406 zcmeI3X_QpO700V*VfJA*HlxY7A&Lf&h-)I?E-q0+0whsXjA&F)L|nlIaf!GjF32Wo zL{JnJ1fqx%0XKq*OXQ=8IVUH_4@vwG&C%Taf7M-Y-n{PD^bF`H>zsS)z1LNBZ&lsB zs-4TYa@W-4RJXf{70wNF&b7B^-v=~1w@}{(56=DG-?>e_oExAv>Y^Um@2W~IL)37N zV4L8J9PrGy0|jZNRzJ*bu5n*YJj~hBGo8IL+1ZUF+Z5*?8JTj7|=mE z5Sm}p*h##jpJ=f9O}*{x$Lj6rTPp1NndQFCTbDZPRqyBG*Xn}9^ZRbTHe(IyOaJe_ z+-9rQ_l@f^5spib^fdT&UZ(X);@&W$%=e`~@bDcyI<;9b!S~;m(H^}idg%ZDRnBgh zQ)81Ksv+ z?&WO4A%hL9X!?)(-XW+HbfqxotpY#45qmjX z{EMs{1U->fBP&mhcXop0ro1d#8^&VHQp!PU^ml>vZE!Ycw6hO2W*WYQco$UIijbG~b*JZa3Ywtuu+B&dDe$9snchFnK@JxTO#?JkHz5V_- zmBxJ2+P*!-*%7-(G=Kx%N*4IUuQ_~`HdgrlC)u&KoDOW1?z?7QP0>Es=sj8^8sO`A zK~DaIEY1Dt_HjeQrs)}L-q4|g+hkv`jr_Lk)(TsBbJivWdZ{1(rMGR!D>4<|2V~Xo zGm5Qae5}b2)poKS*pG*0CuxICoFY9RZy%mdKOkBIbP5Gs^;t%9Un1Wqv@2FK&z?Ek z0p0*-$i96bTYld?Re63v7!O^MlS_0IxY3t3pigP?%{c3>@9cvF{M7UB?Cg&OyrE`& z5BhGj2IzBiwiWV~LZ4*4PJUY)XZ(5Q1I77}v8IiT@Pm6Z_)FzG`Xg^~obl(=JuiD2l^1s6Rd;VKECLcfJl!7zf20wo{#T9(JRX#Oye@AmB-r*ZMd&;yPasKo2 zH~B~T_}`SzJE#b+#qoycJ=bP^>V02qwc9ns6}o2n}s0)B9#0}Ojx$j)Cm zzce1e7W9k70sH@<#dc9V5pc%q^24L~2Ve0sY|pdj=C1)VF!OgL}mo2RI z@fzbEzM{!SY8{d|(%x$yYcW@q0Y83e(l^E@@IC^$fjAAw5pxdX9=fvG_In{+2Zna> zni#8Wzlt#TJA^A)>h;0F zDvtH>9r(eK=8s4I=Scb7o24hAVU6%H=e64F^|HO_;R*8l-nlws$Y>g$gWt!N$3?jD zZR38AUh_)ifA?3sk<39L4+lTr?0qltACD;ifX+qsLS7@xyLNGll?|*6YhH@~9f*NO zzZdAqu|u4ppM(AQKx;zIWytCl8z?y^2eVZ?GUx6pzZSL6wp!)5T65K&*TR}_Z{7iS zsM#ZU5?(dM%-)Z`_L%INkdN9T9@#QAo6lN)joEng>gm*Rts1wkCSyhpkFpOHcz<)avRC> zfMDn2HElL2CR(H%(j@uDKiDl#&$6e;2{_9HJ5qE~~7h=9Uf1H;e1lQjL69mxEol>JtlLh}0_%+8ao$-BVFI~`mn$zaDL3?t} zFlWu;D{Xk-D{xN|KucE&bB1=$>#X@cy`9~5vi!dtSno92!}s?z_Wfrl=Gmo_%tHfn zD0Ls;Irc4Dclby6`N60fiK)m34ED-p4?kWAg?!vC~e4ycV#eOF#KbMTV zh`&xyz9*b3Qxm73x~wspQy3#&b5?+{zopi$2>k3Kr;pZ6`#ZN{UGVyQqDP&sIVMIQrTrMQq|u+nhcOD(>;d@)(Fx#VAP2#J$B*^C7`(P4KEd)?6;VDV z#Ouj=fbt#7Zq1%)uorJ!m!H#3&f$H@@>NH7@|E!0TLj20zPPvD3&$4U$K<%l_oqvs zpZQFDq`oM>B**3b$??u~-X8V zyOKtKPub%OBm?9M(`YU9{Wu}wg3z}vS%dGh2KNC9*J1Eynp-|U*!PV`W>Y^^e1nBug=4vk9{R~9LL8q z`U$_AI|SSv;2ZIB&(8dV4EXsxJT8BXFedjBu$uw@j@I~bD{t1BuX5dkv@Z8+E^$5q zFaFUX^0~pqy|~vz1Nj(uB}X&52OZ?!XP%f&KR)I6cjEeUM!=bT@Rf#Y9xuo4UBa(- z>ON+;OM>ssot8U)5#{co8QmY*ub&N0w_oVXt8{LhcRx>S)1AE-E1!*XhR}ESb*-`o z75+?yb0O{}w(DE?ofPx^_v6Wp>dyOqSpAIiVdN6kpWK#pNT4$GpfCu@!f8Sts~6xgXdB z&b@Y}jezw<&m*(H(*4f(d32J-)OU?pb&bx)Ya;%~=WiAe0}u-k6WF2c+5BXD&EwDb z4jVNG&WKkC(0>QzbVR@nUoRCe^E=?rlcgik!L(=Ip>3&k-HW-iPUX@>C$SbW7qnA| z#fZtQrc(Em(=aO5bUN9^styDdkQc)%_gy zE*aOCGKZSE&6a77c!yXw#E*LPvG5$|2e_wK>|Q#1aJSCRku`v`^NlkyhK{}O?jBxe zbEdpRe!+8!XRv$dj)F2-iu}ARxgFj~?~rSV$M1UeISHTdBv-+`tF+t?^q;v{dMKwq z(5b`3Lq{o>fL&!hk%_@;n*I0gtar30@ICiJI?gi5@gTQ_3Uc7%cydPMj?&^8@_{qt zyY$uFg@B9oMXtGTzC$#JJrV6S^Tjv)%7e~ZZ>oEdm|W*-jLJ}esBArH{Y9gP+8A@LiDAIB&LLvFdxLp;Wv z5`N<@6LxpI>kq##Xtwer{hoY^o3zYoZR{zGGz4VRCUyZ;iG3+P-l zyVBpqLMD)9e6U5D46K2eN#V?i_M2?FHFiWFhR=TUTZ5 z%-d?M?z#r6&>f^qOJrA}9UX}dEJaq;tfYcW_Z6Uf{TYF3zgE>+vwn?Pzlr~xVKcaM z%NZ|x2E49)BDQ{Lth1>joQ>E^eOi?BsFg1!z6@ijhS#w{=y7m<9R=IRSwB7qYZb@u zpNa1{2PId@eUv I_-0q&|D5KJ3;+NC literal 0 HcmV?d00001 diff --git a/docs/source/_static/style.css b/docs/source/_static/style.css new file mode 100644 index 0000000..7850ee3 --- /dev/null +++ b/docs/source/_static/style.css @@ -0,0 +1,3 @@ +div.body h1 { + display: none; +} \ No newline at end of file diff --git a/docs/source/_static/worldometer-icon.png b/docs/source/_static/worldometer-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6fbaba436e76d9d50850a3c8f4e862a06c675ad3 GIT binary patch literal 8977 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
Qew< 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 literal 13110 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%0AnRW-Rz}Olq^Hc>9qz z0dF$*<;>*@pEWiKDw%2;*R3_|M^|juVh)eQ?CVBV{M}Y$tK+S16HRPYqm!Z&ubofx z$=q2qY_Xrt0%f5ga)w`wobWAlQ!zA;eBvgWapa<3)NnbK)pHuqvbml^0OHPL&vHyAMivxd2QF1AE}u}izS?>Hh3QP=DYO!3EP z%o*7jmU|ud>&5W1^1{i><*D=jStX4?^Nc51(GG8%2&R%9N3B^4{T1#!>9neC7#m*5 zl{jv4@>h2eYR4qlT@Lnsc3#Y@(aOW)#BBQyn4r~QKNT~FOSDn+l$a>)ip>TSpO%lv&^1Q0FNNaup02e<||Oyi)G z5B$>gq)1^t)y+fP1^@RQ&HszLJ^nE$$UO81?dHA!0BYrW0-2n0ul-p-cIZllIOzr; z^_kICG=C`(;I%+vC@xvf0|2lJ9f-re7Q7Ak0S5dNthv{Wa7M0s-;PrK^mg{la4t$O zy#9GM(8w*V=&C1CK=Ec$CP>Lj*mPlafU{w?noV=e%@}n!#yg!avGf2I9k;T2Pi#JC z858&XE7h=dYs=2P%ei2SV38Z9^qA4bfu-EW1_G`2y)mwXU18fhYWHL(omN_#(`fvJ z9>x!D6HAg~#*VkI&`Qq{b-XXMDCh17j6bI>k6Og44Vw|TZ*W!XFJz8{Kzb^F2DY-~ zybX5((hc5|O2fT2>ue)VtMcFxS>~cuV8=oI`(Eq))`K8;K*L zFCO}69xV06Z|1(NO7`!q7o6gbGl$~l3Q)^F6)ODNx;cWY76_Tf#LXxw<{$q^_oU?-h8!za@W01f3 z)Q6xJ+zklP1Ab~ONxYN6elsGq)){Mc;@I;7?;W*$VgE#UDdMUkBM?~;BW~p+V7wthy zY9eOC*R~g?3gs>k_06OUPByQp_9R;-(c{0p45d$cNA>?P`?S0=m zs$Wmb-fbzn^#e4SPez}nDJXhBM8gJ1o7=(986e+wkxAa4 z3XKvyC(PdsWY(Y0icg{I)MQwqV3A}JWkxNItqlE6C3|27jB_BJfQNEy^28|MCs#MH zRpCo+x-JA#D3-H;jM$^dCeYx$w_ts}-~2&W@4$oIc5-Bp1wZ|#eigyI@MrgHD^<#f zZoi%#MzwNxL)dyhI@!Z}FUQuXuUI(nj&RY+;odq-*G9u{*KWROb)I>4)z$o4JVLx2 zI@R^hg5AC?)I>R--gE)Rsn+msk_Y+!v+sVVH-mm7hK%`7Uf>|V&%wBjt9;0#Odnmk z!%EguKUHKjK80VK@z=d+%@YlH%SEnG!X0M58)D7v8BmW_sdn-G-?!IPrTA$mj4V+# z_jgOW#cn)ck9GMb?hBr>Tn*7lg*s6zK^fQ>}e~9m-qq;yTM=+!FSvJ3`Kf(>)y-N-Dn&T(;|Zq z@#XzcG~rHCG6pKAiq~OD@1>FQ80~e-uyPC0GTEWAlV82;doyH~5CGAO`t`@>IV zGM_0b-{4ivDmul_^Vud4`J(6CY4TKPFo!%5wXq0_vp5eM`pQaxwjpcG90*kVSyT3N zCo_{g=HA+^cMs2yL8~1G1Bqn)!>;~Hh9L+;)`m* zjIEdN_*OniUzYeem!lW_3EA3EMfa6aSLx%ssAiEC2_6WSfV6Ze?>2A34W$zIUsxhK^gqLs zti>bCjbOT|ZLk4T4ta^;iTdjZp=YF9WbU5zNlNU{WEPxnkEF&4&kYM&BWjADYC>vz zpY%p=INE6F%Jb~>(3n9RwH9TOx64DX18WrfEyAL_$y~(mdGQ*E8*3)i0b%6aWmJjf z%!}5wz^$oW>W9vcX=0EfnXj^`Jaq;0Ij=XHb#dQXCmG@-SagD2A&0KNC4#%2@Z6?o z`i&lZDD;sASx6L6_UX>XU;-JXSLRX?>REaM?s3CyA{_CuLSfge?$o#W;V>{zp`kFo z0NcD6_`npILK<+pXS|?ZIfIR$l<60l`Q4|_k|3H}&$#BUzYx{9C zyLsGpHPo%6%U@5X!!8NOxF90fsgw{IsERqhmPXBQq?V;~H!G6U=J-!&I(`GM0jeyr z(q+3J)AoVqWh>2W9<bvT&Gic9%axC!BE2QOaTf&I2akDBIK!=P1ksY-JIq(K4_If_eWW=-sI$=Y=O zS!D*cNGF|-~pE>R)PhZpu z&Z_Obqs9x^uW11u9R&79S=P`wo}_kU_x-N8>ykCR*g~47M4RpRunlZS)4gx7Wx! zoA7IU^~G>kD*l76D~POFrTn8)b#6f@AuB$o&vHDxa4KV=?V*= z!kIS|_o$HBH)B;H5#)OORz9!dsfHRC^PHZVxmiC=`t?&opNo)T;>Tg}d?Jo3UbrO9K{_8D& zdshjX-h13>Gl;|2<{G#xf3mUJ752)!xdi$Q66x&-tPD&eM;j#b^V1@i+thxJWom0# zyUH*)xvM-_(r`!PlKbsyGK5S{9rgrrw_tCxhz^2FhOg03PQaL1dtkwXGcWOLW6GLq zv(b}(V74>S6TZwW&Wf+R**0LZbg4Ceolfzktb`Y-+G}oGAbMm-mpvfelR8TtsqxXN zpmswkZ#XgBr?yW;Qy>qYcb&Fhaz?m5B+S>;K=NN5F`z(9vx93D{nNIH#Lf+}^ z%ymPo)gS{RSpJMwyO?S|Ta#H0n(G?@Bzb>AyC?tL^6g=UbHri7O#ERND)gpX(?NTn z2tBKt3N>S^hax|(Qoy6Wgyh=F-lCt{l?m7$s*B6hCaS0Ui+)1$!QAsBh17F{hy0`< zu~pNX-{TMVs*^>>(i8&E0Mm5c)wAC(*?S9mTM?ic}l+tpW zfovjGafQFDR1&pbn-rM3j?x3ZK0aU~gv03o07#^pXsu@0a{%D2CNBBQ^#>OMwurh_ zDQW;y~SWI#QtwPM9_XPef#V#@&=k3S+N&!z!9H-K>6+FdZ&(??3*0K9#1y;TU^=I@tggYIA^0=%37*U tag. It defaults to an empty list. +html_css_files = ['style.css'] + # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. diff --git a/docs/source/index.rst b/docs/source/index.rst index 5c8c100..cbe5034 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,8 +3,16 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Worldometer: Scraping & API -=========================== +.. this title is hidden with css + +Worldometer +=========== + +.. image:: https://raw.githubusercontent.com/matheusfelipeog/worldometer/master/.github/assets/images/worldometer.png + :alt: Worldometer package logo + :width: 800px + :align: center + .. image:: https://img.shields.io/pypi/status/worldometer :alt: PyPI - Status From d3b8d8279d59ab28b5d3cc716d53c751836a5427 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 18 Oct 2023 19:47:20 -0300 Subject: [PATCH 104/147] docs: reorder badges --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c3bd1be..f686591 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,12 @@ PyPI - Version - - License MIT - Total Downloads + + License MIT +

From c308c4921b321a33adb42b5eb0799f5d28b056bb Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 18 Oct 2023 20:32:11 -0300 Subject: [PATCH 105/147] fix: use correct selector for h1 on homepage only --- docs/source/_static/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/_static/style.css b/docs/source/_static/style.css index 7850ee3..b7e4e17 100644 --- a/docs/source/_static/style.css +++ b/docs/source/_static/style.css @@ -1,3 +1,3 @@ -div.body h1 { +div.body #worldometer h1 { display: none; } \ No newline at end of file From 5b167f0df8f9a3da2593c9623ae06e740e0db300 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 18 Oct 2023 22:12:07 -0300 Subject: [PATCH 106/147] docs: remove localtoc sidebars of sub pages --- docs/source/conf.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index e95b03f..bd7395f 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -197,7 +197,6 @@ ], '**': [ 'about.html', - 'localtoc.html', 'navigation.html', 'relations.html', 'sourcelink.html', From ff932d9e3d7171395e1cea15ca89106fb71f0429 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 18 Oct 2023 22:56:49 -0300 Subject: [PATCH 107/147] docs: create worldometer.world docs --- docs/source/worldometer/world.rst | 68 +++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 docs/source/worldometer/world.rst diff --git a/docs/source/worldometer/world.rst b/docs/source/worldometer/world.rst new file mode 100644 index 0000000..15ebc0c --- /dev/null +++ b/docs/source/worldometer/world.rst @@ -0,0 +1,68 @@ +world package +============= + +.. module:: worldometer.world.counters + +`world` is the main API of the `worldometer` package, where you can access various live counters and data available on the https://www.worldometers.info website through self-descriptive classes, methods, and attributes. + + +Live Counters +------------- + +Get the data provided by the live counters. + +Each section is represented by an attribute in the :class:`WorldCounters` class, and these attributes are instances of data classes that store the counter values. + +Each of these data classes has attributes that describe the data stored in them. + +.. code-block:: + + >>> from worldometer.world import WorldCounters + + >>> wc = WorldCounters() + + >>> wc.world_population.current_population + 8065299074 + + >>> wc.government_and_economics.computers_produced_this_year + 180248430 + + >>> wc.society_and_media.internet_users_in_the_world_today + 5895566559 + +.. autoclass:: WorldCounters + +.. autoclass:: WorldPopulation +.. autoclass:: GovernmentAndEconomics +.. autoclass:: SocietyAndMedia +.. autoclass:: Environment +.. autoclass:: Food +.. autoclass:: Water +.. autoclass:: Energy +.. autoclass:: Health + + +Country Codes +------------- + +.. module:: worldometer.world.country_codes + +All countries have specific codes that represent them in some way. Get all of these codes with the :class:`CountryCodes` class:: + + >>> from worldometer.world import CountryCodes + + >>> cc = CountryCodes() + + >>> cc.data[0] + CountryCodesData( + country='Afghanistan', + calling_code='93', + three_letter_iso='AF', + two_letter_iso='AFG', + three_digit_iso_numeric=4 + ) + +.. autoclass:: CountryCodes + :members: + +.. autoclass:: CountryCodesData From cc273bdf2c238845034eabcda13166637ac52cce Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 18 Oct 2023 23:00:19 -0300 Subject: [PATCH 108/147] docs: create worldometer docs --- docs/source/worldometer/index.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/source/worldometer/index.rst diff --git a/docs/source/worldometer/index.rst b/docs/source/worldometer/index.rst new file mode 100644 index 0000000..ee31f0b --- /dev/null +++ b/docs/source/worldometer/index.rst @@ -0,0 +1 @@ +.. automodule:: worldometer From 78a8316e479b3b0198f1824399dfe12abf97598a Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 19 Oct 2023 00:16:47 -0300 Subject: [PATCH 109/147] docs: create worldometer.population docs --- docs/source/worldometer/population.rst | 305 +++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 docs/source/worldometer/population.rst diff --git a/docs/source/worldometer/population.rst b/docs/source/worldometer/population.rst new file mode 100644 index 0000000..d0c3bd0 --- /dev/null +++ b/docs/source/worldometer/population.rst @@ -0,0 +1,305 @@ +population package +================== + +The population package provides access to various data related to world populations, regions, and their countries. Additionally, it includes historical data ranging from 1950 to the present day and future projections extending to 2050. + +To understand the significance of each of these data sets, their sources, and any other related information, please visit the official page at https://www.worldometers.info/population + + +Population by country +--------------------- + +.. code-block:: + + >>> from worldometer.world.population import CountriesByPopulation + + >>> cp = CountriesByPopulation() + + >>> cp.data[0] + CountriesByPopulationData( + idx=1, + country='India', + population=1428627663, + yearly_change='0.81 %', + net_change=11454490, + density=481, + land_area=2973190, + migrants=-486136, + fertility_rate=2.0, + median_age=28.0, + urban_population='36 %', + world_share='17.76 %' + ) + +.. module:: worldometer.world.population.countries_by_population + +.. autoclass:: CountriesByPopulation + :members: + +.. autoclass:: CountriesByPopulationData + + +Population by region +-------------------- + +.. code-block:: + + >>> from worldometer.world.population import WorldPopulationByRegion + + >>> pr = WorldPopulationByRegion() + + >>> pr.current()[0] + CurrentWorldPopulationByRegionData( + idx=1, + region='Asia', + population=4753079727, + yearly_change='0.64 %', + net_change=30444963, + density=153, + area=31033131, + migrants=-1487191, + fertility_rate=1.934, + median_age=32, + urban_population='52.6 %', + world_share='59.1 %' + ) + + >>> pr.past()[0] + PastWorldPopulationByRegionData( + idx=1, + region='Asia', + population=1379048370, + world_share='55.2 %' + ) + + >>> pr.future()[0] + FutureWorldPopulationByRegionData( + idx=1, + region='Asia', + population=5292947571, + world_share='54.5 %' + ) + +.. module:: worldometer.world.population.by_region + +.. autoclass:: WorldPopulationByRegion + :members: + +.. autoclass:: CurrentWorldPopulationByRegionData +.. autoclass:: PastWorldPopulationByRegionData +.. autoclass:: FutureWorldPopulationByRegionData + + +Population by year +------------------ + +.. code-block:: + + >>> from worldometer.world.population import WorldPopulationByYear + + >>> py = WorldPopulationByYear() + + >>> py.data[0] + WorldPopulationByYearData( + year=2023, + world_population=8045311447, + yearly_change='0.88 %', + net_change=70206291.0, + density=54.0 + ) + +.. module:: worldometer.world.population.by_year + +.. autoclass:: WorldPopulationByYear + :members: + +.. autoclass:: WorldPopulationByYearData + + +Largest cities in the world +--------------------------- + +.. code-block:: + + >>> from worldometer.world.population import LargestCities + + >>> lc = LargestCities() + + >>> lc.data[0] + LargestCitiesData( + rank=1, + urban_area='Tokyo-Yokohama', + population_estimate=37843000, + country='Japan', + land_area=8547, + density=4400 + ) + +.. module:: worldometer.world.population.largest_cities + +.. autoclass:: LargestCities + :members: + +.. autoclass:: LargestCitiesData + + +Most populous countries +----------------------- + +.. code-block:: + + >>> from worldometer.world.population import MostPopulousCountries + + >>> pc = MostPopulousCountries() + + >>> pc.current()[0] + CurrentMostPopulousCountriesData( + idx=1, + country='India', + population=1428627663, + yearly_change='0.81 %', + world_share='17.8 %' + ) + + >>> pc.past()[0] + PastMostPopulousCountriesData( + idx=1, + country='China', + population=543979233, + world_share='21.8 %', + rank='(2)' + ) + + >>> pc.future()[0] + FutureMostPopulousCountriesData( + idx=1, + country='India', + population=1670490596, + world_share='17.2 %', + rank='(1)' + ) + +.. module:: worldometer.world.population.most_populous_countries + +.. autoclass:: MostPopulousCountries + :members: + +.. autoclass:: CurrentMostPopulousCountriesData +.. autoclass:: PastMostPopulousCountriesData +.. autoclass:: FutureMostPopulousCountriesData + + +World population projections +---------------------------- + +.. code-block:: + + >>> from worldometer.world.population import WorldPopulationProjections + + >>> pp = WorldPopulationProjections() + + >>> pp.data[0] + WorldPopulationProjectionsData( + year=2023, + world_population=8045311447, + yearly_change='0.88 %', + net_change=70206291, + density=54 + ) + +.. module:: worldometer.world.population.projections + +.. autoclass:: WorldPopulationProjections + :members: + +.. autoclass:: WorldPopulationProjectionsData + + +Regions population +------------------ + +.. code-block:: + + >>> from worldometer.world.population import ( + AsiaPopulation, + AfricaPopulation, + EuropePopulation, + LatinAmericanAndTheCaribbeanPopulation, + NorthernAmericanPopulation, + OceaniaPopulation + ) + + >>> ap = AsiaPopulation() + + >>> ap.live() + 4762699828 + + >>> ap.subregions()[0] + SubregionData( + area='Southern Asia', + population='(2,027,578,876)' + ) + + >>> ap.historical()[0] + HistoricalData( + year=2023, + population=4753079727, + yearly_change_percent='0.64 %', + yearly_change=30444963, + migrants=-1487191, + median_age=31.9, + fertility_rate=1.93, + density=153, + urban_population_percent='52.6 %', + urban_population=2500201501, + world_share='59.1 %', + world_population=8045311447, + rank=nan + ) + + >>> ap.forecast()[0] + ForecastData( + year=2025, + population=4816249054, + yearly_change_percent='0.64 %', + yearly_change=30384996, + migrants=-1555419, + median_age=32.7, + fertility_rate=1.93, + density=155, + urban_population_percent='53.8 %', + urban_population=2589655469, + world_share='61.4 %', + world_population=8191988453, + rank=nan + ) + +.. module:: worldometer.world.population.regions + +.. autoclass:: AsiaPopulation + :members: + :inherited-members: + +.. autoclass:: AfricaPopulation + :members: + :inherited-members: + +.. autoclass:: EuropePopulation + :members: + :inherited-members: + +.. autoclass:: LatinAmericanAndTheCaribbeanPopulation + :members: + :inherited-members: + +.. autoclass:: NorthernAmericanPopulation + :members: + :inherited-members: + +.. autoclass:: OceaniaPopulation + :members: + :inherited-members: + +.. autoclass:: SubregionData +.. autoclass:: HistoricalData +.. autoclass:: ForecastData From b83125b8b18e3fe7cdc0cbbf738972e8e28c9d37 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 19 Oct 2023 00:25:47 -0300 Subject: [PATCH 110/147] docs: add index to world and population docs --- docs/source/worldometer/population.rst | 3 +++ docs/source/worldometer/world.rst | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/source/worldometer/population.rst b/docs/source/worldometer/population.rst index d0c3bd0..dc48464 100644 --- a/docs/source/worldometer/population.rst +++ b/docs/source/worldometer/population.rst @@ -1,6 +1,9 @@ population package ================== +.. contents:: Index + :depth: 2 + The population package provides access to various data related to world populations, regions, and their countries. Additionally, it includes historical data ranging from 1950 to the present day and future projections extending to 2050. To understand the significance of each of these data sets, their sources, and any other related information, please visit the official page at https://www.worldometers.info/population diff --git a/docs/source/worldometer/world.rst b/docs/source/worldometer/world.rst index 15ebc0c..d5ac904 100644 --- a/docs/source/worldometer/world.rst +++ b/docs/source/worldometer/world.rst @@ -1,7 +1,8 @@ world package ============= -.. module:: worldometer.world.counters +.. contents:: Index + :depth: 2 `world` is the main API of the `worldometer` package, where you can access various live counters and data available on the https://www.worldometers.info website through self-descriptive classes, methods, and attributes. @@ -9,6 +10,9 @@ world package Live Counters ------------- +.. module:: worldometer.world.counters + + Get the data provided by the live counters. Each section is represented by an attribute in the :class:`WorldCounters` class, and these attributes are instances of data classes that store the counter values. From bd644d05fde013a810781c726910b850e0ba6daa Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 19 Oct 2023 00:56:32 -0300 Subject: [PATCH 111/147] docs: create worldometer.geography docs --- docs/source/worldometer/geography.rst | 121 ++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 docs/source/worldometer/geography.rst diff --git a/docs/source/worldometer/geography.rst b/docs/source/worldometer/geography.rst new file mode 100644 index 0000000..ae25947 --- /dev/null +++ b/docs/source/worldometer/geography.rst @@ -0,0 +1,121 @@ +geography package +================= + +.. contents:: Index + :depth: 2 + +The `geography` package provides access to various data related to geographic information about the world, regions, and their countries. + +To understand the significance of each of these data sets, their sources, and any other related information, please visit the official page at https://www.worldometers.info/geography/how-many-countries-are-there-in-the-world + + +Countries in the world +---------------------- + +.. code-block:: + + >>> from worldometer.world.geography import ( + WorldCountries, + AsiaCountries, + AfricaCountries, + EuropeCountries, + LatinAmericanAndTheCaribbeanCountries, + NorthernAmericanCountries, + OceaniaCountries + ) + + >>> wc = WorldCountries() + + >>> wc.total + 195 + + >>> wc.countries()[0] + WorldCountriesData( + idx=1, + country='India', + population=1428627663, + world_share='17.76 %', + land_area=2973190 + ) + + >>> ac = AfricaCountries() + + >>> ac.total + 54 + + >>> ac.countries()[0] + CountryData( + idx=1, + country='Nigeria', + population=223804632, + subregion='Western Africa' + ) + + >>> ac.dependencies()[0] + DependencyData( + idx=1, + territory='Réunion', + population=981796, + dependency_of='France' + ) + +.. module:: worldometer.world.geography.countries + +.. autoclass:: WorldCountries + :members: + +.. autoclass:: AsiaCountries + :members: + :inherited-members: + +.. autoclass:: AfricaCountries + :members: + :inherited-members: + +.. autoclass:: EuropeCountries + :members: + :inherited-members: + +.. autoclass:: LatinAmericanAndTheCaribbeanCountries + :members: + :inherited-members: + +.. autoclass:: NorthernAmericanCountries + :members: + :inherited-members: + +.. autoclass:: OceaniaCountries + :members: + :inherited-members: + +.. autoclass:: WorldCountriesData +.. autoclass:: CountryData +.. autoclass:: DependencyData + + +Largest countries in the world +------------------------------ + +.. code-block:: + + >>> from worldometer.world.geography import LargestCountries + + >>> lc = LargestCountries() + + >>> lc.data[0] + LargestCountriesData( + idx=1, + country='Russia', + total_area_km2=17098242, + total_area_mi2=6601665, + land_area_km2=16376870, + land_area_mi2=6323142, + percentage_of_world_landmass='11.0 %' + ) + +.. module:: worldometer.world.geography.largest_countries + +.. autoclass:: LargestCountries + :members: + +.. autoclass:: LargestCountriesData From f249353ea336c5c5960a4470385994f4d26c5646 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 19 Oct 2023 00:57:51 -0300 Subject: [PATCH 112/147] docs: fix code block in docstring --- worldometer/__init__.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/worldometer/__init__.py b/worldometer/__init__.py index 9d8207b..9d89213 100644 --- a/worldometer/__init__.py +++ b/worldometer/__init__.py @@ -8,30 +8,30 @@ Examples -------- -Get the data from the live counters available on the homepage: +Get the data from the live counters available on the homepage:: ->>> from worldometer.world import WorldCounters + >>> from worldometer.world import WorldCounters ->>> wc = WorldCounters() + >>> wc = WorldCounters() ->>> wc.world_population.current_population -8065299074 + >>> wc.world_population.current_population + 8065299074 ->>> wc.government_and_economics.computers_produced_this_year -180248430 + >>> wc.government_and_economics.computers_produced_this_year + 180248430 ->>> wc.society_and_media.internet_users_in_the_world_today -5895566559 + >>> wc.society_and_media.internet_users_in_the_world_today + 5895566559 -Reload data to get the latest: +Reload data to get the latest:: ->>> wc.reload_data() ->>> wc.world_population.current_population -8065300592 + >>> wc.reload_data() + >>> wc.world_population.current_population + 8065300592 -Get help and view information about mapped sections: +Get help and view information about mapped sections:: ->>> help(wc) + >>> help(wc) Notes ----- From 125c68cafa8f8b052c96b867b083bb52711effdf Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 19 Oct 2023 04:14:32 -0300 Subject: [PATCH 113/147] docs: create index documentation --- docs/source/index.rst | 182 +++++++++++++----------------------------- 1 file changed, 56 insertions(+), 126 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index cbe5034..6facfb8 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -13,188 +13,118 @@ Worldometer :width: 800px :align: center - -.. image:: https://img.shields.io/pypi/status/worldometer - :alt: PyPI - Status - :target: https://pypi.org/project/worldometer/ +*Get live, population, geography, projected, and historical data from around the world.* .. image:: https://img.shields.io/pypi/v/worldometer - :alt: PyPI + :alt: PyPI - Version :target: https://pypi.org/project/worldometer/ -.. image:: https://img.shields.io/github/v/release/matheusfelipeog/worldometer - :alt: GitHub release (latest by date) - :target: https://github.com/matheusfelipeog/worldometer/releases - -.. image:: https://readthedocs.org/projects/worldometer/badge/?version=latest - :alt: Documentation Status - :target: https://worldometer.readthedocs.io/en/latest/?badge=latest +.. image:: https://pepy.tech/badge/worldometer + :alt: Total Downloads + :target: https://pepy.tech/project/worldometer .. image:: https://img.shields.io/github/license/matheusfelipeog/worldometer :alt: License MIT :target: https://github.com/matheusfelipeog/worldometer/blob/master/LICENSE -Get current metrics in the world with the python **worldometer** module - ------------------------------------------------------------------------ - - -Index ------ - -- `About <#id1>`_ - - - `worldometers <#id2>`_ - - `How it works? <#id3>`_ - -- `Install <#id4>`_ -- `Demo <#id5>`_ -- `Contributions <#id6>`_ -- `License <#id7>`_ -- `Indices and tables <#id8>`_ +.. image:: https://img.shields.io/pypi/status/worldometer + :alt: PyPI - Status + :target: https://pypi.org/project/worldometer/ -**Worldometer Docs:** +.. image:: https://readthedocs.org/projects/worldometer/badge/?version=latest + :alt: Documentation Status + :target: https://worldometer.readthedocs.io/en/latest/?badge=latest -.. toctree:: - :maxdepth: 1 - worldometer_core - worldometer_api +----------------------------------------------------------------------- About ----- -`Worldometer `_ is a python module that collects data from `worldometers.info `_ and provides a simple and self-explanatory interface for using the data. +The `worldometer `_ package accesses various counters and live data available throughout the `worldometers.info `_ website and provides them through simple and self-describing classes, methods and attributes. -worldometers.info -^^^^^^^^^^^^^^^^^ - - "Worldometer is run by an international team of developers, researchers, and volunteers with the goal of making world statistics available in a thought-provoking and time relevant format to a wide audience around the world. It is published by a small and independent digital media company based in the United States. We have no political, governmental, or corporate affiliation. Furthermore, we have no investors, donors, grants, or backers of any type. We are completely independent and self-financed through automated programmatic advertising sold in real time on multiple ad exchanges." - -More info: `worldometers.info/about `_ - -How it works? -^^^^^^^^^^^^^ +Access data on: - **[Adapted]:** "For the data, is elaborate instead a real-time estimate through a proprietary algorithm which processes the latest data and projections provided by the most reputable organizations and statistical offices in the world." - -More info about data source: `worldometers.info/sources `_ +- The world 🌍 +- Population 👥 +- Geography 🗺️ +- Projections 🔮 +- Historical 📜 Install ------- -First, create a directory and enter it:: - - $ mkdir my_project && cd my_project - -Create a virtual environment to avoid breaking dependence on other projects. - -This project uses `pipenv `_, it already does it alone 😆:: - - $ pipenv install worldometer +Use ``pip`` to install the worldometer package:: + $ pip install worldometer -But you can use ``virtualenv`` + ``pip`` if you prefer:: - $ virtualenv venv && source venv/Scripts/activate +API Reference +------------- +The worldometer package is divided into several specific sub-packages for each dataset. So if you are looking for information on a specific package, class, or method, this part of the documentation is for you. -Now install:: +.. toctree:: + :maxdepth: 2 - $ pip install worldometer + worldometer + worldometer.world + worldometer.world.population + worldometer.world.geography Demo ---- .. note:: - The first time you run any function/method or class, it will download Chromium to its home directory (for example, ``~/.pyppeteer/``). It only happens once. - - After, it will only open the chromium to render the contents of worldometers. - -**Simple API usage:** + The first time you run any function/method or class, it will download Chromium to ``~/.local/share/pyppeteer`` directory. It only happens once. After, it will only open the chromium to render the contents of worldometers.info. -*See all function in:* `worldometer.api `_ +Get the data from the live counters available on the `homepage `_:: -Get metrics using simplified functions: + >>> from worldometer.world import WorldCounters - >>> import worldometer + >>> wc = WorldCounters() - >>> worldometer.current_world_population() - {'current_world_population': 7845085923} + >>> wc.world_population.current_population + 8065299074 - >>> worldometer.tweets_sent_today() - {'tweets_sent_today': 4539558} + >>> wc.government_and_economics.computers_produced_this_year + 180248430 -Get metrics by passing the corresponding label: + >>> wc.society_and_media.internet_users_in_the_world_today + 5895566559 - >>> worldometer.get_metric_of(label='computers_produced_this_year') - {'computers_produced_this_year': 27760858} +Reload data to get the latest:: + >>> wc.reload_data() + >>> wc.world_population.current_population + 8065300592 -**Or complete use with Worldometer Class:** +Get help and view information about mapped sections:: -*See all methods in:* `worldometer.core `_ + >>> help(wc) ->>> from worldometer import Worldometer ->>> w = Worldometer() -Get the number of categories, labels and metrics in ``w`` object: - - >>> w.what_is_here() - {'categories': 8, 'labels': 63, 'metrics': 63} +worldometers.info +----------------- -Get all categories used: + "Worldometer is run by an international team of developers, researchers, and volunteers with the goal of making world statistics available in a thought-provoking and time relevant format to a wide audience around the world. It is published by a small and independent digital media company based in the United States. We have no political, governmental, or corporate affiliation. Furthermore, we have no investors, donors, grants, or backers of any type. We are completely independent and self-financed through automated programmatic advertising sold in real time on multiple ad exchanges." - >>> w.categories() - [ - 'world_population', - 'government_and_economics', - 'society_and_media', - ... # compressed - ] +More info: `worldometers.info/about `_ -Get all labels used: - >>> w.metrics_labels() - [ - 'current_world_population', - 'births_this_year', - 'births_today', - 'deaths_this_year', - 'deaths_today', - 'net_population_growth_this_year', - ... # compressed - ] +Data Sources +------------ -Get all metrics used: + **[adapted]:** "worldometers.info collects its statistics and data from the most reputable national and international organizations, including the United Nations, the World Health Organization, the Food and Agriculture Organization, OECD and others. - >>> w.metrics() - [ - 7845087963, - 15741371, - 5676, - 6608605, - 2383, - 9132766, - ... # compressed - ] + Each Worldometer counter has its specific set of sources, which are listed on its dedicated page (accessible by clicking on the counter text link, when available). -Get all metrics with labels in dict format: + Data, estimates, and projections displayed on worldometers.info counters are for the most part provided by organizations included in the following list of United Nations Statistics Division's partners." ->>> w.metrics_with_labels() -{ - 'abortions_this_year': 4785492, - 'bicycles_produced_this_year': 17070566, - 'births_this_year': 15741371, - 'births_today': 5676, - 'blog_posts_written_today': 110171, - 'cars_produced_this_year': 8999185, - 'cellular_phones_sold_today': 98846, - ...: ... # compressed -} +More info about data source: `worldometers.info/sources `_ Contributions From 5254a317fd69f620a5ea83dcad74810fc636abf1 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 19 Oct 2023 04:23:41 -0300 Subject: [PATCH 114/147] docs: update README.md file --- README.md | 53 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index f686591..2c16144 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,11 @@ ## Index - [About](#about) - - [worldometers.info](#worldometersinfo) - - [Sources](#sources) - [Install](#install) +- [Documentation](#documentation) - [Demo](#demo) +- [worldometers.info](#worldometersinfo) +- [Sources](#data-sources) - [Contributions](#contributions) - [License](#license) @@ -55,26 +56,6 @@ Access data on: - Projections 🔮 - Historical 📜 -### worldometers.info - -> Worldometer is run by an international team of developers, researchers, and volunteers with the goal of making world statistics available in a thought-provoking and time relevant format to a wide audience around the world. It is published by a small and independent digital media company based in the United States. We have no political, governmental, or corporate affiliation. Furthermore, we have no investors, donors, grants, or backers of any type. We are completely independent and self-financed through automated programmatic advertising sold in real time on multiple ad exchanges. - -

- worldometers.info/about -

- -### Sources - -> **[adapted]:** worldometers.info collects its statistics and data from the most reputable national and international organizations, including the United Nations, the World Health Organization, the Food and Agriculture Organization, OECD and others. -> -> Each Worldometer counter has its specific set of sources, which are listed on its dedicated page (accessible by clicking on the counter text link, when available). -> -> Data, estimates, and projections displayed on worldometers.info counters are for the most part provided by organizations included in the following list of United Nations Statistics Division's partners. - -

- worldometers.info/sources -

- ## Install @@ -84,6 +65,12 @@ Use `pip` to install the worldometer package: $ pip install worldometer ``` + +## Documentation + +See the documentation for more information on the worldometer package and its API at: [worldometer.readthedocs.io](https://worldometer.readthedocs.io/) + + ## Demo > [!NOTE] @@ -123,6 +110,28 @@ Get help and view information about mapped sections: See the documentation at [worldometer.readthedocs.io](https://worldometer.readthedocs.io/) +## worldometers.info + +> Worldometer is run by an international team of developers, researchers, and volunteers with the goal of making world statistics available in a thought-provoking and time relevant format to a wide audience around the world. It is published by a small and independent digital media company based in the United States. We have no political, governmental, or corporate affiliation. Furthermore, we have no investors, donors, grants, or backers of any type. We are completely independent and self-financed through automated programmatic advertising sold in real time on multiple ad exchanges. + +

+ worldometers.info/about +

+ + +## Data Sources + +> **[adapted]:** worldometers.info collects its statistics and data from the most reputable national and international organizations, including the United Nations, the World Health Organization, the Food and Agriculture Organization, OECD and others. +> +> Each Worldometer counter has its specific set of sources, which are listed on its dedicated page (accessible by clicking on the counter text link, when available). +> +> Data, estimates, and projections displayed on worldometers.info counters are for the most part provided by organizations included in the following list of United Nations Statistics Division's partners. + +

+ worldometers.info/sources +

+ + ## Contributions All contributions are welcome! From 0508cabeb5239614cfc5115dadd8402feb73fcba Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 19 Oct 2023 04:25:59 -0300 Subject: [PATCH 115/147] docs: fix data sources index --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2c16144..8a4307b 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ - [Documentation](#documentation) - [Demo](#demo) - [worldometers.info](#worldometersinfo) -- [Sources](#data-sources) +- [Data Sources](#data-sources) - [Contributions](#contributions) - [License](#license) From d1fbc926877d02b835069e940289209f5851d0fd Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 19 Oct 2023 04:29:57 -0300 Subject: [PATCH 116/147] docs: upd documentation section description --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a4307b..8ee462e 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ $ pip install worldometer ## Documentation -See the documentation for more information on the worldometer package and its API at: [worldometer.readthedocs.io](https://worldometer.readthedocs.io/) +See the docs for more information and its API at: [worldometer.readthedocs.io](https://worldometer.readthedocs.io/) ## Demo From fa1dd7ca592d5767d4c5e71af15a881ac9db93e9 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 19 Oct 2023 04:31:43 -0300 Subject: [PATCH 117/147] docs: remove docs mention of demo section --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 8ee462e..05ee39b 100644 --- a/README.md +++ b/README.md @@ -107,8 +107,6 @@ Get help and view information about mapped sections: >>> help(wc) ``` -See the documentation at [worldometer.readthedocs.io](https://worldometer.readthedocs.io/) - ## worldometers.info From 556c919fd7fa7914577513d0dd8959dd8519e439 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 19 Oct 2023 05:20:49 -0300 Subject: [PATCH 118/147] docs: add attributes section in all package docstring --- worldometer/world/counters.py | 111 ++++++++++++++++-- worldometer/world/country_codes.py | 11 +- worldometer/world/geography/countries.py | 31 ++++- .../world/geography/largest_countries.py | 13 +- worldometer/world/population/by_region.py | 38 +++++- worldometer/world/population/by_year.py | 11 +- .../population/countries_by_population.py | 18 ++- .../world/population/largest_cities.py | 12 +- .../population/most_populous_countries.py | 33 +++++- worldometer/world/population/projections.py | 11 +- worldometer/world/population/regions.py | 46 +++++++- 11 files changed, 309 insertions(+), 26 deletions(-) diff --git a/worldometer/world/counters.py b/worldometer/world/counters.py index ae2ed32..ddcd1b3 100644 --- a/worldometer/world/counters.py +++ b/worldometer/world/counters.py @@ -69,7 +69,18 @@ def reload_data(self) -> None: @dataclass class WorldPopulation: - """Counters related to world population data.""" + """Counters related to world population data. + + Attributes + ---------- + current_population : Union[int, float, None] + births_today : Union[int, float, None] + births_this_year : Union[int, float, None] + deaths_today : Union[int, float, None] + deaths_this_year : Union[int, float, None] + net_population_growth_today : Union[int, float, None] + net_population_growth_this_year : Union[int, float, None] + """ _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: @@ -84,7 +95,17 @@ def __post_init__(self) -> None: @dataclass class GovernmentAndEconomics: - """Counters related to government and economic data.""" + """Counters related to government and economic data. + + Attributes + ---------- + public_healthcare_expenditure_today : Union[int, float, None] + public_education_expenditure_today : Union[int, float, None] + public_military_expenditure_today : Union[int, float, None] + cars_produced_this_year : Union[int, float, None] + bicycles_produced_this_year : Union[int, float, None] + computers_produced_this_year : Union[int, float, None] + """ _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: @@ -98,7 +119,21 @@ def __post_init__(self) -> None: @dataclass class SocietyAndMedia: - """Counters related to society and media data.""" + """Counters related to society and media data. + + Attributes + ---------- + new_book_titles_published_this_year : Union[int, float, None] + newspapers_circulated_today : Union[int, float, None] + tv_sets_sold_worldwide_today : Union[int, float, None] + cellular_phones_sold_today : Union[int, float, None] + money_spent_on_videogames_today : Union[int, float, None] + internet_users_in_the_world_today : Union[int, float, None] + emails_sent_today : Union[int, float, None] + blog_posts_written_today : Union[int, float, None] + tweets_sent_today : Union[int, float, None] + google_searches_today : Union[int, float, None] + """ _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: @@ -116,7 +151,16 @@ def __post_init__(self) -> None: @dataclass class Environment: - """Counters related to environmental data.""" + """Counters related to environmental data. + + Attributes + ---------- + forest_loss_this_year : Union[int, float, None] + land_lost_to_soil_erosion_this_year : Union[int, float, None] + co2_emissions_this_year : Union[int, float, None] + desertification_this_year : Union[int, float, None] + toxic_chemicals_released_in_the_environment_this_year : Union[int, float, None] + """ _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: @@ -129,7 +173,17 @@ def __post_init__(self) -> None: @dataclass class Food: - """Counters related to food data.""" + """Counters related to food data. + + Attributes + ---------- + undernourished_people_in_the_world : Union[int, float, None] + overweight_people_in_the_world : Union[int, float, None] + obese_people_in_the_world : Union[int, float, None] + people_who_died_of_hunger_today : Union[int, float, None] + money_spent_for_obesity_related_diseases_in_the_usa_today : Union[int, float, None] + money_spent_on_weight_loss_programs_in_the_usa_today : Union[int, float, None] + """ _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: @@ -143,7 +197,14 @@ def __post_init__(self) -> None: @dataclass class Water: - """Counters related to water data.""" + """Counters related to water data. + + Attributes + ---------- + water_used_this_year : Union[int, float, None] + deaths_caused_by_water_related_diseases_this_year : Union[int, float, None] + people_with_no_access_to_a_safe_drinking_water_source : Union[int, float, None] + """ _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: @@ -154,7 +215,22 @@ def __post_init__(self) -> None: @dataclass class Energy: - """Counters related to energy data.""" + """Counters related to energy data. + + Attributes + ---------- + energy_used_today : Union[int, float, None] + non_renewable_sources : Union[int, float, None] + renewable_sources : Union[int, float, None] + solar_energy_striking_earth_today : Union[int, float, None] + oil_pumped_today : Union[int, float, None] + oil_left : Union[int, float, None] + days_to_the_end_of_oil : Union[int, float, None] + natural_gas_left : Union[int, float, None] + days_to_the_end_of_natural_gas : Union[int, float, None] + coal_left : Union[int, float, None] + days_to_the_end_of_coal : Union[int, float, None] + """ _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: @@ -173,7 +249,26 @@ def __post_init__(self) -> None: @dataclass class Health: - """Counters related to health data.""" + """Counters related to health data. + + Attributes + ---------- + communicable_disease_deaths_this_year : Union[int, float, None] + seasonal_flu_deaths_this_year : Union[int, float, None] + deaths_of_children_under_5_this_year : Union[int, float, None] + abortions_this_year : Union[int, float, None] + deaths_of_mothers_during_birth_this_year : Union[int, float, None] + hiv_aids_infected_people : Union[int, float, None] + deaths_caused_by_hiv_aids_this_year : Union[int, float, None] + deaths_caused_by_cancer_this_year : Union[int, float, None] + deaths_caused_by_malaria_this_year : Union[int, float, None] + cigarettes_smoked_today : Union[int, float, None] + deaths_caused_by_smoking_this_year : Union[int, float, None] + deaths_caused_by_alcohol_this_year : Union[int, float, None] + suicides_this_year : Union[int, float, None] + money_spent_on_illegal_drugs_this_year : Union[int, float, None] + road_traffic_accident_fatalities_this_year : Union[int, float, None] + """ _data: Dict[str, Union[int, float, None]] = field(repr=False) def __post_init__(self) -> None: diff --git a/worldometer/world/country_codes.py b/worldometer/world/country_codes.py index 5a1f14e..9fcd746 100644 --- a/worldometer/world/country_codes.py +++ b/worldometer/world/country_codes.py @@ -7,7 +7,16 @@ @dataclass class CountryCodesData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + country: str + calling_code: str + three_letter_iso: str + two_letter_iso: str + three_digit_iso_numeric: str + """ country: str calling_code: str three_letter_iso: str diff --git a/worldometer/world/geography/countries.py b/worldometer/world/geography/countries.py index 9bbb87f..75694ed 100644 --- a/worldometer/world/geography/countries.py +++ b/worldometer/world/geography/countries.py @@ -7,7 +7,16 @@ @dataclass class WorldCountriesData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + idx: int + country: str + population: int + world_share: str + land_area: int + """ idx: int country: str population: int @@ -19,7 +28,15 @@ class WorldCountriesData: @dataclass class CountryData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + idx: int + country: str + population: int + subregion: str + """ idx: int country: str population: int @@ -30,7 +47,15 @@ class CountryData: @dataclass class DependencyData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + idx: int + territory: str + population: int + dependency_of: str + """ idx: int territory: str population: int diff --git a/worldometer/world/geography/largest_countries.py b/worldometer/world/geography/largest_countries.py index 9f7526f..a5a8a6e 100644 --- a/worldometer/world/geography/largest_countries.py +++ b/worldometer/world/geography/largest_countries.py @@ -7,7 +7,18 @@ @dataclass class LargestCountriesData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + idx: int + country: str + total_area_km2: int + total_area_mi2: int + land_area_km2: int + land_area_mi2: int + percentage_of_world_landmass: str + """ idx: int country: str total_area_km2: int diff --git a/worldometer/world/population/by_region.py b/worldometer/world/population/by_region.py index 2096fba..ce6812e 100644 --- a/worldometer/world/population/by_region.py +++ b/worldometer/world/population/by_region.py @@ -7,7 +7,23 @@ @dataclass class CurrentWorldPopulationByRegionData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + idx: int + region: str + population: int + yearly_change: str + net_change: int + density: int + area: int + migrants: int + fertility_rate: float + median_age: int + urban_population: str + world_share: str + """ idx: int region: str population: int @@ -26,7 +42,15 @@ class CurrentWorldPopulationByRegionData: @dataclass class PastWorldPopulationByRegionData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + idx: int + region: str + population: int + world_share: str + """ idx: int region: str population: int @@ -37,7 +61,15 @@ class PastWorldPopulationByRegionData: @dataclass class FutureWorldPopulationByRegionData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + idx: int + region: str + population: int + world_share: str + """ idx: int region: str population: int diff --git a/worldometer/world/population/by_year.py b/worldometer/world/population/by_year.py index b27736b..fa83ee8 100644 --- a/worldometer/world/population/by_year.py +++ b/worldometer/world/population/by_year.py @@ -7,7 +7,16 @@ @dataclass class WorldPopulationByYearData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + year: int + world_population: int + yearly_change: str + net_change: float + density: float + """ year: int world_population: int yearly_change: str diff --git a/worldometer/world/population/countries_by_population.py b/worldometer/world/population/countries_by_population.py index a08a1e0..09f32a4 100644 --- a/worldometer/world/population/countries_by_population.py +++ b/worldometer/world/population/countries_by_population.py @@ -7,7 +7,23 @@ @dataclass class CountriesByPopulationData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + idx: int + country: str + population: int + yearly_change: str + net_change: int + density: int + land_area: int + migrants: int + fertility_rate: float + median_age: float + urban_population: str + world_share: str + """ idx: int country: str population: int diff --git a/worldometer/world/population/largest_cities.py b/worldometer/world/population/largest_cities.py index 571035f..a83c16a 100644 --- a/worldometer/world/population/largest_cities.py +++ b/worldometer/world/population/largest_cities.py @@ -7,7 +7,17 @@ @dataclass class LargestCitiesData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + rank: int + urban_area: str + population_estimate: str + country: str + land_area: int + density: int + """ rank: int urban_area: str population_estimate: str diff --git a/worldometer/world/population/most_populous_countries.py b/worldometer/world/population/most_populous_countries.py index 01455d8..10edd26 100644 --- a/worldometer/world/population/most_populous_countries.py +++ b/worldometer/world/population/most_populous_countries.py @@ -7,7 +7,16 @@ @dataclass class CurrentMostPopulousCountriesData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + idx: int + country: str + population: int + yearly_change: str + world_share: str + """ idx: int country: str population: int @@ -19,7 +28,16 @@ class CurrentMostPopulousCountriesData: @dataclass class PastMostPopulousCountriesData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + idx: int + country: str + population: int + world_share: str + rank: str + """ idx: int country: str population: int @@ -31,7 +49,16 @@ class PastMostPopulousCountriesData: @dataclass class FutureMostPopulousCountriesData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + idx: int + country: str + population: int + world_share: str + rank: str + """ idx: int country: str population: int diff --git a/worldometer/world/population/projections.py b/worldometer/world/population/projections.py index d83089e..9b7a4ab 100644 --- a/worldometer/world/population/projections.py +++ b/worldometer/world/population/projections.py @@ -7,7 +7,16 @@ @dataclass class WorldPopulationProjectionsData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + year: int + world_population: int + yearly_change: str + net_change: int + density: int + """ year: int world_population: int yearly_change: str diff --git a/worldometer/world/population/regions.py b/worldometer/world/population/regions.py index b3513c7..5df45ac 100644 --- a/worldometer/world/population/regions.py +++ b/worldometer/world/population/regions.py @@ -7,7 +7,13 @@ @dataclass class SubregionData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + area: int + population: str + """ area: int population: str @@ -16,7 +22,24 @@ class SubregionData: @dataclass class HistoricalData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + year: int + population: int + yearly_change_percent: str + yearly_change: int + migrants: int + median_age: float + fertility_rate: float + density: int + urban_population_percent: str + urban_population: int + world_share: str + world_population: int + rank: int + """ year: int population: int yearly_change_percent: str @@ -36,7 +59,24 @@ class HistoricalData: @dataclass class ForecastData: - """Represents a data row from the respective table.""" + """Represents a data row from the respective table. + + Attributes + ---------- + year: int + population: int + yearly_change_percent: str + yearly_change: int + migrants: int + median_age: float + fertility_rate: float + density: int + urban_population_percent: str + urban_population: int + world_share: str + world_population: int + rank: int + """ year: int population: int yearly_change_percent: str From fa1de79fe78bc20cc0d53eeaff4a9387ec8df19e Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 19 Oct 2023 05:27:57 -0300 Subject: [PATCH 119/147] docs: upd toctree names in api reference --- docs/source/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index 6facfb8..228c848 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -70,9 +70,9 @@ The worldometer package is divided into several specific sub-packages for each d :maxdepth: 2 worldometer - worldometer.world - worldometer.world.population - worldometer.world.geography + world + population + geography Demo From 98c1838be2878406ae0d1bc4ed1ab7dd5c19b0d8 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 19 Oct 2023 05:42:24 -0300 Subject: [PATCH 120/147] docs: upd documentation config file --- docs/source/conf.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index bd7395f..33a437c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,7 +1,7 @@ # test documentation build configuration file, created by # sphinx-quickstart on Sun Jun 26 00:00:43 2016. # -# This file is executed through importlib.import_module with +# This file is executed through importlib.import_module with # the current directory set to its containing dir. # # Note that not all possible configuration values are present in this @@ -159,7 +159,7 @@ # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # -# html_favicon = './path/to/favicon' +html_favicon = './_static/favicon.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -223,15 +223,15 @@ # If true, links to the reST sources are added to the pages. # -# html_show_sourcelink = True +html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # -# html_show_sphinx = True +html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # -# html_show_copyright = True +html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the @@ -247,7 +247,7 @@ # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr', 'zh' # -# html_search_language = 'en' +html_search_language = 'en' # A dictionary with options for the search language support, empty by default. # 'ja' uses this config value. @@ -356,4 +356,4 @@ # If false, do not generate in manual @ref nodes. # -# texinfo_cross_references = False \ No newline at end of file +# texinfo_cross_references = False From e442aac4bb0fd896a91b1e7f5e5dc33d91208457 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 19 Oct 2023 22:19:34 -0300 Subject: [PATCH 121/147] docs: rename worldometer to api directory and upd index --- docs/source/api/geography.rst | 121 +++++++++++++ docs/source/api/population.rst | 308 ++++++++++++++++++++++++++++++++ docs/source/api/world.rst | 72 ++++++++ docs/source/api/worldometer.rst | 1 + docs/source/index.rst | 8 +- 5 files changed, 506 insertions(+), 4 deletions(-) create mode 100644 docs/source/api/geography.rst create mode 100644 docs/source/api/population.rst create mode 100644 docs/source/api/world.rst create mode 100644 docs/source/api/worldometer.rst diff --git a/docs/source/api/geography.rst b/docs/source/api/geography.rst new file mode 100644 index 0000000..ae25947 --- /dev/null +++ b/docs/source/api/geography.rst @@ -0,0 +1,121 @@ +geography package +================= + +.. contents:: Index + :depth: 2 + +The `geography` package provides access to various data related to geographic information about the world, regions, and their countries. + +To understand the significance of each of these data sets, their sources, and any other related information, please visit the official page at https://www.worldometers.info/geography/how-many-countries-are-there-in-the-world + + +Countries in the world +---------------------- + +.. code-block:: + + >>> from worldometer.world.geography import ( + WorldCountries, + AsiaCountries, + AfricaCountries, + EuropeCountries, + LatinAmericanAndTheCaribbeanCountries, + NorthernAmericanCountries, + OceaniaCountries + ) + + >>> wc = WorldCountries() + + >>> wc.total + 195 + + >>> wc.countries()[0] + WorldCountriesData( + idx=1, + country='India', + population=1428627663, + world_share='17.76 %', + land_area=2973190 + ) + + >>> ac = AfricaCountries() + + >>> ac.total + 54 + + >>> ac.countries()[0] + CountryData( + idx=1, + country='Nigeria', + population=223804632, + subregion='Western Africa' + ) + + >>> ac.dependencies()[0] + DependencyData( + idx=1, + territory='Réunion', + population=981796, + dependency_of='France' + ) + +.. module:: worldometer.world.geography.countries + +.. autoclass:: WorldCountries + :members: + +.. autoclass:: AsiaCountries + :members: + :inherited-members: + +.. autoclass:: AfricaCountries + :members: + :inherited-members: + +.. autoclass:: EuropeCountries + :members: + :inherited-members: + +.. autoclass:: LatinAmericanAndTheCaribbeanCountries + :members: + :inherited-members: + +.. autoclass:: NorthernAmericanCountries + :members: + :inherited-members: + +.. autoclass:: OceaniaCountries + :members: + :inherited-members: + +.. autoclass:: WorldCountriesData +.. autoclass:: CountryData +.. autoclass:: DependencyData + + +Largest countries in the world +------------------------------ + +.. code-block:: + + >>> from worldometer.world.geography import LargestCountries + + >>> lc = LargestCountries() + + >>> lc.data[0] + LargestCountriesData( + idx=1, + country='Russia', + total_area_km2=17098242, + total_area_mi2=6601665, + land_area_km2=16376870, + land_area_mi2=6323142, + percentage_of_world_landmass='11.0 %' + ) + +.. module:: worldometer.world.geography.largest_countries + +.. autoclass:: LargestCountries + :members: + +.. autoclass:: LargestCountriesData diff --git a/docs/source/api/population.rst b/docs/source/api/population.rst new file mode 100644 index 0000000..dc48464 --- /dev/null +++ b/docs/source/api/population.rst @@ -0,0 +1,308 @@ +population package +================== + +.. contents:: Index + :depth: 2 + +The population package provides access to various data related to world populations, regions, and their countries. Additionally, it includes historical data ranging from 1950 to the present day and future projections extending to 2050. + +To understand the significance of each of these data sets, their sources, and any other related information, please visit the official page at https://www.worldometers.info/population + + +Population by country +--------------------- + +.. code-block:: + + >>> from worldometer.world.population import CountriesByPopulation + + >>> cp = CountriesByPopulation() + + >>> cp.data[0] + CountriesByPopulationData( + idx=1, + country='India', + population=1428627663, + yearly_change='0.81 %', + net_change=11454490, + density=481, + land_area=2973190, + migrants=-486136, + fertility_rate=2.0, + median_age=28.0, + urban_population='36 %', + world_share='17.76 %' + ) + +.. module:: worldometer.world.population.countries_by_population + +.. autoclass:: CountriesByPopulation + :members: + +.. autoclass:: CountriesByPopulationData + + +Population by region +-------------------- + +.. code-block:: + + >>> from worldometer.world.population import WorldPopulationByRegion + + >>> pr = WorldPopulationByRegion() + + >>> pr.current()[0] + CurrentWorldPopulationByRegionData( + idx=1, + region='Asia', + population=4753079727, + yearly_change='0.64 %', + net_change=30444963, + density=153, + area=31033131, + migrants=-1487191, + fertility_rate=1.934, + median_age=32, + urban_population='52.6 %', + world_share='59.1 %' + ) + + >>> pr.past()[0] + PastWorldPopulationByRegionData( + idx=1, + region='Asia', + population=1379048370, + world_share='55.2 %' + ) + + >>> pr.future()[0] + FutureWorldPopulationByRegionData( + idx=1, + region='Asia', + population=5292947571, + world_share='54.5 %' + ) + +.. module:: worldometer.world.population.by_region + +.. autoclass:: WorldPopulationByRegion + :members: + +.. autoclass:: CurrentWorldPopulationByRegionData +.. autoclass:: PastWorldPopulationByRegionData +.. autoclass:: FutureWorldPopulationByRegionData + + +Population by year +------------------ + +.. code-block:: + + >>> from worldometer.world.population import WorldPopulationByYear + + >>> py = WorldPopulationByYear() + + >>> py.data[0] + WorldPopulationByYearData( + year=2023, + world_population=8045311447, + yearly_change='0.88 %', + net_change=70206291.0, + density=54.0 + ) + +.. module:: worldometer.world.population.by_year + +.. autoclass:: WorldPopulationByYear + :members: + +.. autoclass:: WorldPopulationByYearData + + +Largest cities in the world +--------------------------- + +.. code-block:: + + >>> from worldometer.world.population import LargestCities + + >>> lc = LargestCities() + + >>> lc.data[0] + LargestCitiesData( + rank=1, + urban_area='Tokyo-Yokohama', + population_estimate=37843000, + country='Japan', + land_area=8547, + density=4400 + ) + +.. module:: worldometer.world.population.largest_cities + +.. autoclass:: LargestCities + :members: + +.. autoclass:: LargestCitiesData + + +Most populous countries +----------------------- + +.. code-block:: + + >>> from worldometer.world.population import MostPopulousCountries + + >>> pc = MostPopulousCountries() + + >>> pc.current()[0] + CurrentMostPopulousCountriesData( + idx=1, + country='India', + population=1428627663, + yearly_change='0.81 %', + world_share='17.8 %' + ) + + >>> pc.past()[0] + PastMostPopulousCountriesData( + idx=1, + country='China', + population=543979233, + world_share='21.8 %', + rank='(2)' + ) + + >>> pc.future()[0] + FutureMostPopulousCountriesData( + idx=1, + country='India', + population=1670490596, + world_share='17.2 %', + rank='(1)' + ) + +.. module:: worldometer.world.population.most_populous_countries + +.. autoclass:: MostPopulousCountries + :members: + +.. autoclass:: CurrentMostPopulousCountriesData +.. autoclass:: PastMostPopulousCountriesData +.. autoclass:: FutureMostPopulousCountriesData + + +World population projections +---------------------------- + +.. code-block:: + + >>> from worldometer.world.population import WorldPopulationProjections + + >>> pp = WorldPopulationProjections() + + >>> pp.data[0] + WorldPopulationProjectionsData( + year=2023, + world_population=8045311447, + yearly_change='0.88 %', + net_change=70206291, + density=54 + ) + +.. module:: worldometer.world.population.projections + +.. autoclass:: WorldPopulationProjections + :members: + +.. autoclass:: WorldPopulationProjectionsData + + +Regions population +------------------ + +.. code-block:: + + >>> from worldometer.world.population import ( + AsiaPopulation, + AfricaPopulation, + EuropePopulation, + LatinAmericanAndTheCaribbeanPopulation, + NorthernAmericanPopulation, + OceaniaPopulation + ) + + >>> ap = AsiaPopulation() + + >>> ap.live() + 4762699828 + + >>> ap.subregions()[0] + SubregionData( + area='Southern Asia', + population='(2,027,578,876)' + ) + + >>> ap.historical()[0] + HistoricalData( + year=2023, + population=4753079727, + yearly_change_percent='0.64 %', + yearly_change=30444963, + migrants=-1487191, + median_age=31.9, + fertility_rate=1.93, + density=153, + urban_population_percent='52.6 %', + urban_population=2500201501, + world_share='59.1 %', + world_population=8045311447, + rank=nan + ) + + >>> ap.forecast()[0] + ForecastData( + year=2025, + population=4816249054, + yearly_change_percent='0.64 %', + yearly_change=30384996, + migrants=-1555419, + median_age=32.7, + fertility_rate=1.93, + density=155, + urban_population_percent='53.8 %', + urban_population=2589655469, + world_share='61.4 %', + world_population=8191988453, + rank=nan + ) + +.. module:: worldometer.world.population.regions + +.. autoclass:: AsiaPopulation + :members: + :inherited-members: + +.. autoclass:: AfricaPopulation + :members: + :inherited-members: + +.. autoclass:: EuropePopulation + :members: + :inherited-members: + +.. autoclass:: LatinAmericanAndTheCaribbeanPopulation + :members: + :inherited-members: + +.. autoclass:: NorthernAmericanPopulation + :members: + :inherited-members: + +.. autoclass:: OceaniaPopulation + :members: + :inherited-members: + +.. autoclass:: SubregionData +.. autoclass:: HistoricalData +.. autoclass:: ForecastData diff --git a/docs/source/api/world.rst b/docs/source/api/world.rst new file mode 100644 index 0000000..d5ac904 --- /dev/null +++ b/docs/source/api/world.rst @@ -0,0 +1,72 @@ +world package +============= + +.. contents:: Index + :depth: 2 + +`world` is the main API of the `worldometer` package, where you can access various live counters and data available on the https://www.worldometers.info website through self-descriptive classes, methods, and attributes. + + +Live Counters +------------- + +.. module:: worldometer.world.counters + + +Get the data provided by the live counters. + +Each section is represented by an attribute in the :class:`WorldCounters` class, and these attributes are instances of data classes that store the counter values. + +Each of these data classes has attributes that describe the data stored in them. + +.. code-block:: + + >>> from worldometer.world import WorldCounters + + >>> wc = WorldCounters() + + >>> wc.world_population.current_population + 8065299074 + + >>> wc.government_and_economics.computers_produced_this_year + 180248430 + + >>> wc.society_and_media.internet_users_in_the_world_today + 5895566559 + +.. autoclass:: WorldCounters + +.. autoclass:: WorldPopulation +.. autoclass:: GovernmentAndEconomics +.. autoclass:: SocietyAndMedia +.. autoclass:: Environment +.. autoclass:: Food +.. autoclass:: Water +.. autoclass:: Energy +.. autoclass:: Health + + +Country Codes +------------- + +.. module:: worldometer.world.country_codes + +All countries have specific codes that represent them in some way. Get all of these codes with the :class:`CountryCodes` class:: + + >>> from worldometer.world import CountryCodes + + >>> cc = CountryCodes() + + >>> cc.data[0] + CountryCodesData( + country='Afghanistan', + calling_code='93', + three_letter_iso='AF', + two_letter_iso='AFG', + three_digit_iso_numeric=4 + ) + +.. autoclass:: CountryCodes + :members: + +.. autoclass:: CountryCodesData diff --git a/docs/source/api/worldometer.rst b/docs/source/api/worldometer.rst new file mode 100644 index 0000000..ee31f0b --- /dev/null +++ b/docs/source/api/worldometer.rst @@ -0,0 +1 @@ +.. automodule:: worldometer diff --git a/docs/source/index.rst b/docs/source/index.rst index 228c848..35b3ec5 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -69,10 +69,10 @@ The worldometer package is divided into several specific sub-packages for each d .. toctree:: :maxdepth: 2 - worldometer - world - population - geography + worldometer + world + population + geography Demo From 1055610bc6bdab9eb91d77d4fb12e379bbf0995b Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Thu, 19 Oct 2023 22:47:13 -0300 Subject: [PATCH 122/147] chore: upd .readthedocs.yml file --- .readthedocs.yml | 5 +- docs/source/worldometer/geography.rst | 121 ---------- docs/source/worldometer/index.rst | 1 - docs/source/worldometer/population.rst | 308 ------------------------- docs/source/worldometer/world.rst | 72 ------ docs/source/worldometer_api.rst | 2 - docs/source/worldometer_core.rst | 2 - 7 files changed, 3 insertions(+), 508 deletions(-) delete mode 100644 docs/source/worldometer/geography.rst delete mode 100644 docs/source/worldometer/index.rst delete mode 100644 docs/source/worldometer/population.rst delete mode 100644 docs/source/worldometer/world.rst delete mode 100644 docs/source/worldometer_api.rst delete mode 100644 docs/source/worldometer_core.rst diff --git a/.readthedocs.yml b/.readthedocs.yml index 96244df..dc540c2 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -7,7 +7,9 @@ version: 2 # Select the Docker image used for building the docs. build: - image: latest + os: ubuntu-22.04 + tools: + python: "3.8" # Build documentation in the docs/ directory with Sphinx sphinx: @@ -20,6 +22,5 @@ formats: all # Configure python for install requirements python: - version: 3.8 install: - requirements: docs/docs_requirements.txt diff --git a/docs/source/worldometer/geography.rst b/docs/source/worldometer/geography.rst deleted file mode 100644 index ae25947..0000000 --- a/docs/source/worldometer/geography.rst +++ /dev/null @@ -1,121 +0,0 @@ -geography package -================= - -.. contents:: Index - :depth: 2 - -The `geography` package provides access to various data related to geographic information about the world, regions, and their countries. - -To understand the significance of each of these data sets, their sources, and any other related information, please visit the official page at https://www.worldometers.info/geography/how-many-countries-are-there-in-the-world - - -Countries in the world ----------------------- - -.. code-block:: - - >>> from worldometer.world.geography import ( - WorldCountries, - AsiaCountries, - AfricaCountries, - EuropeCountries, - LatinAmericanAndTheCaribbeanCountries, - NorthernAmericanCountries, - OceaniaCountries - ) - - >>> wc = WorldCountries() - - >>> wc.total - 195 - - >>> wc.countries()[0] - WorldCountriesData( - idx=1, - country='India', - population=1428627663, - world_share='17.76 %', - land_area=2973190 - ) - - >>> ac = AfricaCountries() - - >>> ac.total - 54 - - >>> ac.countries()[0] - CountryData( - idx=1, - country='Nigeria', - population=223804632, - subregion='Western Africa' - ) - - >>> ac.dependencies()[0] - DependencyData( - idx=1, - territory='Réunion', - population=981796, - dependency_of='France' - ) - -.. module:: worldometer.world.geography.countries - -.. autoclass:: WorldCountries - :members: - -.. autoclass:: AsiaCountries - :members: - :inherited-members: - -.. autoclass:: AfricaCountries - :members: - :inherited-members: - -.. autoclass:: EuropeCountries - :members: - :inherited-members: - -.. autoclass:: LatinAmericanAndTheCaribbeanCountries - :members: - :inherited-members: - -.. autoclass:: NorthernAmericanCountries - :members: - :inherited-members: - -.. autoclass:: OceaniaCountries - :members: - :inherited-members: - -.. autoclass:: WorldCountriesData -.. autoclass:: CountryData -.. autoclass:: DependencyData - - -Largest countries in the world ------------------------------- - -.. code-block:: - - >>> from worldometer.world.geography import LargestCountries - - >>> lc = LargestCountries() - - >>> lc.data[0] - LargestCountriesData( - idx=1, - country='Russia', - total_area_km2=17098242, - total_area_mi2=6601665, - land_area_km2=16376870, - land_area_mi2=6323142, - percentage_of_world_landmass='11.0 %' - ) - -.. module:: worldometer.world.geography.largest_countries - -.. autoclass:: LargestCountries - :members: - -.. autoclass:: LargestCountriesData diff --git a/docs/source/worldometer/index.rst b/docs/source/worldometer/index.rst deleted file mode 100644 index ee31f0b..0000000 --- a/docs/source/worldometer/index.rst +++ /dev/null @@ -1 +0,0 @@ -.. automodule:: worldometer diff --git a/docs/source/worldometer/population.rst b/docs/source/worldometer/population.rst deleted file mode 100644 index dc48464..0000000 --- a/docs/source/worldometer/population.rst +++ /dev/null @@ -1,308 +0,0 @@ -population package -================== - -.. contents:: Index - :depth: 2 - -The population package provides access to various data related to world populations, regions, and their countries. Additionally, it includes historical data ranging from 1950 to the present day and future projections extending to 2050. - -To understand the significance of each of these data sets, their sources, and any other related information, please visit the official page at https://www.worldometers.info/population - - -Population by country ---------------------- - -.. code-block:: - - >>> from worldometer.world.population import CountriesByPopulation - - >>> cp = CountriesByPopulation() - - >>> cp.data[0] - CountriesByPopulationData( - idx=1, - country='India', - population=1428627663, - yearly_change='0.81 %', - net_change=11454490, - density=481, - land_area=2973190, - migrants=-486136, - fertility_rate=2.0, - median_age=28.0, - urban_population='36 %', - world_share='17.76 %' - ) - -.. module:: worldometer.world.population.countries_by_population - -.. autoclass:: CountriesByPopulation - :members: - -.. autoclass:: CountriesByPopulationData - - -Population by region --------------------- - -.. code-block:: - - >>> from worldometer.world.population import WorldPopulationByRegion - - >>> pr = WorldPopulationByRegion() - - >>> pr.current()[0] - CurrentWorldPopulationByRegionData( - idx=1, - region='Asia', - population=4753079727, - yearly_change='0.64 %', - net_change=30444963, - density=153, - area=31033131, - migrants=-1487191, - fertility_rate=1.934, - median_age=32, - urban_population='52.6 %', - world_share='59.1 %' - ) - - >>> pr.past()[0] - PastWorldPopulationByRegionData( - idx=1, - region='Asia', - population=1379048370, - world_share='55.2 %' - ) - - >>> pr.future()[0] - FutureWorldPopulationByRegionData( - idx=1, - region='Asia', - population=5292947571, - world_share='54.5 %' - ) - -.. module:: worldometer.world.population.by_region - -.. autoclass:: WorldPopulationByRegion - :members: - -.. autoclass:: CurrentWorldPopulationByRegionData -.. autoclass:: PastWorldPopulationByRegionData -.. autoclass:: FutureWorldPopulationByRegionData - - -Population by year ------------------- - -.. code-block:: - - >>> from worldometer.world.population import WorldPopulationByYear - - >>> py = WorldPopulationByYear() - - >>> py.data[0] - WorldPopulationByYearData( - year=2023, - world_population=8045311447, - yearly_change='0.88 %', - net_change=70206291.0, - density=54.0 - ) - -.. module:: worldometer.world.population.by_year - -.. autoclass:: WorldPopulationByYear - :members: - -.. autoclass:: WorldPopulationByYearData - - -Largest cities in the world ---------------------------- - -.. code-block:: - - >>> from worldometer.world.population import LargestCities - - >>> lc = LargestCities() - - >>> lc.data[0] - LargestCitiesData( - rank=1, - urban_area='Tokyo-Yokohama', - population_estimate=37843000, - country='Japan', - land_area=8547, - density=4400 - ) - -.. module:: worldometer.world.population.largest_cities - -.. autoclass:: LargestCities - :members: - -.. autoclass:: LargestCitiesData - - -Most populous countries ------------------------ - -.. code-block:: - - >>> from worldometer.world.population import MostPopulousCountries - - >>> pc = MostPopulousCountries() - - >>> pc.current()[0] - CurrentMostPopulousCountriesData( - idx=1, - country='India', - population=1428627663, - yearly_change='0.81 %', - world_share='17.8 %' - ) - - >>> pc.past()[0] - PastMostPopulousCountriesData( - idx=1, - country='China', - population=543979233, - world_share='21.8 %', - rank='(2)' - ) - - >>> pc.future()[0] - FutureMostPopulousCountriesData( - idx=1, - country='India', - population=1670490596, - world_share='17.2 %', - rank='(1)' - ) - -.. module:: worldometer.world.population.most_populous_countries - -.. autoclass:: MostPopulousCountries - :members: - -.. autoclass:: CurrentMostPopulousCountriesData -.. autoclass:: PastMostPopulousCountriesData -.. autoclass:: FutureMostPopulousCountriesData - - -World population projections ----------------------------- - -.. code-block:: - - >>> from worldometer.world.population import WorldPopulationProjections - - >>> pp = WorldPopulationProjections() - - >>> pp.data[0] - WorldPopulationProjectionsData( - year=2023, - world_population=8045311447, - yearly_change='0.88 %', - net_change=70206291, - density=54 - ) - -.. module:: worldometer.world.population.projections - -.. autoclass:: WorldPopulationProjections - :members: - -.. autoclass:: WorldPopulationProjectionsData - - -Regions population ------------------- - -.. code-block:: - - >>> from worldometer.world.population import ( - AsiaPopulation, - AfricaPopulation, - EuropePopulation, - LatinAmericanAndTheCaribbeanPopulation, - NorthernAmericanPopulation, - OceaniaPopulation - ) - - >>> ap = AsiaPopulation() - - >>> ap.live() - 4762699828 - - >>> ap.subregions()[0] - SubregionData( - area='Southern Asia', - population='(2,027,578,876)' - ) - - >>> ap.historical()[0] - HistoricalData( - year=2023, - population=4753079727, - yearly_change_percent='0.64 %', - yearly_change=30444963, - migrants=-1487191, - median_age=31.9, - fertility_rate=1.93, - density=153, - urban_population_percent='52.6 %', - urban_population=2500201501, - world_share='59.1 %', - world_population=8045311447, - rank=nan - ) - - >>> ap.forecast()[0] - ForecastData( - year=2025, - population=4816249054, - yearly_change_percent='0.64 %', - yearly_change=30384996, - migrants=-1555419, - median_age=32.7, - fertility_rate=1.93, - density=155, - urban_population_percent='53.8 %', - urban_population=2589655469, - world_share='61.4 %', - world_population=8191988453, - rank=nan - ) - -.. module:: worldometer.world.population.regions - -.. autoclass:: AsiaPopulation - :members: - :inherited-members: - -.. autoclass:: AfricaPopulation - :members: - :inherited-members: - -.. autoclass:: EuropePopulation - :members: - :inherited-members: - -.. autoclass:: LatinAmericanAndTheCaribbeanPopulation - :members: - :inherited-members: - -.. autoclass:: NorthernAmericanPopulation - :members: - :inherited-members: - -.. autoclass:: OceaniaPopulation - :members: - :inherited-members: - -.. autoclass:: SubregionData -.. autoclass:: HistoricalData -.. autoclass:: ForecastData diff --git a/docs/source/worldometer/world.rst b/docs/source/worldometer/world.rst deleted file mode 100644 index d5ac904..0000000 --- a/docs/source/worldometer/world.rst +++ /dev/null @@ -1,72 +0,0 @@ -world package -============= - -.. contents:: Index - :depth: 2 - -`world` is the main API of the `worldometer` package, where you can access various live counters and data available on the https://www.worldometers.info website through self-descriptive classes, methods, and attributes. - - -Live Counters -------------- - -.. module:: worldometer.world.counters - - -Get the data provided by the live counters. - -Each section is represented by an attribute in the :class:`WorldCounters` class, and these attributes are instances of data classes that store the counter values. - -Each of these data classes has attributes that describe the data stored in them. - -.. code-block:: - - >>> from worldometer.world import WorldCounters - - >>> wc = WorldCounters() - - >>> wc.world_population.current_population - 8065299074 - - >>> wc.government_and_economics.computers_produced_this_year - 180248430 - - >>> wc.society_and_media.internet_users_in_the_world_today - 5895566559 - -.. autoclass:: WorldCounters - -.. autoclass:: WorldPopulation -.. autoclass:: GovernmentAndEconomics -.. autoclass:: SocietyAndMedia -.. autoclass:: Environment -.. autoclass:: Food -.. autoclass:: Water -.. autoclass:: Energy -.. autoclass:: Health - - -Country Codes -------------- - -.. module:: worldometer.world.country_codes - -All countries have specific codes that represent them in some way. Get all of these codes with the :class:`CountryCodes` class:: - - >>> from worldometer.world import CountryCodes - - >>> cc = CountryCodes() - - >>> cc.data[0] - CountryCodesData( - country='Afghanistan', - calling_code='93', - three_letter_iso='AF', - two_letter_iso='AFG', - three_digit_iso_numeric=4 - ) - -.. autoclass:: CountryCodes - :members: - -.. autoclass:: CountryCodesData diff --git a/docs/source/worldometer_api.rst b/docs/source/worldometer_api.rst deleted file mode 100644 index 270cd4d..0000000 --- a/docs/source/worldometer_api.rst +++ /dev/null @@ -1,2 +0,0 @@ -.. automodule:: worldometer.api - :members: diff --git a/docs/source/worldometer_core.rst b/docs/source/worldometer_core.rst deleted file mode 100644 index 14f656c..0000000 --- a/docs/source/worldometer_core.rst +++ /dev/null @@ -1,2 +0,0 @@ -.. automodule:: worldometer.core - :members: From 9cbf6e324d351587d568113c1312c6e4aaefc883 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Fri, 20 Oct 2023 00:13:30 -0300 Subject: [PATCH 123/147] chore: add sphinx.ext.duration extension in conf.py file --- docs/source/conf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 33a437c..cff9b3e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -29,7 +29,8 @@ # ones. extensions = [ 'sphinx.ext.autodoc', - 'sphinx.ext.napoleon' + 'sphinx.ext.napoleon', + 'sphinx.ext.duration' ] # Add any paths that contain templates here, relative to this directory. From 0888a699970cdc890ee0ec7a7d20c5a59e68bbd5 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Fri, 20 Oct 2023 03:27:45 -0300 Subject: [PATCH 124/147] fix: use absolute and explicit imports from the old api resolve #12 --- worldometer/__init__.py | 143 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 137 insertions(+), 6 deletions(-) diff --git a/worldometer/__init__.py b/worldometer/__init__.py index 9d89213..6684d21 100644 --- a/worldometer/__init__.py +++ b/worldometer/__init__.py @@ -40,11 +40,142 @@ """ __all__ = [ - 'core', - 'api' + 'Worldometer', + 'get_metric_of', + 'update_metrics', + 'current_world_population', + 'births_this_year', + 'births_today', + 'deaths_this_year', + 'deaths_today', + 'net_population_growth_this_year', + 'net_population_growth_today', + 'public_healthcare_expenditure_today', + 'public_education_expenditure_today', + 'public_military_expenditure_today', + 'cars_produced_this_year', + 'bicycles_produced_this_year', + 'computers_produced_this_year', + 'new_book_titles_published_this_year', + 'newspapers_circulated_today', + 'tv_sets_sold_worldwide_today', + 'cellular_phones_sold_today', + 'money_spent_on_videogames_today', + 'internet_users_in_the_world_today', + 'emails_sent_today', + 'blog_posts_written_today', + 'tweets_sent_today', + 'google_searches_today', + 'forest_loss_this_year', + 'land_lost_to_soil_erosion_this_year', + 'co2_emissions_this_year', + 'desertification_this_year', + 'toxic_chemicals_released_in_the_environment_this_year', + 'undernourished_people_in_the_world', + 'overweight_people_in_the_world', + 'obese_people_in_the_world', + 'people_who_died_of_hunger_today', + 'money_spent_for_obesity_related_diseases_in_the_usa_today', + 'money_spent_on_weight_loss_programs_in_the_usa_today', + 'water_used_this_year', + 'deaths_caused_by_water_related_diseases_this_year', + 'people_with_no_access_to_a_safe_drinking_water_source', + 'energy_used_today', + 'non_renewable_sources', + 'renewable_sources', + 'solar_energy_striking_earth_today', + 'oil_pumped_today', + 'oil_left', + 'days_to_the_end_of_oil', + 'natural_gas_left', + 'days_to_the_end_of_natural_gas', + 'coal_left', + 'days_to_the_end_of_coal', + 'communicable_disease_deaths_this_year', + 'seasonal_flu_deaths_this_year', + 'deaths_of_children_under_5_this_year', + 'abortions_this_year', + 'deaths_of_mothers_during_birth_this_year', + 'hiv_aids_infected_people', + 'deaths_caused_by_hiv_aids_this_year', + 'deaths_caused_by_cancer_this_year', + 'deaths_caused_by_malaria_this_year', + 'cigarettes_smoked_today', + 'deaths_caused_by_smoking_this_year', + 'deaths_caused_by_alcohol_this_year', + 'suicides_this_year', + 'money_spent_on_illegal_drugs_this_year', + 'road_traffic_accident_fatalities_this_year' ] -from .__about__ import __version__, __author__, __email__ - -from .core import Worldometer -from .api import * +# TODO: The worldometer.core module is deprecated. +# TODO: The old API (worldometer.api) is deprecated. +# This will be removed in the future. +from worldometer.core import Worldometer +from worldometer.api import ( + get_metric_of, + update_metrics, + current_world_population, + births_this_year, + births_today, + deaths_this_year, + deaths_today, + net_population_growth_this_year, + net_population_growth_today, + public_healthcare_expenditure_today, + public_education_expenditure_today, + public_military_expenditure_today, + cars_produced_this_year, + bicycles_produced_this_year, + computers_produced_this_year, + new_book_titles_published_this_year, + newspapers_circulated_today, + tv_sets_sold_worldwide_today, + cellular_phones_sold_today, + money_spent_on_videogames_today, + internet_users_in_the_world_today, + emails_sent_today, + blog_posts_written_today, + tweets_sent_today, + google_searches_today, + forest_loss_this_year, + land_lost_to_soil_erosion_this_year, + co2_emissions_this_year, + desertification_this_year, + toxic_chemicals_released_in_the_environment_this_year, + undernourished_people_in_the_world, + overweight_people_in_the_world, + obese_people_in_the_world, + people_who_died_of_hunger_today, + money_spent_for_obesity_related_diseases_in_the_usa_today, + money_spent_on_weight_loss_programs_in_the_usa_today, + water_used_this_year, + deaths_caused_by_water_related_diseases_this_year, + people_with_no_access_to_a_safe_drinking_water_source, + energy_used_today, + non_renewable_sources, + renewable_sources, + solar_energy_striking_earth_today, + oil_pumped_today, + oil_left, + days_to_the_end_of_oil, + natural_gas_left, + days_to_the_end_of_natural_gas, + coal_left, + days_to_the_end_of_coal, + communicable_disease_deaths_this_year, + seasonal_flu_deaths_this_year, + deaths_of_children_under_5_this_year, + abortions_this_year, + deaths_of_mothers_during_birth_this_year, + hiv_aids_infected_people, + deaths_caused_by_hiv_aids_this_year, + deaths_caused_by_cancer_this_year, + deaths_caused_by_malaria_this_year, + cigarettes_smoked_today, + deaths_caused_by_smoking_this_year, + deaths_caused_by_alcohol_this_year, + suicides_this_year, + money_spent_on_illegal_drugs_this_year, + road_traffic_accident_fatalities_this_year +) From 3ff8192e7e9955875e12e42fb2af3c2a73ed0c26 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Fri, 20 Oct 2023 20:50:42 -0300 Subject: [PATCH 125/147] fix: use the new API within the old API This will be maintained until the complete removal of the old API. --- worldometer/api.py | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/worldometer/api.py b/worldometer/api.py index e4c75ab..9d1bd0a 100644 --- a/worldometer/api.py +++ b/worldometer/api.py @@ -99,18 +99,14 @@ 'road_traffic_accident_fatalities_this_year' ] +from dataclasses import asdict -from .core import Worldometer - -from .__about__ import __version__, __author__, __email__ - - -__w = Worldometer() +from worldometer.world import WorldCounters def get_metric_of(label: str) -> dict: """Get metric of label specified. - + Parameters ---------- label @@ -126,8 +122,18 @@ def get_metric_of(label: str) -> dict: >>> get_metric_of(label='current_world_population') {'current_world_population': 7845085923} """ - - metrics = __w.metrics_with_labels() + wc = WorldCounters() + + metrics = { + **asdict(wc.world_population), + **asdict(wc.government_and_economics), + **asdict(wc.society_and_media), + **asdict(wc.environment), + **asdict(wc.food), + **asdict(wc.water), + **asdict(wc.energy), + **asdict(wc.health) + } if label not in metrics: raise Exception(f'This label "{label}" is invalid, please use a valid label.') @@ -137,13 +143,11 @@ def get_metric_of(label: str) -> dict: def update_metrics() -> None: """Update metrics of worldometer.""" - - __w.update_metrics() def current_world_population() -> dict: """Get number of current world population.""" - return get_metric_of(label='current_world_population') + return get_metric_of(label='current_population') def births_this_year() -> dict: @@ -333,7 +337,7 @@ def energy_used_today() -> dict: def non_renewable_sources() -> dict: """Get number of non renewable sources.""" - return get_metric_of(label='non-renewable_sources') + return get_metric_of(label='non_renewable_sources') def renewable_sources() -> dict: @@ -408,12 +412,12 @@ def deaths_of_mothers_during_birth_this_year() -> dict: def hiv_aids_infected_people() -> dict: """Get number of hiv aids infected people.""" - return get_metric_of(label='hiv/aids_infected_people') + return get_metric_of(label='hiv_aids_infected_people') def deaths_caused_by_hiv_aids_this_year() -> dict: """Get number of deaths caused by hiv aids this year.""" - return get_metric_of(label='deaths_caused_by_hiv/aids_this_year') + return get_metric_of(label='deaths_caused_by_hiv_aids_this_year') def deaths_caused_by_cancer_this_year() -> dict: From e59d7c8d0abf657a8e14eed445ffde3d2915c98a Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Fri, 20 Oct 2023 21:01:32 -0300 Subject: [PATCH 126/147] style: remove blank space --- worldometer/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldometer/api.py b/worldometer/api.py index 9d1bd0a..89d39e8 100644 --- a/worldometer/api.py +++ b/worldometer/api.py @@ -19,7 +19,7 @@ {'computers_produced_this_year': 27760858} There is also a simplified and self-explanatory API that provides -functions corresponding to the labels. +functions corresponding to the labels. Autocomplete tools from the editors/IDE will help you use these functions without having to decorate all labels: From eb9e53d150125308ee9e9e8329e32aeaf73360d7 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Fri, 20 Oct 2023 22:13:08 -0300 Subject: [PATCH 127/147] fix: use the new API in the old core module Some functionalities in the core module were broken. Using the new API internally to collect the used metrics solves the problems. This will be maintained until the complete removal of this module in a future version. --- resolve #13 resolve #18 resolve #20 resolve #21 --- worldometer/core.py | 147 +++++++++++++++----------------------------- 1 file changed, 49 insertions(+), 98 deletions(-) diff --git a/worldometer/core.py b/worldometer/core.py index 042cf6b..d749162 100644 --- a/worldometer/core.py +++ b/worldometer/core.py @@ -24,7 +24,7 @@ Get all metrics with labels in dict format: >>> w.metrics_with_labels() -{ +{ 'abortions_this_year': 4785492, 'bicycles_produced_this_year': 17070566, 'births_this_year': 15741371, @@ -38,20 +38,12 @@ __all__ = ['Worldometer'] -from .__about__ import __version__, __author__, __email__ - -import re - -from requests_html import HTML, HTMLSession - +from worldometer.world import WorldCounters # Constant variables, used in the Worldometer module. URL = 'https://www.worldometers.info/' -_CSS_SELECTOR_OF_COUNTER_NUMBERS = '.counter-number' -_CSS_SELECTOR_OF_COUNTER_ITEM = '.counter-item, .counter-item-double' - _METRICS_LABELS = { 'world_population': [ 'current_world_population', @@ -138,7 +130,7 @@ class Worldometer(object): """This is the core class of the worldometer module. - All functions/methods of the worldometer module use + All functions/methods of the worldometer module use this class to build a Worldometer Object to access the collected data. Get more info about its attributes/methods using the ``help`` function: @@ -161,33 +153,30 @@ class Worldometer(builtins.object) | ---------- | timeout | Seconds of wait for processing. - | + | | (...) """ def __init__(self, timeout: int = 30): """Initializer of Worldometer class. - + Parameters ---------- timeout Seconds of wait for processing. """ - self.__r = None # Stores the response with html code for later rendering self.__timeout = timeout self._metrics = self.collect_metrics() - - def __str__(self): + def __str__(self): c, l, m = self.what_is_here().values() return f'Worldometer has {c} categories, {l} labels and {m} metrics' def __repr__(self): - c, l, m = self.what_is_here().values() return ( @@ -197,7 +186,7 @@ def __repr__(self): def metrics(self) -> list: """Get all metrics of worldometer. - + Returns ------- list @@ -208,7 +197,7 @@ def metrics(self) -> list: >>> from worldometer import Worldometer >>> w = Worldometer() >>> w.metrics() - [ + [ 7845087963, 15741371, 5676, @@ -218,75 +207,43 @@ def metrics(self) -> list: ... ] """ - return self._metrics.copy() - def _get_html(self, url: str) -> str: + def _get_html(self, url: str) -> None: """Get the html code from the specified url and return its rendered content. """ - session = HTMLSession() - - try: - # Get html page and render dynamic content - self.__r = session.get(url, timeout=self.__timeout) - self.__r.html.render(timeout=self.__timeout) - - return self.__r.html.raw_html - - except Exception as err: - raise Exception(err) - @staticmethod - def find_metrics_in_html(html_code: str) -> list: + def find_metrics_in_html(html_code: str) -> None: """Find worldometer metrics in html code. - + Parameters ---------- html_code Receive html code. - + Returns ------- list A list of not sanitized metrics of str type. """ - html = HTML(html=html_code) - - # Get only text of all requests_html.Element object - metrics = [metric.text for metric in html.find(_CSS_SELECTOR_OF_COUNTER_NUMBERS)] - - return metrics - @staticmethod - def sanitize_metrics(metric_list: list) -> list: + def sanitize_metrics(metric_list: list) -> None: """Sanitize all metrics in list. - + Parameters ---------- metric_list Receive list of metrics in str type. - + Returns ------- list A list of sanitized metrics of int type. """ - sanitized_metrics = [] - - for metric in metric_list: - - # Get only the number and convert to int - found = re.search(r'[0-9,]+', metric).group() - number = int(found.replace(',', '')) - - sanitized_metrics.append(number) - - return sanitized_metrics - def collect_metrics(self) -> list: """Collects all metrics from the worldometer site. @@ -295,30 +252,32 @@ def collect_metrics(self) -> list: list A list of metrics of int type. """ + wc = WorldCounters() + + metrics = { + **wc.world_population.__dict__, + **wc.government_and_economics.__dict__, + **wc.society_and_media.__dict__, + **wc.environment.__dict__, + **wc.food.__dict__, + **wc.water.__dict__, + **wc.energy.__dict__, + **wc.health.__dict__ + } + metrics.pop('_data') - if self.__r is None: - html = self._get_html(url=URL) - else: - html = self.__r.html.raw_html - - metrics = self.find_metrics_in_html(html_code=html) - sanitized_metrics = self.sanitize_metrics(metric_list=metrics) + metrics_values = list(metrics.values()) - return sanitized_metrics + return metrics_values def update_metrics(self) -> None: """Update metrics of worldometer.""" - - if self.__r is not None: - self.__r.html.render(timeout=self.__timeout) - self._metrics = self.collect_metrics() - else: - raise Exception('There are no metrics. Collect them to update.') + self._metrics = self.collect_metrics() @staticmethod def metrics_labels(with_categories=False) -> list: """Return metrics labels of worldometer. - + Parameters ---------- with_categories @@ -328,7 +287,7 @@ def metrics_labels(with_categories=False) -> list: ------- list A list of labels if ``with_categories`` parameter is False. - + A dict of labels with categories if ``with_categories`` parameter is True. Example @@ -336,7 +295,7 @@ def metrics_labels(with_categories=False) -> list: >>> from worldometer import Worldometer >>> w = Worldometer() >>> w.metrics_labels() - [ + [ 'current_world_population', 'births_this_year', 'births_today', @@ -346,9 +305,8 @@ def metrics_labels(with_categories=False) -> list: ... ] """ - if with_categories: - return _METRICS_LABELS + return _METRICS_LABELS # type: ignore only_metrics = [] for metrics in _METRICS_LABELS.values(): @@ -359,7 +317,7 @@ def metrics_labels(with_categories=False) -> list: @staticmethod def categories() -> list: """Return categories of worldometer. - + Returns ------- list @@ -370,19 +328,18 @@ def categories() -> list: >>> from worldometer import Worldometer >>> w = Worldometer() >>> w.categories() - [ + [ 'world_population', 'government_and_economics', 'society_and_media', ... ] """ - return [category for category in _METRICS_LABELS.keys()] def metrics_with_labels(self, with_categories: bool = False) -> dict: """Return metrics with labels in key-value structure. - + Parameters ---------- with_categories @@ -398,7 +355,7 @@ def metrics_with_labels(self, with_categories: bool = False) -> dict: >>> from worldometer import Worldometer >>> w = Worldometer() >>> w.metrics_with_labels() - { + { 'abortions_this_year': 4785492, 'bicycles_produced_this_year': 17070566, 'births_this_year': 15741371, @@ -409,11 +366,10 @@ def metrics_with_labels(self, with_categories: bool = False) -> dict: ...: ... } """ - metrics = self.metrics() if with_categories: - + m_with_l = {} # Storage all structure of metrics with labels metrics_labels = self.metrics_labels(with_categories=True).copy() @@ -424,29 +380,29 @@ def metrics_with_labels(self, with_categories: bool = False) -> dict: for label in metrics_labels[category]: - # Storage of a metric on the key label as the index + # Storage of a metric on the key label as the index # increases +1 to iterate through the entire list of metrics m_with_l[category][label] = metrics[idx] idx += 1 - + return m_with_l else: - + labels = self.metrics_labels().copy() - + return dict( zip(labels, metrics) ) def what_is_here(self) -> dict: """Return what is here in object. - + Returns ------- dict Number of categories, labels and metrics. - + Example ------- >>> from worldometer import Worldometer @@ -454,13 +410,8 @@ def what_is_here(self) -> dict: >>> w.what_is_here() {'categories': 8, 'labels': 63, 'metrics': 63} """ - - c = len(self.categories()) - l = len(self.metrics_labels()) - m = len(self.metrics()) - return { - 'categories': c, - 'labels': l, - 'metrics': m + 'categories': len(self.categories()), + 'labels': len(self.metrics_labels()), + 'metrics': len(self.metrics()) } From d340bdf40773e5e3855581da261b76b3feacbb8f Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Fri, 20 Oct 2023 22:35:32 -0300 Subject: [PATCH 128/147] fix: update label names according to the new api --- worldometer/core.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/worldometer/core.py b/worldometer/core.py index d749162..f3d4df9 100644 --- a/worldometer/core.py +++ b/worldometer/core.py @@ -46,7 +46,7 @@ _METRICS_LABELS = { 'world_population': [ - 'current_world_population', + 'current_population', 'births_this_year', 'births_today', 'deaths_this_year', @@ -96,7 +96,7 @@ ], 'energy': [ 'energy_used_today', - 'non-renewable_sources', + 'non_renewable_sources', 'renewable_sources', 'solar_energy_striking_earth_today', 'oil_pumped_today', @@ -113,8 +113,8 @@ 'deaths_of_children_under_5_this_year', 'abortions_this_year', 'deaths_of_mothers_during_birth_this_year', - 'hiv/aids_infected_people', - 'deaths_caused_by_hiv/aids_this_year', + 'hiv_aids_infected_people', + 'deaths_caused_by_hiv_aids_this_year', 'deaths_caused_by_cancer_this_year', 'deaths_caused_by_malaria_this_year', 'cigarettes_smoked_today', From f531cc76bed33dcf7ae2ec0c87d09fedd62dad1f Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Fri, 20 Oct 2023 22:51:14 -0300 Subject: [PATCH 129/147] refactor: Use the core module's class in the simplified API Instead of using the new API directly in the simplified API, use the Worldometer class from the core module. This class now uses the new API internally, thus avoiding code duplication between both modules. --- worldometer/api.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/worldometer/api.py b/worldometer/api.py index 89d39e8..87b496e 100644 --- a/worldometer/api.py +++ b/worldometer/api.py @@ -99,9 +99,11 @@ 'road_traffic_accident_fatalities_this_year' ] -from dataclasses import asdict -from worldometer.world import WorldCounters +from worldometer import Worldometer + + +_cached_metrics = {} def get_metric_of(label: str) -> dict: @@ -122,18 +124,12 @@ def get_metric_of(label: str) -> dict: >>> get_metric_of(label='current_world_population') {'current_world_population': 7845085923} """ - wc = WorldCounters() - - metrics = { - **asdict(wc.world_population), - **asdict(wc.government_and_economics), - **asdict(wc.society_and_media), - **asdict(wc.environment), - **asdict(wc.food), - **asdict(wc.water), - **asdict(wc.energy), - **asdict(wc.health) - } + + if not _cached_metrics: + w = Worldometer() + _cached_metrics.update(w.metrics_with_labels()) + + metrics = _cached_metrics.copy() if label not in metrics: raise Exception(f'This label "{label}" is invalid, please use a valid label.') @@ -143,6 +139,7 @@ def get_metric_of(label: str) -> dict: def update_metrics() -> None: """Update metrics of worldometer.""" + _cached_metrics.clear() def current_world_population() -> dict: From 2d47e144c66a2d8f12a59f46377ccbfdf1da2233 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sat, 21 Oct 2023 21:20:20 -0300 Subject: [PATCH 130/147] feat: implement a decorator to warn users that the old API is deprecated --- worldometer/api.py | 67 ++++++++++++++++++++++++++++++++++++++++++++- worldometer/core.py | 17 ++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/worldometer/api.py b/worldometer/api.py index 87b496e..365302b 100644 --- a/worldometer/api.py +++ b/worldometer/api.py @@ -99,13 +99,14 @@ 'road_traffic_accident_fatalities_this_year' ] - from worldometer import Worldometer +from worldometer.core import _deprecated_api _cached_metrics = {} +@_deprecated_api def get_metric_of(label: str) -> dict: """Get metric of label specified. @@ -137,321 +138,385 @@ def get_metric_of(label: str) -> dict: return {label: metrics[label]} +@_deprecated_api def update_metrics() -> None: """Update metrics of worldometer.""" _cached_metrics.clear() +@_deprecated_api def current_world_population() -> dict: """Get number of current world population.""" return get_metric_of(label='current_population') +@_deprecated_api def births_this_year() -> dict: """Get number of births this year.""" return get_metric_of(label='births_this_year') +@_deprecated_api def births_today() -> dict: """Get number of births today.""" return get_metric_of(label='births_today') +@_deprecated_api def deaths_this_year() -> dict: """Get number of deaths this year.""" return get_metric_of(label='deaths_this_year') +@_deprecated_api def deaths_today() -> dict: """Get number of deaths today.""" return get_metric_of(label='deaths_today') +@_deprecated_api def net_population_growth_this_year() -> dict: """Get number of net population growth this year.""" return get_metric_of(label='net_population_growth_this_year') +@_deprecated_api def net_population_growth_today() -> dict: """Get number of net population growth today.""" return get_metric_of(label='net_population_growth_today') +@_deprecated_api def public_healthcare_expenditure_today() -> dict: """Get number of public healthcare expenditure today.""" return get_metric_of(label='public_healthcare_expenditure_today') +@_deprecated_api def public_education_expenditure_today() -> dict: """Get number of public education expenditure today.""" return get_metric_of(label='public_education_expenditure_today') +@_deprecated_api def public_military_expenditure_today() -> dict: """Get number of public military expenditure today.""" return get_metric_of(label='public_military_expenditure_today') +@_deprecated_api def cars_produced_this_year() -> dict: """Get number of cars produced this year.""" return get_metric_of(label='cars_produced_this_year') +@_deprecated_api def bicycles_produced_this_year() -> dict: """Get number of bicycles produced this year.""" return get_metric_of(label='bicycles_produced_this_year') +@_deprecated_api def computers_produced_this_year() -> dict: """Get number of computers produced this year.""" return get_metric_of(label='computers_produced_this_year') +@_deprecated_api def new_book_titles_published_this_year() -> dict: """Get number of new book titles published this year.""" return get_metric_of(label='new_book_titles_published_this_year') +@_deprecated_api def newspapers_circulated_today() -> dict: """Get number of newspapers circulated today.""" return get_metric_of(label='newspapers_circulated_today') +@_deprecated_api def tv_sets_sold_worldwide_today() -> dict: """Get number of tv sets sold worldwide today.""" return get_metric_of(label='tv_sets_sold_worldwide_today') +@_deprecated_api def cellular_phones_sold_today() -> dict: """Get number of cellular phones sold today.""" return get_metric_of(label='cellular_phones_sold_today') +@_deprecated_api def money_spent_on_videogames_today() -> dict: """Get number of money spent on videogames today.""" return get_metric_of(label='money_spent_on_videogames_today') +@_deprecated_api def internet_users_in_the_world_today() -> dict: """Get number of internet users in the world today.""" return get_metric_of(label='internet_users_in_the_world_today') +@_deprecated_api def emails_sent_today() -> dict: """Get number of emails sent today.""" return get_metric_of(label='emails_sent_today') +@_deprecated_api def blog_posts_written_today() -> dict: """Get number of blog posts written today.""" return get_metric_of(label='blog_posts_written_today') +@_deprecated_api def tweets_sent_today() -> dict: """Get number of tweets sent today.""" return get_metric_of(label='tweets_sent_today') +@_deprecated_api def google_searches_today() -> dict: """Get number of google searches today.""" return get_metric_of(label='google_searches_today') +@_deprecated_api def forest_loss_this_year() -> dict: """Get number of forest loss this year.""" return get_metric_of(label='forest_loss_this_year') +@_deprecated_api def land_lost_to_soil_erosion_this_year() -> dict: """Get number of land lost to soil erosion this year.""" return get_metric_of(label='land_lost_to_soil_erosion_this_year') +@_deprecated_api def co2_emissions_this_year() -> dict: """Get number of co2 emissions this year.""" return get_metric_of(label='co2_emissions_this_year') +@_deprecated_api def desertification_this_year() -> dict: """Get number of desertification this year.""" return get_metric_of(label='desertification_this_year') +@_deprecated_api def toxic_chemicals_released_in_the_environment_this_year() -> dict: """Get number of toxic chemicals released in the environment this year.""" return get_metric_of(label='toxic_chemicals_released_in_the_environment_this_year') +@_deprecated_api def undernourished_people_in_the_world() -> dict: """Get number of undernourished people in the world.""" return get_metric_of(label='undernourished_people_in_the_world') +@_deprecated_api def overweight_people_in_the_world() -> dict: """Get number of overweight people in the world.""" return get_metric_of(label='overweight_people_in_the_world') +@_deprecated_api def obese_people_in_the_world() -> dict: """Get number of obese people in the world.""" return get_metric_of(label='obese_people_in_the_world') +@_deprecated_api def people_who_died_of_hunger_today() -> dict: """Get number of people who died of hunger today.""" return get_metric_of(label='people_who_died_of_hunger_today') +@_deprecated_api def money_spent_for_obesity_related_diseases_in_the_usa_today() -> dict: """Get number of money spent for obesity related diseases in the usa today.""" return get_metric_of(label='money_spent_for_obesity_related_diseases_in_the_usa_today') +@_deprecated_api def money_spent_on_weight_loss_programs_in_the_usa_today() -> dict: """Get number of money spent on weight loss programs in the usa today.""" return get_metric_of(label='money_spent_on_weight_loss_programs_in_the_usa_today') +@_deprecated_api def water_used_this_year() -> dict: """Get number of water used this year.""" return get_metric_of(label='water_used_this_year') +@_deprecated_api def deaths_caused_by_water_related_diseases_this_year() -> dict: """Get number of deaths caused by water related diseases this year.""" return get_metric_of(label='deaths_caused_by_water_related_diseases_this_year') +@_deprecated_api def people_with_no_access_to_a_safe_drinking_water_source() -> dict: """Get number of people with no access to a safe drinking water source.""" return get_metric_of(label='people_with_no_access_to_a_safe_drinking_water_source') +@_deprecated_api def energy_used_today() -> dict: """Get number of energy used today.""" return get_metric_of(label='energy_used_today') +@_deprecated_api def non_renewable_sources() -> dict: """Get number of non renewable sources.""" return get_metric_of(label='non_renewable_sources') +@_deprecated_api def renewable_sources() -> dict: """Get number of renewable sources.""" return get_metric_of(label='renewable_sources') +@_deprecated_api def solar_energy_striking_earth_today() -> dict: """Get number of solar energy striking earth today.""" return get_metric_of(label='solar_energy_striking_earth_today') +@_deprecated_api def oil_pumped_today() -> dict: """Get number of oil pumped today.""" return get_metric_of(label='oil_pumped_today') +@_deprecated_api def oil_left() -> dict: """Get number of oil left.""" return get_metric_of(label='oil_left') +@_deprecated_api def days_to_the_end_of_oil() -> dict: """Get number of days to the end of oil.""" return get_metric_of(label='days_to_the_end_of_oil') +@_deprecated_api def natural_gas_left() -> dict: """Get number of natural gas left.""" return get_metric_of(label='natural_gas_left') +@_deprecated_api def days_to_the_end_of_natural_gas() -> dict: """Get number of days to the end of natural gas.""" return get_metric_of(label='days_to_the_end_of_natural_gas') +@_deprecated_api def coal_left() -> dict: """Get number of coal left.""" return get_metric_of(label='coal_left') +@_deprecated_api def days_to_the_end_of_coal() -> dict: """Get number of days to the end of coal.""" return get_metric_of(label='days_to_the_end_of_coal') +@_deprecated_api def communicable_disease_deaths_this_year() -> dict: """Get number of communicable disease deaths this year.""" return get_metric_of(label='communicable_disease_deaths_this_year') +@_deprecated_api def seasonal_flu_deaths_this_year() -> dict: """Get number of seasonal flu deaths this year.""" return get_metric_of(label='seasonal_flu_deaths_this_year') +@_deprecated_api def deaths_of_children_under_5_this_year() -> dict: """Get number of deaths of children under 5 this year.""" return get_metric_of(label='deaths_of_children_under_5_this_year') +@_deprecated_api def abortions_this_year() -> dict: """Get number of abortions this year.""" return get_metric_of(label='abortions_this_year') +@_deprecated_api def deaths_of_mothers_during_birth_this_year() -> dict: """Get number of deaths of mothers during birth this year.""" return get_metric_of(label='deaths_of_mothers_during_birth_this_year') +@_deprecated_api def hiv_aids_infected_people() -> dict: """Get number of hiv aids infected people.""" return get_metric_of(label='hiv_aids_infected_people') +@_deprecated_api def deaths_caused_by_hiv_aids_this_year() -> dict: """Get number of deaths caused by hiv aids this year.""" return get_metric_of(label='deaths_caused_by_hiv_aids_this_year') +@_deprecated_api def deaths_caused_by_cancer_this_year() -> dict: """Get number of deaths caused by cancer this year.""" return get_metric_of(label='deaths_caused_by_cancer_this_year') +@_deprecated_api def deaths_caused_by_malaria_this_year() -> dict: """Get number of deaths caused by malaria this year.""" return get_metric_of(label='deaths_caused_by_malaria_this_year') +@_deprecated_api def cigarettes_smoked_today() -> dict: """Get number of cigarettes smoked today.""" return get_metric_of(label='cigarettes_smoked_today') +@_deprecated_api def deaths_caused_by_smoking_this_year() -> dict: """Get number of deaths caused by smoking this year.""" return get_metric_of(label='deaths_caused_by_smoking_this_year') +@_deprecated_api def deaths_caused_by_alcohol_this_year() -> dict: """Get number of deaths caused by alcohol this year.""" return get_metric_of(label='deaths_caused_by_alcohol_this_year') +@_deprecated_api def suicides_this_year() -> dict: """Get number of suicides this year.""" return get_metric_of(label='suicides_this_year') +@_deprecated_api def money_spent_on_illegal_drugs_this_year() -> dict: """Get number of money spent on illegal drugs this year.""" return get_metric_of(label='money_spent_on_illegal_drugs_this_year') +@_deprecated_api def road_traffic_accident_fatalities_this_year() -> dict: """Get number of road traffic accident fatalities this year.""" return get_metric_of(label='road_traffic_accident_fatalities_this_year') diff --git a/worldometer/core.py b/worldometer/core.py index f3d4df9..d3fd5b7 100644 --- a/worldometer/core.py +++ b/worldometer/core.py @@ -38,6 +38,9 @@ __all__ = ['Worldometer'] +import warnings +from functools import wraps + from worldometer.world import WorldCounters # Constant variables, used in the Worldometer module. @@ -127,6 +130,20 @@ } +def _deprecated_api(func_or_class): + @wraps(func_or_class) + def decorated(*args, **kwargs): + warnings.warn( + f'{func_or_class.__name__}() is deprecated. Use WorldCounters() instead.' + ' It will be removed in a future release.', + DeprecationWarning, + stacklevel=2 + ) + return func_or_class(*args, **kwargs) + return decorated + + +@_deprecated_api class Worldometer(object): """This is the core class of the worldometer module. From 104d2b92fc10f69a3451af9ac470216f319c0454 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 22 Oct 2023 00:04:06 -0300 Subject: [PATCH 131/147] chore: set false in fail_on_warning configuration --- .readthedocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index dc540c2..22210ff 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -15,7 +15,7 @@ build: sphinx: builder: html configuration: docs/source/conf.py - fail_on_warning: true + fail_on_warning: false # Build all formats (htmlzip, pdf and epub) formats: all From 7afdc2ae543dea2dbe881d785fa0246e819e9fa9 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 22 Oct 2023 02:02:47 -0300 Subject: [PATCH 132/147] refactor: create a type alias for the counter values data --- worldometer/world/counters.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/worldometer/world/counters.py b/worldometer/world/counters.py index ddcd1b3..49e9d87 100644 --- a/worldometer/world/counters.py +++ b/worldometer/world/counters.py @@ -4,6 +4,9 @@ from worldometer.scraper import get_rts_counters_object +CounterValuesType = Dict[str, Union[int, float, None]] + + class WorldCounters: """Contains a reference to each section of the home page counters. @@ -47,7 +50,7 @@ def __init__(self) -> None: self._data = self._load_data() self._init_counters() - def _load_data(self) -> Dict[str, Union[int, float, None]]: + def _load_data(self) -> CounterValuesType: rts_counters = get_rts_counters_object(path_url=self.source_path) return rts_counters @@ -81,7 +84,7 @@ class WorldPopulation: net_population_growth_today : Union[int, float, None] net_population_growth_this_year : Union[int, float, None] """ - _data: Dict[str, Union[int, float, None]] = field(repr=False) + _data: CounterValuesType = field(repr=False) def __post_init__(self) -> None: self.current_population = self._data.get('current_population') @@ -106,7 +109,7 @@ class GovernmentAndEconomics: bicycles_produced_this_year : Union[int, float, None] computers_produced_this_year : Union[int, float, None] """ - _data: Dict[str, Union[int, float, None]] = field(repr=False) + _data: CounterValuesType = field(repr=False) def __post_init__(self) -> None: self.public_healthcare_expenditure_today = self._data.get('gov_expenditures_health') @@ -134,7 +137,7 @@ class SocietyAndMedia: tweets_sent_today : Union[int, float, None] google_searches_today : Union[int, float, None] """ - _data: Dict[str, Union[int, float, None]] = field(repr=False) + _data: CounterValuesType = field(repr=False) def __post_init__(self) -> None: self.new_book_titles_published_this_year = self._data.get('books_published') @@ -161,7 +164,7 @@ class Environment: desertification_this_year : Union[int, float, None] toxic_chemicals_released_in_the_environment_this_year : Union[int, float, None] """ - _data: Dict[str, Union[int, float, None]] = field(repr=False) + _data: CounterValuesType = field(repr=False) def __post_init__(self) -> None: self.forest_loss_this_year = self._data.get('forest_loss') @@ -184,7 +187,7 @@ class Food: money_spent_for_obesity_related_diseases_in_the_usa_today : Union[int, float, None] money_spent_on_weight_loss_programs_in_the_usa_today : Union[int, float, None] """ - _data: Dict[str, Union[int, float, None]] = field(repr=False) + _data: CounterValuesType = field(repr=False) def __post_init__(self) -> None: self.undernourished_people_in_the_world = self._data.get('undernourished') @@ -205,7 +208,7 @@ class Water: deaths_caused_by_water_related_diseases_this_year : Union[int, float, None] people_with_no_access_to_a_safe_drinking_water_source : Union[int, float, None] """ - _data: Dict[str, Union[int, float, None]] = field(repr=False) + _data: CounterValuesType = field(repr=False) def __post_init__(self) -> None: self.water_used_this_year = self._data.get('water_consumed') @@ -231,7 +234,7 @@ class Energy: coal_left : Union[int, float, None] days_to_the_end_of_coal : Union[int, float, None] """ - _data: Dict[str, Union[int, float, None]] = field(repr=False) + _data: CounterValuesType = field(repr=False) def __post_init__(self) -> None: self.energy_used_today = self._data.get('energy_used') @@ -269,7 +272,7 @@ class Health: money_spent_on_illegal_drugs_this_year : Union[int, float, None] road_traffic_accident_fatalities_this_year : Union[int, float, None] """ - _data: Dict[str, Union[int, float, None]] = field(repr=False) + _data: CounterValuesType = field(repr=False) def __post_init__(self) -> None: self.communicable_disease_deaths_this_year = self._data.get('dth1s_communicable_disaxs') From fa7ae10d12480aab3136828441cfacec83ce4fdd Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 22 Oct 2023 02:16:16 -0300 Subject: [PATCH 133/147] refactor: _data is not a dataclass field, but an init-only variable --- worldometer/world/counters.py | 164 +++++++++++++++++----------------- 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/worldometer/world/counters.py b/worldometer/world/counters.py index 49e9d87..4713c22 100644 --- a/worldometer/world/counters.py +++ b/worldometer/world/counters.py @@ -1,4 +1,4 @@ -from dataclasses import dataclass, field +from dataclasses import InitVar, dataclass, field from typing import Dict, Union from worldometer.scraper import get_rts_counters_object @@ -84,16 +84,16 @@ class WorldPopulation: net_population_growth_today : Union[int, float, None] net_population_growth_this_year : Union[int, float, None] """ - _data: CounterValuesType = field(repr=False) + _data: InitVar[CounterValuesType] - def __post_init__(self) -> None: - self.current_population = self._data.get('current_population') - self.births_today = self._data.get('births_today') - self.births_this_year = self._data.get('births_this_year') - self.deaths_today = self._data.get('dth1s_today') - self.deaths_this_year = self._data.get('dth1s_this_year') - self.net_population_growth_today = self._data.get('absolute_growth') - self.net_population_growth_this_year = self._data.get('absolute_growth_year') + def __post_init__(self, _data: CounterValuesType) -> None: + self.current_population = _data.get('current_population') + self.births_today = _data.get('births_today') + self.births_this_year = _data.get('births_this_year') + self.deaths_today = _data.get('dth1s_today') + self.deaths_this_year = _data.get('dth1s_this_year') + self.net_population_growth_today = _data.get('absolute_growth') + self.net_population_growth_this_year = _data.get('absolute_growth_year') @dataclass @@ -109,15 +109,15 @@ class GovernmentAndEconomics: bicycles_produced_this_year : Union[int, float, None] computers_produced_this_year : Union[int, float, None] """ - _data: CounterValuesType = field(repr=False) + _data: InitVar[CounterValuesType] - def __post_init__(self) -> None: - self.public_healthcare_expenditure_today = self._data.get('gov_expenditures_health') - self.public_education_expenditure_today = self._data.get('gov_expenditures_education') - self.public_military_expenditure_today = self._data.get('gov_expenditures_military') - self.cars_produced_this_year = self._data.get('automobile_produced') - self.bicycles_produced_this_year = self._data.get('bicycle_produced') - self.computers_produced_this_year = self._data.get('computers_sold') + def __post_init__(self, _data: CounterValuesType) -> None: + self.public_healthcare_expenditure_today = _data.get('gov_expenditures_health') + self.public_education_expenditure_today = _data.get('gov_expenditures_education') + self.public_military_expenditure_today = _data.get('gov_expenditures_military') + self.cars_produced_this_year = _data.get('automobile_produced') + self.bicycles_produced_this_year = _data.get('bicycle_produced') + self.computers_produced_this_year = _data.get('computers_sold') @dataclass @@ -137,19 +137,19 @@ class SocietyAndMedia: tweets_sent_today : Union[int, float, None] google_searches_today : Union[int, float, None] """ - _data: CounterValuesType = field(repr=False) + _data: InitVar[CounterValuesType] - def __post_init__(self) -> None: - self.new_book_titles_published_this_year = self._data.get('books_published') - self.newspapers_circulated_today = self._data.get('newspapers_circulated') - self.tv_sets_sold_worldwide_today = self._data.get('tv') - self.cellular_phones_sold_today = self._data.get('cellular') - self.money_spent_on_videogames_today = self._data.get('videogames') - self.internet_users_in_the_world_today = self._data.get('internet_users') - self.emails_sent_today = self._data.get('em') - self.blog_posts_written_today = self._data.get('blog_posts') - self.tweets_sent_today = self._data.get('tweets') - self.google_searches_today = self._data.get('google_searches') + def __post_init__(self, _data: CounterValuesType) -> None: + self.new_book_titles_published_this_year = _data.get('books_published') + self.newspapers_circulated_today = _data.get('newspapers_circulated') + self.tv_sets_sold_worldwide_today = _data.get('tv') + self.cellular_phones_sold_today = _data.get('cellular') + self.money_spent_on_videogames_today = _data.get('videogames') + self.internet_users_in_the_world_today = _data.get('internet_users') + self.emails_sent_today = _data.get('em') + self.blog_posts_written_today = _data.get('blog_posts') + self.tweets_sent_today = _data.get('tweets') + self.google_searches_today = _data.get('google_searches') @dataclass @@ -164,14 +164,14 @@ class Environment: desertification_this_year : Union[int, float, None] toxic_chemicals_released_in_the_environment_this_year : Union[int, float, None] """ - _data: CounterValuesType = field(repr=False) + _data: InitVar[CounterValuesType] - def __post_init__(self) -> None: - self.forest_loss_this_year = self._data.get('forest_loss') - self.land_lost_to_soil_erosion_this_year = self._data.get('soil_erosion') - self.co2_emissions_this_year = self._data.get('co2_emissions') - self.desertification_this_year = self._data.get('desert_land_formed') - self.toxic_chemicals_released_in_the_environment_this_year = self._data.get('tox_chem') + def __post_init__(self, _data: CounterValuesType) -> None: + self.forest_loss_this_year = _data.get('forest_loss') + self.land_lost_to_soil_erosion_this_year = _data.get('soil_erosion') + self.co2_emissions_this_year = _data.get('co2_emissions') + self.desertification_this_year = _data.get('desert_land_formed') + self.toxic_chemicals_released_in_the_environment_this_year = _data.get('tox_chem') @dataclass @@ -187,15 +187,15 @@ class Food: money_spent_for_obesity_related_diseases_in_the_usa_today : Union[int, float, None] money_spent_on_weight_loss_programs_in_the_usa_today : Union[int, float, None] """ - _data: CounterValuesType = field(repr=False) + _data: InitVar[CounterValuesType] - def __post_init__(self) -> None: - self.undernourished_people_in_the_world = self._data.get('undernourished') - self.overweight_people_in_the_world = self._data.get('overweight') - self.obese_people_in_the_world = self._data.get('obese') - self.people_who_died_of_hunger_today = self._data.get('dth1_hunger') - self.money_spent_for_obesity_related_diseases_in_the_usa_today = self._data.get('obesity_spending') - self.money_spent_on_weight_loss_programs_in_the_usa_today = self._data.get('spending_on_weight_loss') + def __post_init__(self, _data: CounterValuesType) -> None: + self.undernourished_people_in_the_world = _data.get('undernourished') + self.overweight_people_in_the_world = _data.get('overweight') + self.obese_people_in_the_world = _data.get('obese') + self.people_who_died_of_hunger_today = _data.get('dth1_hunger') + self.money_spent_for_obesity_related_diseases_in_the_usa_today = _data.get('obesity_spending') + self.money_spent_on_weight_loss_programs_in_the_usa_today = _data.get('spending_on_weight_loss') @dataclass @@ -208,12 +208,12 @@ class Water: deaths_caused_by_water_related_diseases_this_year : Union[int, float, None] people_with_no_access_to_a_safe_drinking_water_source : Union[int, float, None] """ - _data: CounterValuesType = field(repr=False) + _data: InitVar[CounterValuesType] - def __post_init__(self) -> None: - self.water_used_this_year = self._data.get('water_consumed') - self.deaths_caused_by_water_related_diseases_this_year = self._data.get('water_disax') - self.people_with_no_access_to_a_safe_drinking_water_source = self._data.get('nowater_population') + def __post_init__(self, _data: CounterValuesType) -> None: + self.water_used_this_year = _data.get('water_consumed') + self.deaths_caused_by_water_related_diseases_this_year = _data.get('water_disax') + self.people_with_no_access_to_a_safe_drinking_water_source = _data.get('nowater_population') @dataclass @@ -234,20 +234,20 @@ class Energy: coal_left : Union[int, float, None] days_to_the_end_of_coal : Union[int, float, None] """ - _data: CounterValuesType = field(repr=False) - - def __post_init__(self) -> None: - self.energy_used_today = self._data.get('energy_used') - self.non_renewable_sources = self._data.get('energy_nonren') - self.renewable_sources = self._data.get('energy_ren') - self.solar_energy_striking_earth_today = self._data.get('solar_energy') - self.oil_pumped_today = self._data.get('oil_consumption') - self.oil_left = self._data.get('oil_reserves') - self.days_to_the_end_of_oil = self._data.get('oil_days') - self.natural_gas_left = self._data.get('gas_reserves') - self.days_to_the_end_of_natural_gas = self._data.get('gas_days') - self.coal_left = self._data.get('coal_reserves') - self.days_to_the_end_of_coal = self._data.get('coal_days') + _data: InitVar[CounterValuesType] + + def __post_init__(self, _data: CounterValuesType) -> None: + self.energy_used_today = _data.get('energy_used') + self.non_renewable_sources = _data.get('energy_nonren') + self.renewable_sources = _data.get('energy_ren') + self.solar_energy_striking_earth_today = _data.get('solar_energy') + self.oil_pumped_today = _data.get('oil_consumption') + self.oil_left = _data.get('oil_reserves') + self.days_to_the_end_of_oil = _data.get('oil_days') + self.natural_gas_left = _data.get('gas_reserves') + self.days_to_the_end_of_natural_gas = _data.get('gas_days') + self.coal_left = _data.get('coal_reserves') + self.days_to_the_end_of_coal = _data.get('coal_days') @dataclass @@ -272,21 +272,21 @@ class Health: money_spent_on_illegal_drugs_this_year : Union[int, float, None] road_traffic_accident_fatalities_this_year : Union[int, float, None] """ - _data: CounterValuesType = field(repr=False) - - def __post_init__(self) -> None: - self.communicable_disease_deaths_this_year = self._data.get('dth1s_communicable_disaxs') - self.seasonal_flu_deaths_this_year = self._data.get('dth1s_flu') - self.deaths_of_children_under_5_this_year = self._data.get('dth1s_children') - self.abortions_this_year = self._data.get('ab') - self.deaths_of_mothers_during_birth_this_year = self._data.get('dth1s_maternal') - self.hiv_aids_infected_people = self._data.get('infections_hiv') - self.deaths_caused_by_hiv_aids_this_year = self._data.get('dth1s_ads') - self.deaths_caused_by_cancer_this_year = self._data.get('dth1s_cancer') - self.deaths_caused_by_malaria_this_year = self._data.get('dth1s_malarial') - self.cigarettes_smoked_today = self._data.get('cigarettes_smoked') - self.deaths_caused_by_smoking_this_year = self._data.get('dth1s_cigarettes') - self.deaths_caused_by_alcohol_this_year = self._data.get('dth1s_alchool') - self.suicides_this_year = self._data.get('sui') - self.money_spent_on_illegal_drugs_this_year = self._data.get('drug_spending') - self.road_traffic_accident_fatalities_this_year = self._data.get('dth1s_cars') + _data: InitVar[CounterValuesType] + + def __post_init__(self, _data: CounterValuesType) -> None: + self.communicable_disease_deaths_this_year = _data.get('dth1s_communicable_disaxs') + self.seasonal_flu_deaths_this_year = _data.get('dth1s_flu') + self.deaths_of_children_under_5_this_year = _data.get('dth1s_children') + self.abortions_this_year = _data.get('ab') + self.deaths_of_mothers_during_birth_this_year = _data.get('dth1s_maternal') + self.hiv_aids_infected_people = _data.get('infections_hiv') + self.deaths_caused_by_hiv_aids_this_year = _data.get('dth1s_ads') + self.deaths_caused_by_cancer_this_year = _data.get('dth1s_cancer') + self.deaths_caused_by_malaria_this_year = _data.get('dth1s_malarial') + self.cigarettes_smoked_today = _data.get('cigarettes_smoked') + self.deaths_caused_by_smoking_this_year = _data.get('dth1s_cigarettes') + self.deaths_caused_by_alcohol_this_year = _data.get('dth1s_alchool') + self.suicides_this_year = _data.get('sui') + self.money_spent_on_illegal_drugs_this_year = _data.get('drug_spending') + self.road_traffic_accident_fatalities_this_year = _data.get('dth1s_cars') From 4bcd8b78f614a33ccecdf6a48b45000e3ae239cb Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 22 Oct 2023 02:49:46 -0300 Subject: [PATCH 134/147] refactor: define explicit fields in all counter dataclasses This is necessary to convert the dataclass fields to a dict object with the asdict function --- worldometer/world/counters.py | 66 ++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/worldometer/world/counters.py b/worldometer/world/counters.py index 4713c22..4d89c8f 100644 --- a/worldometer/world/counters.py +++ b/worldometer/world/counters.py @@ -4,7 +4,8 @@ from worldometer.scraper import get_rts_counters_object -CounterValuesType = Dict[str, Union[int, float, None]] +CounterValueType = Union[int, float, None] +CounterValuesType = Dict[str, CounterValueType] class WorldCounters: @@ -85,6 +86,13 @@ class WorldPopulation: net_population_growth_this_year : Union[int, float, None] """ _data: InitVar[CounterValuesType] + current_population: CounterValueType = field(init=False) + births_today: CounterValueType = field(init=False) + births_this_year: CounterValueType = field(init=False) + deaths_today: CounterValueType = field(init=False) + deaths_this_year: CounterValueType = field(init=False) + net_population_growth_today: CounterValueType = field(init=False) + net_population_growth_this_year: CounterValueType = field(init=False) def __post_init__(self, _data: CounterValuesType) -> None: self.current_population = _data.get('current_population') @@ -110,6 +118,12 @@ class GovernmentAndEconomics: computers_produced_this_year : Union[int, float, None] """ _data: InitVar[CounterValuesType] + public_healthcare_expenditure_today: CounterValueType = field(init=False) + public_education_expenditure_today: CounterValueType = field(init=False) + public_military_expenditure_today: CounterValueType = field(init=False) + cars_produced_this_year: CounterValueType = field(init=False) + bicycles_produced_this_year: CounterValueType = field(init=False) + computers_produced_this_year: CounterValueType = field(init=False) def __post_init__(self, _data: CounterValuesType) -> None: self.public_healthcare_expenditure_today = _data.get('gov_expenditures_health') @@ -138,6 +152,16 @@ class SocietyAndMedia: google_searches_today : Union[int, float, None] """ _data: InitVar[CounterValuesType] + new_book_titles_published_this_year: CounterValueType = field(init=False) + newspapers_circulated_today: CounterValueType = field(init=False) + tv_sets_sold_worldwide_today: CounterValueType = field(init=False) + cellular_phones_sold_today: CounterValueType = field(init=False) + money_spent_on_videogames_today: CounterValueType = field(init=False) + internet_users_in_the_world_today: CounterValueType = field(init=False) + emails_sent_today: CounterValueType = field(init=False) + blog_posts_written_today: CounterValueType = field(init=False) + tweets_sent_today: CounterValueType = field(init=False) + google_searches_today: CounterValueType = field(init=False) def __post_init__(self, _data: CounterValuesType) -> None: self.new_book_titles_published_this_year = _data.get('books_published') @@ -165,6 +189,11 @@ class Environment: toxic_chemicals_released_in_the_environment_this_year : Union[int, float, None] """ _data: InitVar[CounterValuesType] + forest_loss_this_year: CounterValueType = field(init=False) + land_lost_to_soil_erosion_this_year: CounterValueType = field(init=False) + co2_emissions_this_year: CounterValueType = field(init=False) + desertification_this_year: CounterValueType = field(init=False) + toxic_chemicals_released_in_the_environment_this_year: CounterValueType = field(init=False) def __post_init__(self, _data: CounterValuesType) -> None: self.forest_loss_this_year = _data.get('forest_loss') @@ -188,6 +217,12 @@ class Food: money_spent_on_weight_loss_programs_in_the_usa_today : Union[int, float, None] """ _data: InitVar[CounterValuesType] + undernourished_people_in_the_world: CounterValueType = field(init=False) + overweight_people_in_the_world: CounterValueType = field(init=False) + obese_people_in_the_world: CounterValueType = field(init=False) + people_who_died_of_hunger_today: CounterValueType = field(init=False) + money_spent_for_obesity_related_diseases_in_the_usa_today: CounterValueType = field(init=False) + money_spent_on_weight_loss_programs_in_the_usa_today: CounterValueType = field(init=False) def __post_init__(self, _data: CounterValuesType) -> None: self.undernourished_people_in_the_world = _data.get('undernourished') @@ -209,6 +244,9 @@ class Water: people_with_no_access_to_a_safe_drinking_water_source : Union[int, float, None] """ _data: InitVar[CounterValuesType] + water_used_this_year: CounterValueType = field(init=False) + deaths_caused_by_water_related_diseases_this_year: CounterValueType = field(init=False) + people_with_no_access_to_a_safe_drinking_water_source: CounterValueType = field(init=False) def __post_init__(self, _data: CounterValuesType) -> None: self.water_used_this_year = _data.get('water_consumed') @@ -235,6 +273,17 @@ class Energy: days_to_the_end_of_coal : Union[int, float, None] """ _data: InitVar[CounterValuesType] + energy_used_today: CounterValueType = field(init=False) + non_renewable_sources: CounterValueType = field(init=False) + renewable_sources: CounterValueType = field(init=False) + solar_energy_striking_earth_today: CounterValueType = field(init=False) + oil_pumped_today: CounterValueType = field(init=False) + oil_left: CounterValueType = field(init=False) + days_to_the_end_of_oil: CounterValueType = field(init=False) + natural_gas_left: CounterValueType = field(init=False) + days_to_the_end_of_natural_gas: CounterValueType = field(init=False) + coal_left: CounterValueType = field(init=False) + days_to_the_end_of_coal: CounterValueType = field(init=False) def __post_init__(self, _data: CounterValuesType) -> None: self.energy_used_today = _data.get('energy_used') @@ -273,6 +322,21 @@ class Health: road_traffic_accident_fatalities_this_year : Union[int, float, None] """ _data: InitVar[CounterValuesType] + communicable_disease_deaths_this_year: CounterValueType = field(init=False) + seasonal_flu_deaths_this_year: CounterValueType = field(init=False) + deaths_of_children_under_5_this_year: CounterValueType = field(init=False) + abortions_this_year: CounterValueType = field(init=False) + deaths_of_mothers_during_birth_this_year: CounterValueType = field(init=False) + hiv_aids_infected_people: CounterValueType = field(init=False) + deaths_caused_by_hiv_aids_this_year: CounterValueType = field(init=False) + deaths_caused_by_cancer_this_year: CounterValueType = field(init=False) + deaths_caused_by_malaria_this_year: CounterValueType = field(init=False) + cigarettes_smoked_today: CounterValueType = field(init=False) + deaths_caused_by_smoking_this_year: CounterValueType = field(init=False) + deaths_caused_by_alcohol_this_year: CounterValueType = field(init=False) + suicides_this_year: CounterValueType = field(init=False) + money_spent_on_illegal_drugs_this_year: CounterValueType = field(init=False) + road_traffic_accident_fatalities_this_year: CounterValueType = field(init=False) def __post_init__(self, _data: CounterValuesType) -> None: self.communicable_disease_deaths_this_year = _data.get('dth1s_communicable_disaxs') From ac5258d105932aa46a372c00c6ea128640d30f58 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 22 Oct 2023 03:02:57 -0300 Subject: [PATCH 135/147] fix: _data field is no longer a field, it does not need to be removed --- worldometer/core.py | 1 - 1 file changed, 1 deletion(-) diff --git a/worldometer/core.py b/worldometer/core.py index d3fd5b7..5e89a2c 100644 --- a/worldometer/core.py +++ b/worldometer/core.py @@ -281,7 +281,6 @@ def collect_metrics(self) -> list: **wc.energy.__dict__, **wc.health.__dict__ } - metrics.pop('_data') metrics_values = list(metrics.values()) From 00148447ddd9aa3ac60a2064bde04869e8ab6d30 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 22 Oct 2023 03:22:40 -0300 Subject: [PATCH 136/147] refactor: use asdict func instead of __dict__ attr in old api --- worldometer/core.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/worldometer/core.py b/worldometer/core.py index 5e89a2c..2425340 100644 --- a/worldometer/core.py +++ b/worldometer/core.py @@ -40,6 +40,7 @@ import warnings from functools import wraps +from dataclasses import asdict from worldometer.world import WorldCounters @@ -272,14 +273,14 @@ def collect_metrics(self) -> list: wc = WorldCounters() metrics = { - **wc.world_population.__dict__, - **wc.government_and_economics.__dict__, - **wc.society_and_media.__dict__, - **wc.environment.__dict__, - **wc.food.__dict__, - **wc.water.__dict__, - **wc.energy.__dict__, - **wc.health.__dict__ + **asdict(wc.world_population), + **asdict(wc.government_and_economics), + **asdict(wc.society_and_media), + **asdict(wc.environment), + **asdict(wc.food), + **asdict(wc.water), + **asdict(wc.energy), + **asdict(wc.health) } metrics_values = list(metrics.values()) From f76d8ca5e316ca4a9b742ca081292b0236c94201 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 22 Oct 2023 03:50:41 -0300 Subject: [PATCH 137/147] chore: add pandas to the docs_requirements file --- docs/docs_requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/docs_requirements.txt b/docs/docs_requirements.txt index 421ec2e..5637830 100644 --- a/docs/docs_requirements.txt +++ b/docs/docs_requirements.txt @@ -1 +1,2 @@ -requests-html==0.10.0 \ No newline at end of file +requests-html==0.10.0 +pandas \ No newline at end of file From 19a39d26aa353239102eabe7eed8ed38ccdfdfab Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 22 Oct 2023 06:52:16 -0300 Subject: [PATCH 138/147] build: update all project metadata --- docs/source/conf.py | 10 ++++++---- setup.py | 34 +++++++++++++++------------------- worldometer/__about__.py | 5 ----- worldometer/__init__.py | 3 +++ 4 files changed, 24 insertions(+), 28 deletions(-) delete mode 100644 worldometer/__about__.py diff --git a/docs/source/conf.py b/docs/source/conf.py index cff9b3e..6864050 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -16,7 +16,9 @@ # import os import sys -sys.path.insert(0, os.path.abspath('../..')) +sys.path.insert(0, os.path.abspath(os.path.join('..', '..'))) + +import worldometer # noqa # -- General configuration ------------------------------------------------ @@ -52,16 +54,16 @@ # General information about the project. project = 'worldometer' copyright = '2023, Matheus Felipe' -author = 'Matheus Felipe' +author = worldometer.__author__ # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = 'v1.0' +version = worldometer.__version__ # The full version, including alpha/beta/rc tags. -release = 'v1.0.1' +release = worldometer.__version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index 7e6cd26..7706e7c 100644 --- a/setup.py +++ b/setup.py @@ -1,38 +1,34 @@ -# -*- coding: utf-8 -*- - import os -from setuptools import setup, find_packages - -from worldometer.__about__ import __version__, __author__, __email__ +from setuptools import find_packages, setup -NAME = 'worldometer' -URL = 'https://github.com/matheusfelipeog/worldometer' -DESCRIPTION = 'Worldometer Scraping & API - Get world metrics from worldometers.info' +import worldometer here = os.path.abspath(os.path.dirname(__file__)) with open(os.path.join(here, 'README.md'), mode='r', encoding='utf-8') as f: - long_description = f.read() + long_description = '\n' + f.read() setup( - name=NAME, - version=__version__, - description=DESCRIPTION, + name='worldometer', + version=worldometer.__version__, + description='Get live, population, geography, projected, and historical data from around the world.', long_description=long_description, long_description_content_type='text/markdown', license='MIT License', - author=__author__, - author_email=__email__, - url=URL, + author=worldometer.__author__, + author_email='matheusfelipeog@protonmail.com', + url='https://github.com/matheusfelipeog/worldometer', packages=find_packages(), install_requires=[ - 'requests-html' + 'requests-html', + 'pandas', + 'html5lib' ], zip_safe=False, - python_requires='>=3.6', + python_requires='>=3.8', project_urls={ "Bug Tracker": "https://github.com/matheusfelipeog/worldometer/issues", "Documentation": "https://worldometer.readthedocs.io", @@ -51,10 +47,10 @@ 'Natural Language :: English', 'Operating System :: OS Independent', 'Programming Language :: Python', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: Implementation :: CPython', 'Topic :: Software Development :: Libraries', 'Topic :: Software Development :: Libraries :: Python Modules' diff --git a/worldometer/__about__.py b/worldometer/__about__.py deleted file mode 100644 index 92f14d2..0000000 --- a/worldometer/__about__.py +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- - -__version__ = '1.0.1' -__author__ = 'Matheus Felipe' -__email__ = 'matheusfelipeog@protonmail.com' diff --git a/worldometer/__init__.py b/worldometer/__init__.py index 6684d21..222c1e2 100644 --- a/worldometer/__init__.py +++ b/worldometer/__init__.py @@ -108,6 +108,9 @@ 'road_traffic_accident_fatalities_this_year' ] +__version__ = '1.0.1' +__author__ = 'Matheus Felipe' + # TODO: The worldometer.core module is deprecated. # TODO: The old API (worldometer.api) is deprecated. # This will be removed in the future. From 5f015c1bb7cfb4e65998983dda986a09ff00497d Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Sun, 22 Oct 2023 07:05:45 -0300 Subject: [PATCH 139/147] build: update worldometer version to 2.0.0 --- worldometer/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worldometer/__init__.py b/worldometer/__init__.py index 222c1e2..0a1b17f 100644 --- a/worldometer/__init__.py +++ b/worldometer/__init__.py @@ -108,7 +108,7 @@ 'road_traffic_accident_fatalities_this_year' ] -__version__ = '1.0.1' +__version__ = '2.0.0' __author__ = 'Matheus Felipe' # TODO: The worldometer.core module is deprecated. From 8a89e8e7bf2bba9be26b555f9fc32bc13ba01311 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Tue, 24 Oct 2023 22:57:46 -0300 Subject: [PATCH 140/147] Update .gitignore --- .gitignore | 199 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 187 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index d0b01cf..b5707a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,195 @@ -# Ignore local directory -.vscode/ +# Created by https://www.toptal.com/developers/gitignore/api/python,visualstudiocode +# Edit at https://www.toptal.com/developers/gitignore?templates=python,visualstudiocode -# Ignore local secret file -.env -.pypirc - -# Ignore cache +### Python ### +# Byte-compiled / optimized / DLL files __pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so -# Ignore build and distribution directories/files +# Distribution / packaging +.Python build/ +develop-eggs/ dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ *.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + +# ruff +.ruff_cache/ + +# LSP config files +pyrightconfig.json + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix -# Ignore the docs build directory -docs/build/ +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide -# Ignore local tests -local_test.py +# End of https://www.toptal.com/developers/gitignore/api/python,visualstudiocode \ No newline at end of file From 734c7b4dcba2ba1508ddbe710d1cdf09e21f5f2d Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 25 Oct 2023 10:33:55 -0300 Subject: [PATCH 141/147] chore: create pyproject.toml --- pyproject.toml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..f2bd017 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,16 @@ +[tool.poetry] +name = "worldometer" +version = "2.0.0" +description = "Get live, population, geography, projected, and historical data from around the world." +authors = ["Matheus Felipe "] +license = "MIT" +readme = "README.md" + +[tool.poetry.dependencies] +python = ">=3.9, <=3.11" + +[tool.poetry.group.dev.dependencies] + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" From aedceac1f6a85e17a21816a25b235bb363494f8a Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 25 Oct 2023 12:38:42 -0300 Subject: [PATCH 142/147] chore: add all dependencies in pyproject.toml and generate lock --- poetry.lock | 1169 ++++++++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 9 + 2 files changed, 1178 insertions(+) create mode 100644 poetry.lock diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..26edeab --- /dev/null +++ b/poetry.lock @@ -0,0 +1,1169 @@ +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. + +[[package]] +name = "alabaster" +version = "0.7.13" +description = "A configurable sidebar-enabled Sphinx theme" +optional = false +python-versions = ">=3.6" +files = [ + {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, + {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, +] + +[[package]] +name = "appdirs" +version = "1.4.4" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = "*" +files = [ + {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, + {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, +] + +[[package]] +name = "babel" +version = "2.13.1" +description = "Internationalization utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "Babel-2.13.1-py3-none-any.whl", hash = "sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed"}, + {file = "Babel-2.13.1.tar.gz", hash = "sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900"}, +] + +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] + +[[package]] +name = "beautifulsoup4" +version = "4.12.2" +description = "Screen-scraping library" +optional = false +python-versions = ">=3.6.0" +files = [ + {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"}, + {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"}, +] + +[package.dependencies] +soupsieve = ">1.2" + +[package.extras] +html5lib = ["html5lib"] +lxml = ["lxml"] + +[[package]] +name = "bs4" +version = "0.0.1" +description = "Dummy package for Beautiful Soup" +optional = false +python-versions = "*" +files = [ + {file = "bs4-0.0.1.tar.gz", hash = "sha256:36ecea1fd7cc5c0c6e4a1ff075df26d50da647b75376626cc186e2212886dd3a"}, +] + +[package.dependencies] +beautifulsoup4 = "*" + +[[package]] +name = "certifi" +version = "2023.7.22" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, + {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.1" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.1.tar.gz", hash = "sha256:d9137a876020661972ca6eec0766d81aef8a5627df628b664b234b73396e727e"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8aee051c89e13565c6bd366813c386939f8e928af93c29fda4af86d25b73d8f8"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:352a88c3df0d1fa886562384b86f9a9e27563d4704ee0e9d56ec6fcd270ea690"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:223b4d54561c01048f657fa6ce41461d5ad8ff128b9678cfe8b2ecd951e3f8a2"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f861d94c2a450b974b86093c6c027888627b8082f1299dfd5a4bae8e2292821"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1171ef1fc5ab4693c5d151ae0fdad7f7349920eabbaca6271f95969fa0756c2d"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28f512b9a33235545fbbdac6a330a510b63be278a50071a336afc1b78781b147"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0e842112fe3f1a4ffcf64b06dc4c61a88441c2f02f373367f7b4c1aa9be2ad5"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f9bc2ce123637a60ebe819f9fccc614da1bcc05798bbbaf2dd4ec91f3e08846"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f194cce575e59ffe442c10a360182a986535fd90b57f7debfaa5c845c409ecc3"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9a74041ba0bfa9bc9b9bb2cd3238a6ab3b7618e759b41bd15b5f6ad958d17605"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b578cbe580e3b41ad17b1c428f382c814b32a6ce90f2d8e39e2e635d49e498d1"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6db3cfb9b4fcecb4390db154e75b49578c87a3b9979b40cdf90d7e4b945656e1"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:debb633f3f7856f95ad957d9b9c781f8e2c6303ef21724ec94bea2ce2fcbd056"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-win32.whl", hash = "sha256:87071618d3d8ec8b186d53cb6e66955ef2a0e4fa63ccd3709c0c90ac5a43520f"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:e372d7dfd154009142631de2d316adad3cc1c36c32a38b16a4751ba78da2a397"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae4070f741f8d809075ef697877fd350ecf0b7c5837ed68738607ee0a2c572cf"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:58e875eb7016fd014c0eea46c6fa92b87b62c0cb31b9feae25cbbe62c919f54d"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dbd95e300367aa0827496fe75a1766d198d34385a58f97683fe6e07f89ca3e3c"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de0b4caa1c8a21394e8ce971997614a17648f94e1cd0640fbd6b4d14cab13a72"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:985c7965f62f6f32bf432e2681173db41336a9c2611693247069288bcb0c7f8b"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a15c1fe6d26e83fd2e5972425a772cca158eae58b05d4a25a4e474c221053e2d"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae55d592b02c4349525b6ed8f74c692509e5adffa842e582c0f861751701a673"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be4d9c2770044a59715eb57c1144dedea7c5d5ae80c68fb9959515037cde2008"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:851cf693fb3aaef71031237cd68699dded198657ec1e76a76eb8be58c03a5d1f"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:31bbaba7218904d2eabecf4feec0d07469284e952a27400f23b6628439439fa7"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:871d045d6ccc181fd863a3cd66ee8e395523ebfbc57f85f91f035f50cee8e3d4"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:501adc5eb6cd5f40a6f77fbd90e5ab915c8fd6e8c614af2db5561e16c600d6f3"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f5fb672c396d826ca16a022ac04c9dce74e00a1c344f6ad1a0fdc1ba1f332213"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-win32.whl", hash = "sha256:bb06098d019766ca16fc915ecaa455c1f1cd594204e7f840cd6258237b5079a8"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:8af5a8917b8af42295e86b64903156b4f110a30dca5f3b5aedea123fbd638bff"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7ae8e5142dcc7a49168f4055255dbcced01dc1714a90a21f87448dc8d90617d1"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5b70bab78accbc672f50e878a5b73ca692f45f5b5e25c8066d748c09405e6a55"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ceca5876032362ae73b83347be8b5dbd2d1faf3358deb38c9c88776779b2e2f"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34d95638ff3613849f473afc33f65c401a89f3b9528d0d213c7037c398a51296"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9edbe6a5bf8b56a4a84533ba2b2f489d0046e755c29616ef8830f9e7d9cf5728"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6a02a3c7950cafaadcd46a226ad9e12fc9744652cc69f9e5534f98b47f3bbcf"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10b8dd31e10f32410751b3430996f9807fc4d1587ca69772e2aa940a82ab571a"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edc0202099ea1d82844316604e17d2b175044f9bcb6b398aab781eba957224bd"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b891a2f68e09c5ef989007fac11476ed33c5c9994449a4e2c3386529d703dc8b"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:71ef3b9be10070360f289aea4838c784f8b851be3ba58cf796262b57775c2f14"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:55602981b2dbf8184c098bc10287e8c245e351cd4fdcad050bd7199d5a8bf514"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:46fb9970aa5eeca547d7aa0de5d4b124a288b42eaefac677bde805013c95725c"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:520b7a142d2524f999447b3a0cf95115df81c4f33003c51a6ab637cbda9d0bf4"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-win32.whl", hash = "sha256:8ec8ef42c6cd5856a7613dcd1eaf21e5573b2185263d87d27c8edcae33b62a61"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:baec8148d6b8bd5cee1ae138ba658c71f5b03e0d69d5907703e3e1df96db5e41"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63a6f59e2d01310f754c270e4a257426fe5a591dc487f1983b3bbe793cf6bac6"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d6bfc32a68bc0933819cfdfe45f9abc3cae3877e1d90aac7259d57e6e0f85b1"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f3100d86dcd03c03f7e9c3fdb23d92e32abbca07e7c13ebd7ddfbcb06f5991f"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39b70a6f88eebe239fa775190796d55a33cfb6d36b9ffdd37843f7c4c1b5dc67"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e12f8ee80aa35e746230a2af83e81bd6b52daa92a8afaef4fea4a2ce9b9f4fa"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b6cefa579e1237ce198619b76eaa148b71894fb0d6bcf9024460f9bf30fd228"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:61f1e3fb621f5420523abb71f5771a204b33c21d31e7d9d86881b2cffe92c47c"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4f6e2a839f83a6a76854d12dbebde50e4b1afa63e27761549d006fa53e9aa80e"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:1ec937546cad86d0dce5396748bf392bb7b62a9eeb8c66efac60e947697f0e58"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:82ca51ff0fc5b641a2d4e1cc8c5ff108699b7a56d7f3ad6f6da9dbb6f0145b48"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:633968254f8d421e70f91c6ebe71ed0ab140220469cf87a9857e21c16687c034"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-win32.whl", hash = "sha256:c0c72d34e7de5604df0fde3644cc079feee5e55464967d10b24b1de268deceb9"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:63accd11149c0f9a99e3bc095bbdb5a464862d77a7e309ad5938fbc8721235ae"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5a3580a4fdc4ac05f9e53c57f965e3594b2f99796231380adb2baaab96e22761"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2465aa50c9299d615d757c1c888bc6fef384b7c4aec81c05a0172b4400f98557"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb7cd68814308aade9d0c93c5bd2ade9f9441666f8ba5aa9c2d4b389cb5e2a45"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91e43805ccafa0a91831f9cd5443aa34528c0c3f2cc48c4cb3d9a7721053874b"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:854cc74367180beb327ab9d00f964f6d91da06450b0855cbbb09187bcdb02de5"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c15070ebf11b8b7fd1bfff7217e9324963c82dbdf6182ff7050519e350e7ad9f"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4c99f98fc3a1835af8179dcc9013f93594d0670e2fa80c83aa36346ee763d2"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fb765362688821404ad6cf86772fc54993ec11577cd5a92ac44b4c2ba52155b"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dced27917823df984fe0c80a5c4ad75cf58df0fbfae890bc08004cd3888922a2"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a66bcdf19c1a523e41b8e9d53d0cedbfbac2e93c649a2e9502cb26c014d0980c"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ecd26be9f112c4f96718290c10f4caea6cc798459a3a76636b817a0ed7874e42"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3f70fd716855cd3b855316b226a1ac8bdb3caf4f7ea96edcccc6f484217c9597"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:17a866d61259c7de1bdadef418a37755050ddb4b922df8b356503234fff7932c"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-win32.whl", hash = "sha256:548eefad783ed787b38cb6f9a574bd8664468cc76d1538215d510a3cd41406cb"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:45f053a0ece92c734d874861ffe6e3cc92150e32136dd59ab1fb070575189c97"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bc791ec3fd0c4309a753f95bb6c749ef0d8ea3aea91f07ee1cf06b7b02118f2f"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0c8c61fb505c7dad1d251c284e712d4e0372cef3b067f7ddf82a7fa82e1e9a93"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2c092be3885a1b7899cd85ce24acedc1034199d6fca1483fa2c3a35c86e43041"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2000c54c395d9e5e44c99dc7c20a64dc371f777faf8bae4919ad3e99ce5253e"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cb50a0335382aac15c31b61d8531bc9bb657cfd848b1d7158009472189f3d62"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c30187840d36d0ba2893bc3271a36a517a717f9fd383a98e2697ee890a37c273"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe81b35c33772e56f4b6cf62cf4aedc1762ef7162a31e6ac7fe5e40d0149eb67"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0bf89afcbcf4d1bb2652f6580e5e55a840fdf87384f6063c4a4f0c95e378656"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:06cf46bdff72f58645434d467bf5228080801298fbba19fe268a01b4534467f5"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3c66df3f41abee950d6638adc7eac4730a306b022570f71dd0bd6ba53503ab57"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd805513198304026bd379d1d516afbf6c3c13f4382134a2c526b8b854da1c2e"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:9505dc359edb6a330efcd2be825fdb73ee3e628d9010597aa1aee5aa63442e97"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:31445f38053476a0c4e6d12b047b08ced81e2c7c712e5a1ad97bc913256f91b2"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-win32.whl", hash = "sha256:bd28b31730f0e982ace8663d108e01199098432a30a4c410d06fe08fdb9e93f4"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:555fe186da0068d3354cdf4bbcbc609b0ecae4d04c921cc13e209eece7720727"}, + {file = "charset_normalizer-3.3.1-py3-none-any.whl", hash = "sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "cssselect" +version = "1.2.0" +description = "cssselect parses CSS3 Selectors and translates them to XPath 1.0" +optional = false +python-versions = ">=3.7" +files = [ + {file = "cssselect-1.2.0-py2.py3-none-any.whl", hash = "sha256:da1885f0c10b60c03ed5eccbb6b68d6eff248d91976fcde348f395d54c9fd35e"}, + {file = "cssselect-1.2.0.tar.gz", hash = "sha256:666b19839cfaddb9ce9d36bfe4c969132c647b92fc9088c4e23f786b30f1b3dc"}, +] + +[[package]] +name = "docutils" +version = "0.20.1" +description = "Docutils -- Python Documentation Utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"}, + {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.1.3" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, + {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "fake-useragent" +version = "1.3.0" +description = "Up-to-date simple useragent faker with real world database" +optional = false +python-versions = "*" +files = [ + {file = "fake-useragent-1.3.0.tar.gz", hash = "sha256:0b3a223b4c03e3df46b0e9ff53ad26cf4690f68871396b9c59a7fa6ee830c395"}, + {file = "fake_useragent-1.3.0-py3-none-any.whl", hash = "sha256:73cee1d10bcd1deb25a15e916f6674c537d2d9088ecb4d7af98c2619f83827d1"}, +] + +[package.dependencies] +importlib-resources = {version = ">=5.0", markers = "python_version < \"3.10\""} + +[[package]] +name = "html5lib" +version = "1.1" +description = "HTML parser based on the WHATWG HTML specification" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "html5lib-1.1-py2.py3-none-any.whl", hash = "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d"}, + {file = "html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"}, +] + +[package.dependencies] +six = ">=1.9" +webencodings = "*" + +[package.extras] +all = ["chardet (>=2.2)", "genshi", "lxml"] +chardet = ["chardet (>=2.2)"] +genshi = ["genshi"] +lxml = ["lxml"] + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] + +[[package]] +name = "imagesize" +version = "1.4.1" +description = "Getting image size from png/jpeg/jpeg2000/gif file" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, + {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, +] + +[[package]] +name = "importlib-metadata" +version = "6.8.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, + {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, +] + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] + +[[package]] +name = "importlib-resources" +version = "6.1.0" +description = "Read resources from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_resources-6.1.0-py3-none-any.whl", hash = "sha256:aa50258bbfa56d4e33fbd8aa3ef48ded10d1735f11532b8df95388cc6bdb7e83"}, + {file = "importlib_resources-6.1.0.tar.gz", hash = "sha256:9d48dcccc213325e810fd723e7fbb45ccb39f6cf5c31f00cf2b965f5f10f3cb9"}, +] + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "zipp (>=3.17)"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "jinja2" +version = "3.1.2" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, + {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "lxml" +version = "4.9.3" +description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" +files = [ + {file = "lxml-4.9.3-cp27-cp27m-macosx_11_0_x86_64.whl", hash = "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c"}, + {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d"}, + {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef"}, + {file = "lxml-4.9.3-cp27-cp27m-win32.whl", hash = "sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7"}, + {file = "lxml-4.9.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1"}, + {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb"}, + {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e"}, + {file = "lxml-4.9.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76"}, + {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23"}, + {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f"}, + {file = "lxml-4.9.3-cp310-cp310-win32.whl", hash = "sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85"}, + {file = "lxml-4.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d"}, + {file = "lxml-4.9.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b"}, + {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120"}, + {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6"}, + {file = "lxml-4.9.3-cp311-cp311-win32.whl", hash = "sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305"}, + {file = "lxml-4.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc"}, + {file = "lxml-4.9.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4"}, + {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be"}, + {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13"}, + {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9"}, + {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5"}, + {file = "lxml-4.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8"}, + {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7"}, + {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2"}, + {file = "lxml-4.9.3-cp35-cp35m-win32.whl", hash = "sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d"}, + {file = "lxml-4.9.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833"}, + {file = "lxml-4.9.3-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584"}, + {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287"}, + {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458"}, + {file = "lxml-4.9.3-cp36-cp36m-win32.whl", hash = "sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477"}, + {file = "lxml-4.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4"}, + {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a"}, + {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02"}, + {file = "lxml-4.9.3-cp37-cp37m-win32.whl", hash = "sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f"}, + {file = "lxml-4.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa"}, + {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40"}, + {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7"}, + {file = "lxml-4.9.3-cp38-cp38-win32.whl", hash = "sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574"}, + {file = "lxml-4.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96"}, + {file = "lxml-4.9.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432"}, + {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69"}, + {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50"}, + {file = "lxml-4.9.3-cp39-cp39-win32.whl", hash = "sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2"}, + {file = "lxml-4.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2"}, + {file = "lxml-4.9.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9"}, + {file = "lxml-4.9.3.tar.gz", hash = "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c"}, +] + +[package.extras] +cssselect = ["cssselect (>=0.7)"] +html5 = ["html5lib"] +htmlsoup = ["BeautifulSoup4"] +source = ["Cython (>=0.29.35)"] + +[[package]] +name = "markupsafe" +version = "2.1.3" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, + {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, + {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, +] + +[[package]] +name = "numpy" +version = "1.26.1" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = "<3.13,>=3.9" +files = [ + {file = "numpy-1.26.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82e871307a6331b5f09efda3c22e03c095d957f04bf6bc1804f30048d0e5e7af"}, + {file = "numpy-1.26.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdd9ec98f0063d93baeb01aad472a1a0840dee302842a2746a7a8e92968f9575"}, + {file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d78f269e0c4fd365fc2992c00353e4530d274ba68f15e968d8bc3c69ce5f5244"}, + {file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ab9163ca8aeb7fd32fe93866490654d2f7dda4e61bc6297bf72ce07fdc02f67"}, + {file = "numpy-1.26.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:78ca54b2f9daffa5f323f34cdf21e1d9779a54073f0018a3094ab907938331a2"}, + {file = "numpy-1.26.1-cp310-cp310-win32.whl", hash = "sha256:d1cfc92db6af1fd37a7bb58e55c8383b4aa1ba23d012bdbba26b4bcca45ac297"}, + {file = "numpy-1.26.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2984cb6caaf05294b8466966627e80bf6c7afd273279077679cb010acb0e5ab"}, + {file = "numpy-1.26.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cd7837b2b734ca72959a1caf3309457a318c934abef7a43a14bb984e574bbb9a"}, + {file = "numpy-1.26.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c59c046c31a43310ad0199d6299e59f57a289e22f0f36951ced1c9eac3665b9"}, + {file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d58e8c51a7cf43090d124d5073bc29ab2755822181fcad978b12e144e5e5a4b3"}, + {file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6081aed64714a18c72b168a9276095ef9155dd7888b9e74b5987808f0dd0a974"}, + {file = "numpy-1.26.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:97e5d6a9f0702c2863aaabf19f0d1b6c2628fbe476438ce0b5ce06e83085064c"}, + {file = "numpy-1.26.1-cp311-cp311-win32.whl", hash = "sha256:b9d45d1dbb9de84894cc50efece5b09939752a2d75aab3a8b0cef6f3a35ecd6b"}, + {file = "numpy-1.26.1-cp311-cp311-win_amd64.whl", hash = "sha256:3649d566e2fc067597125428db15d60eb42a4e0897fc48d28cb75dc2e0454e53"}, + {file = "numpy-1.26.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d1bd82d539607951cac963388534da3b7ea0e18b149a53cf883d8f699178c0f"}, + {file = "numpy-1.26.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:afd5ced4e5a96dac6725daeb5242a35494243f2239244fad10a90ce58b071d24"}, + {file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03fb25610ef560a6201ff06df4f8105292ba56e7cdd196ea350d123fc32e24e"}, + {file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcfaf015b79d1f9f9c9fd0731a907407dc3e45769262d657d754c3a028586124"}, + {file = "numpy-1.26.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e509cbc488c735b43b5ffea175235cec24bbc57b227ef1acc691725beb230d1c"}, + {file = "numpy-1.26.1-cp312-cp312-win32.whl", hash = "sha256:af22f3d8e228d84d1c0c44c1fbdeb80f97a15a0abe4f080960393a00db733b66"}, + {file = "numpy-1.26.1-cp312-cp312-win_amd64.whl", hash = "sha256:9f42284ebf91bdf32fafac29d29d4c07e5e9d1af862ea73686581773ef9e73a7"}, + {file = "numpy-1.26.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb894accfd16b867d8643fc2ba6c8617c78ba2828051e9a69511644ce86ce83e"}, + {file = "numpy-1.26.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e44ccb93f30c75dfc0c3aa3ce38f33486a75ec9abadabd4e59f114994a9c4617"}, + {file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9696aa2e35cc41e398a6d42d147cf326f8f9d81befcb399bc1ed7ffea339b64e"}, + {file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5b411040beead47a228bde3b2241100454a6abde9df139ed087bd73fc0a4908"}, + {file = "numpy-1.26.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1e11668d6f756ca5ef534b5be8653d16c5352cbb210a5c2a79ff288e937010d5"}, + {file = "numpy-1.26.1-cp39-cp39-win32.whl", hash = "sha256:d1d2c6b7dd618c41e202c59c1413ef9b2c8e8a15f5039e344af64195459e3104"}, + {file = "numpy-1.26.1-cp39-cp39-win_amd64.whl", hash = "sha256:59227c981d43425ca5e5c01094d59eb14e8772ce6975d4b2fc1e106a833d5ae2"}, + {file = "numpy-1.26.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:06934e1a22c54636a059215d6da99e23286424f316fddd979f5071093b648668"}, + {file = "numpy-1.26.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76ff661a867d9272cd2a99eed002470f46dbe0943a5ffd140f49be84f68ffc42"}, + {file = "numpy-1.26.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:6965888d65d2848e8768824ca8288db0a81263c1efccec881cb35a0d805fcd2f"}, + {file = "numpy-1.26.1.tar.gz", hash = "sha256:c8c6c72d4a9f831f328efb1312642a1cafafaa88981d9ab76368d50d07d93cbe"}, +] + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pandas" +version = "2.1.1" +description = "Powerful data structures for data analysis, time series, and statistics" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pandas-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:58d997dbee0d4b64f3cb881a24f918b5f25dd64ddf31f467bb9b67ae4c63a1e4"}, + {file = "pandas-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02304e11582c5d090e5a52aec726f31fe3f42895d6bfc1f28738f9b64b6f0614"}, + {file = "pandas-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffa8f0966de2c22de408d0e322db2faed6f6e74265aa0856f3824813cf124363"}, + {file = "pandas-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1f84c144dee086fe4f04a472b5cd51e680f061adf75c1ae4fc3a9275560f8f4"}, + {file = "pandas-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:75ce97667d06d69396d72be074f0556698c7f662029322027c226fd7a26965cb"}, + {file = "pandas-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:4c3f32fd7c4dccd035f71734df39231ac1a6ff95e8bdab8d891167197b7018d2"}, + {file = "pandas-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e2959720b70e106bb1d8b6eadd8ecd7c8e99ccdbe03ee03260877184bb2877d"}, + {file = "pandas-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:25e8474a8eb258e391e30c288eecec565bfed3e026f312b0cbd709a63906b6f8"}, + {file = "pandas-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8bd1685556f3374520466998929bade3076aeae77c3e67ada5ed2b90b4de7f0"}, + {file = "pandas-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc3657869c7902810f32bd072f0740487f9e030c1a3ab03e0af093db35a9d14e"}, + {file = "pandas-2.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:05674536bd477af36aa2effd4ec8f71b92234ce0cc174de34fd21e2ee99adbc2"}, + {file = "pandas-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:b407381258a667df49d58a1b637be33e514b07f9285feb27769cedb3ab3d0b3a"}, + {file = "pandas-2.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c747793c4e9dcece7bb20156179529898abf505fe32cb40c4052107a3c620b49"}, + {file = "pandas-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3bcad1e6fb34b727b016775bea407311f7721db87e5b409e6542f4546a4951ea"}, + {file = "pandas-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f5ec7740f9ccb90aec64edd71434711f58ee0ea7f5ed4ac48be11cfa9abf7317"}, + {file = "pandas-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:29deb61de5a8a93bdd033df328441a79fcf8dd3c12d5ed0b41a395eef9cd76f0"}, + {file = "pandas-2.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4f99bebf19b7e03cf80a4e770a3e65eee9dd4e2679039f542d7c1ace7b7b1daa"}, + {file = "pandas-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:84e7e910096416adec68075dc87b986ff202920fb8704e6d9c8c9897fe7332d6"}, + {file = "pandas-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:366da7b0e540d1b908886d4feb3d951f2f1e572e655c1160f5fde28ad4abb750"}, + {file = "pandas-2.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9e50e72b667415a816ac27dfcfe686dc5a0b02202e06196b943d54c4f9c7693e"}, + {file = "pandas-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc1ab6a25da197f03ebe6d8fa17273126120874386b4ac11c1d687df288542dd"}, + {file = "pandas-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0dbfea0dd3901ad4ce2306575c54348d98499c95be01b8d885a2737fe4d7a98"}, + {file = "pandas-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0489b0e6aa3d907e909aef92975edae89b1ee1654db5eafb9be633b0124abe97"}, + {file = "pandas-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:4cdb0fab0400c2cb46dafcf1a0fe084c8bb2480a1fa8d81e19d15e12e6d4ded2"}, + {file = "pandas-2.1.1.tar.gz", hash = "sha256:fecb198dc389429be557cde50a2d46da8434a17fe37d7d41ff102e3987fd947b"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.22.4", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2", markers = "python_version == \"3.11\""}, +] +python-dateutil = ">=2.8.2" +pytz = ">=2020.1" +tzdata = ">=2022.1" + +[package.extras] +all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"] +aws = ["s3fs (>=2022.05.0)"] +clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"] +compression = ["zstandard (>=0.17.0)"] +computation = ["scipy (>=1.8.1)", "xarray (>=2022.03.0)"] +consortium-standard = ["dataframe-api-compat (>=0.1.7)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pyxlsb (>=1.0.9)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)"] +feather = ["pyarrow (>=7.0.0)"] +fss = ["fsspec (>=2022.05.0)"] +gcp = ["gcsfs (>=2022.05.0)", "pandas-gbq (>=0.17.5)"] +hdf5 = ["tables (>=3.7.0)"] +html = ["beautifulsoup4 (>=4.11.1)", "html5lib (>=1.1)", "lxml (>=4.8.0)"] +mysql = ["SQLAlchemy (>=1.4.36)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.8.10)"] +parquet = ["pyarrow (>=7.0.0)"] +performance = ["bottleneck (>=1.3.4)", "numba (>=0.55.2)", "numexpr (>=2.8.0)"] +plot = ["matplotlib (>=3.6.1)"] +postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"] +spss = ["pyreadstat (>=1.1.5)"] +sql-other = ["SQLAlchemy (>=1.4.36)"] +test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.8.0)"] + +[[package]] +name = "parse" +version = "1.19.1" +description = "parse() is the opposite of format()" +optional = false +python-versions = "*" +files = [ + {file = "parse-1.19.1-py2.py3-none-any.whl", hash = "sha256:371ed3800dc63983832159cc9373156613947707bc448b5215473a219dbd4362"}, + {file = "parse-1.19.1.tar.gz", hash = "sha256:cc3a47236ff05da377617ddefa867b7ba983819c664e1afe46249e5b469be464"}, +] + +[[package]] +name = "pluggy" +version = "1.3.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pyee" +version = "8.2.2" +description = "A port of node.js's EventEmitter to python." +optional = false +python-versions = "*" +files = [ + {file = "pyee-8.2.2-py2.py3-none-any.whl", hash = "sha256:c09f56e36eb10bf23aa2aacf145f690ded75b990a3d9523fd478b005940303d2"}, + {file = "pyee-8.2.2.tar.gz", hash = "sha256:5c7e60f8df95710dbe17550e16ce0153f83990c00ef744841b43f371ed53ebea"}, +] + +[[package]] +name = "pygments" +version = "2.16.1" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, + {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, +] + +[package.extras] +plugins = ["importlib-metadata"] + +[[package]] +name = "pyppeteer" +version = "1.0.2" +description = "Headless chrome/chromium automation library (unofficial port of puppeteer)" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "pyppeteer-1.0.2-py3-none-any.whl", hash = "sha256:11a734d8f02c6b128035aba8faf32748f2016310a6a1cbc6aa5b1e2580742e8f"}, + {file = "pyppeteer-1.0.2.tar.gz", hash = "sha256:ddb0d15cb644720160d49abb1ad0d97e87a55581febf1b7531be9e983aad7742"}, +] + +[package.dependencies] +appdirs = ">=1.4.3,<2.0.0" +certifi = ">=2021" +importlib-metadata = ">=1.4" +pyee = ">=8.1.0,<9.0.0" +tqdm = ">=4.42.1,<5.0.0" +urllib3 = ">=1.25.8,<2.0.0" +websockets = ">=10.0,<11.0" + +[[package]] +name = "pyquery" +version = "2.0.0" +description = "A jquery-like library for python" +optional = false +python-versions = "*" +files = [ + {file = "pyquery-2.0.0-py3-none-any.whl", hash = "sha256:8dfc9b4b7c5f877d619bbae74b1898d5743f6ca248cfd5d72b504dd614da312f"}, + {file = "pyquery-2.0.0.tar.gz", hash = "sha256:963e8d4e90262ff6d8dec072ea97285dc374a2f69cad7776f4082abcf6a1d8ae"}, +] + +[package.dependencies] +cssselect = ">=1.2.0" +lxml = ">=2.1" + +[package.extras] +test = ["pytest", "pytest-cov", "requests", "webob", "webtest"] + +[[package]] +name = "pytest" +version = "7.4.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, + {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2023.3.post1" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, + {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "requests-html" +version = "0.10.0" +description = "HTML Parsing for Humans." +optional = false +python-versions = ">=3.6.0" +files = [ + {file = "requests-html-0.10.0.tar.gz", hash = "sha256:7e929ecfed95fb1d0994bb368295d6d7c4d06b03fcb900c33d7d0b17e6003947"}, + {file = "requests_html-0.10.0-py3-none-any.whl", hash = "sha256:cb8a78cf829c4eca9d6233f28524f65dd2bfaafb4bdbbc407f0a0b8f487df6e2"}, +] + +[package.dependencies] +bs4 = "*" +fake-useragent = "*" +parse = "*" +pyppeteer = ">=0.0.14" +pyquery = "*" +requests = "*" +w3lib = "*" + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "snowballstemmer" +version = "2.2.0" +description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +optional = false +python-versions = "*" +files = [ + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, +] + +[[package]] +name = "soupsieve" +version = "2.5" +description = "A modern CSS selector implementation for Beautiful Soup." +optional = false +python-versions = ">=3.8" +files = [ + {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, + {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, +] + +[[package]] +name = "sphinx" +version = "7.2.6" +description = "Python documentation generator" +optional = false +python-versions = ">=3.9" +files = [ + {file = "sphinx-7.2.6-py3-none-any.whl", hash = "sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560"}, + {file = "sphinx-7.2.6.tar.gz", hash = "sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5"}, +] + +[package.dependencies] +alabaster = ">=0.7,<0.8" +babel = ">=2.9" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +docutils = ">=0.18.1,<0.21" +imagesize = ">=1.3" +importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} +Jinja2 = ">=3.0" +packaging = ">=21.0" +Pygments = ">=2.14" +requests = ">=2.25.0" +snowballstemmer = ">=2.0" +sphinxcontrib-applehelp = "*" +sphinxcontrib-devhelp = "*" +sphinxcontrib-htmlhelp = ">=2.0.0" +sphinxcontrib-jsmath = "*" +sphinxcontrib-qthelp = "*" +sphinxcontrib-serializinghtml = ">=1.1.9" + +[package.extras] +docs = ["sphinxcontrib-websupport"] +lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-simplify", "isort", "mypy (>=0.990)", "ruff", "sphinx-lint", "types-requests"] +test = ["cython (>=3.0)", "filelock", "html5lib", "pytest (>=4.6)", "setuptools (>=67.0)"] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "1.0.7" +description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" +optional = false +python-versions = ">=3.9" +files = [ + {file = "sphinxcontrib_applehelp-1.0.7-py3-none-any.whl", hash = "sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d"}, + {file = "sphinxcontrib_applehelp-1.0.7.tar.gz", hash = "sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa"}, +] + +[package.dependencies] +Sphinx = ">=5" + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "1.0.5" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" +optional = false +python-versions = ">=3.9" +files = [ + {file = "sphinxcontrib_devhelp-1.0.5-py3-none-any.whl", hash = "sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f"}, + {file = "sphinxcontrib_devhelp-1.0.5.tar.gz", hash = "sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212"}, +] + +[package.dependencies] +Sphinx = ">=5" + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.0.4" +description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +optional = false +python-versions = ">=3.9" +files = [ + {file = "sphinxcontrib_htmlhelp-2.0.4-py3-none-any.whl", hash = "sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9"}, + {file = "sphinxcontrib_htmlhelp-2.0.4.tar.gz", hash = "sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a"}, +] + +[package.dependencies] +Sphinx = ">=5" + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["html5lib", "pytest"] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +description = "A sphinx extension which renders display math in HTML via JavaScript" +optional = false +python-versions = ">=3.5" +files = [ + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, +] + +[package.extras] +test = ["flake8", "mypy", "pytest"] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "1.0.6" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" +optional = false +python-versions = ">=3.9" +files = [ + {file = "sphinxcontrib_qthelp-1.0.6-py3-none-any.whl", hash = "sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4"}, + {file = "sphinxcontrib_qthelp-1.0.6.tar.gz", hash = "sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d"}, +] + +[package.dependencies] +Sphinx = ">=5" + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "1.1.9" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" +optional = false +python-versions = ">=3.9" +files = [ + {file = "sphinxcontrib_serializinghtml-1.1.9-py3-none-any.whl", hash = "sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1"}, + {file = "sphinxcontrib_serializinghtml-1.1.9.tar.gz", hash = "sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54"}, +] + +[package.dependencies] +Sphinx = ">=5" + +[package.extras] +lint = ["docutils-stubs", "flake8", "mypy"] +test = ["pytest"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "tqdm" +version = "4.66.1" +description = "Fast, Extensible Progress Meter" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, + {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + +[[package]] +name = "tzdata" +version = "2023.3" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, + {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, +] + +[[package]] +name = "urllib3" +version = "1.26.18" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, +] + +[package.extras] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[[package]] +name = "w3lib" +version = "2.1.2" +description = "Library of web-related functions" +optional = false +python-versions = ">=3.7" +files = [ + {file = "w3lib-2.1.2-py3-none-any.whl", hash = "sha256:c4432926e739caa8e3f49f5de783f336df563d9490416aebd5d39fb896d264e7"}, + {file = "w3lib-2.1.2.tar.gz", hash = "sha256:ed5b74e997eea2abe3c1321f916e344144ee8e9072a6f33463ee8e57f858a4b1"}, +] + +[[package]] +name = "webencodings" +version = "0.5.1" +description = "Character encoding aliases for legacy web content" +optional = false +python-versions = "*" +files = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] + +[[package]] +name = "websockets" +version = "10.4" +description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "websockets-10.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d58804e996d7d2307173d56c297cf7bc132c52df27a3efaac5e8d43e36c21c48"}, + {file = "websockets-10.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc0b82d728fe21a0d03e65f81980abbbcb13b5387f733a1a870672c5be26edab"}, + {file = "websockets-10.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ba089c499e1f4155d2a3c2a05d2878a3428cf321c848f2b5a45ce55f0d7d310c"}, + {file = "websockets-10.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33d69ca7612f0ddff3316b0c7b33ca180d464ecac2d115805c044bf0a3b0d032"}, + {file = "websockets-10.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62e627f6b6d4aed919a2052efc408da7a545c606268d5ab5bfab4432734b82b4"}, + {file = "websockets-10.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ea7b82bfcae927eeffc55d2ffa31665dc7fec7b8dc654506b8e5a518eb4d50"}, + {file = "websockets-10.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e0cb5cc6ece6ffa75baccfd5c02cffe776f3f5c8bf486811f9d3ea3453676ce8"}, + {file = "websockets-10.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ae5e95cfb53ab1da62185e23b3130e11d64431179debac6dc3c6acf08760e9b1"}, + {file = "websockets-10.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7c584f366f46ba667cfa66020344886cf47088e79c9b9d39c84ce9ea98aaa331"}, + {file = "websockets-10.4-cp310-cp310-win32.whl", hash = "sha256:b029fb2032ae4724d8ae8d4f6b363f2cc39e4c7b12454df8df7f0f563ed3e61a"}, + {file = "websockets-10.4-cp310-cp310-win_amd64.whl", hash = "sha256:8dc96f64ae43dde92530775e9cb169979f414dcf5cff670455d81a6823b42089"}, + {file = "websockets-10.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47a2964021f2110116cc1125b3e6d87ab5ad16dea161949e7244ec583b905bb4"}, + {file = "websockets-10.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e789376b52c295c4946403bd0efecf27ab98f05319df4583d3c48e43c7342c2f"}, + {file = "websockets-10.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d3f0b61c45c3fa9a349cf484962c559a8a1d80dae6977276df8fd1fa5e3cb8c"}, + {file = "websockets-10.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f55b5905705725af31ccef50e55391621532cd64fbf0bc6f4bac935f0fccec46"}, + {file = "websockets-10.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00c870522cdb69cd625b93f002961ffb0c095394f06ba8c48f17eef7c1541f96"}, + {file = "websockets-10.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f38706e0b15d3c20ef6259fd4bc1700cd133b06c3c1bb108ffe3f8947be15fa"}, + {file = "websockets-10.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f2c38d588887a609191d30e902df2a32711f708abfd85d318ca9b367258cfd0c"}, + {file = "websockets-10.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:fe10ddc59b304cb19a1bdf5bd0a7719cbbc9fbdd57ac80ed436b709fcf889106"}, + {file = "websockets-10.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:90fcf8929836d4a0e964d799a58823547df5a5e9afa83081761630553be731f9"}, + {file = "websockets-10.4-cp311-cp311-win32.whl", hash = "sha256:b9968694c5f467bf67ef97ae7ad4d56d14be2751000c1207d31bf3bb8860bae8"}, + {file = "websockets-10.4-cp311-cp311-win_amd64.whl", hash = "sha256:a7a240d7a74bf8d5cb3bfe6be7f21697a28ec4b1a437607bae08ac7acf5b4882"}, + {file = "websockets-10.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:74de2b894b47f1d21cbd0b37a5e2b2392ad95d17ae983e64727e18eb281fe7cb"}, + {file = "websockets-10.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3a686ecb4aa0d64ae60c9c9f1a7d5d46cab9bfb5d91a2d303d00e2cd4c4c5cc"}, + {file = "websockets-10.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d15c968ea7a65211e084f523151dbf8ae44634de03c801b8bd070b74e85033"}, + {file = "websockets-10.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00213676a2e46b6ebf6045bc11d0f529d9120baa6f58d122b4021ad92adabd41"}, + {file = "websockets-10.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:e23173580d740bf8822fd0379e4bf30aa1d5a92a4f252d34e893070c081050df"}, + {file = "websockets-10.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:dd500e0a5e11969cdd3320935ca2ff1e936f2358f9c2e61f100a1660933320ea"}, + {file = "websockets-10.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4239b6027e3d66a89446908ff3027d2737afc1a375f8fd3eea630a4842ec9a0c"}, + {file = "websockets-10.4-cp37-cp37m-win32.whl", hash = "sha256:8a5cc00546e0a701da4639aa0bbcb0ae2bb678c87f46da01ac2d789e1f2d2038"}, + {file = "websockets-10.4-cp37-cp37m-win_amd64.whl", hash = "sha256:a9f9a735deaf9a0cadc2d8c50d1a5bcdbae8b6e539c6e08237bc4082d7c13f28"}, + {file = "websockets-10.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5c1289596042fad2cdceb05e1ebf7aadf9995c928e0da2b7a4e99494953b1b94"}, + {file = "websockets-10.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0cff816f51fb33c26d6e2b16b5c7d48eaa31dae5488ace6aae468b361f422b63"}, + {file = "websockets-10.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dd9becd5fe29773d140d68d607d66a38f60e31b86df75332703757ee645b6faf"}, + {file = "websockets-10.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45ec8e75b7dbc9539cbfafa570742fe4f676eb8b0d3694b67dabe2f2ceed8aa6"}, + {file = "websockets-10.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f72e5cd0f18f262f5da20efa9e241699e0cf3a766317a17392550c9ad7b37d8"}, + {file = "websockets-10.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:185929b4808b36a79c65b7865783b87b6841e852ef5407a2fb0c03381092fa3b"}, + {file = "websockets-10.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7d27a7e34c313b3a7f91adcd05134315002aaf8540d7b4f90336beafaea6217c"}, + {file = "websockets-10.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:884be66c76a444c59f801ac13f40c76f176f1bfa815ef5b8ed44321e74f1600b"}, + {file = "websockets-10.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:931c039af54fc195fe6ad536fde4b0de04da9d5916e78e55405436348cfb0e56"}, + {file = "websockets-10.4-cp38-cp38-win32.whl", hash = "sha256:db3c336f9eda2532ec0fd8ea49fef7a8df8f6c804cdf4f39e5c5c0d4a4ad9a7a"}, + {file = "websockets-10.4-cp38-cp38-win_amd64.whl", hash = "sha256:48c08473563323f9c9debac781ecf66f94ad5a3680a38fe84dee5388cf5acaf6"}, + {file = "websockets-10.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:40e826de3085721dabc7cf9bfd41682dadc02286d8cf149b3ad05bff89311e4f"}, + {file = "websockets-10.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:56029457f219ade1f2fc12a6504ea61e14ee227a815531f9738e41203a429112"}, + {file = "websockets-10.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f5fc088b7a32f244c519a048c170f14cf2251b849ef0e20cbbb0fdf0fdaf556f"}, + {file = "websockets-10.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fc8709c00704194213d45e455adc106ff9e87658297f72d544220e32029cd3d"}, + {file = "websockets-10.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0154f7691e4fe6c2b2bc275b5701e8b158dae92a1ab229e2b940efe11905dff4"}, + {file = "websockets-10.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c6d2264f485f0b53adf22697ac11e261ce84805c232ed5dbe6b1bcb84b00ff0"}, + {file = "websockets-10.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9bc42e8402dc5e9905fb8b9649f57efcb2056693b7e88faa8fb029256ba9c68c"}, + {file = "websockets-10.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:edc344de4dac1d89300a053ac973299e82d3db56330f3494905643bb68801269"}, + {file = "websockets-10.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:84bc2a7d075f32f6ed98652db3a680a17a4edb21ca7f80fe42e38753a58ee02b"}, + {file = "websockets-10.4-cp39-cp39-win32.whl", hash = "sha256:c94ae4faf2d09f7c81847c63843f84fe47bf6253c9d60b20f25edfd30fb12588"}, + {file = "websockets-10.4-cp39-cp39-win_amd64.whl", hash = "sha256:bbccd847aa0c3a69b5f691a84d2341a4f8a629c6922558f2a70611305f902d74"}, + {file = "websockets-10.4-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:82ff5e1cae4e855147fd57a2863376ed7454134c2bf49ec604dfe71e446e2193"}, + {file = "websockets-10.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d210abe51b5da0ffdbf7b43eed0cfdff8a55a1ab17abbec4301c9ff077dd0342"}, + {file = "websockets-10.4-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:942de28af58f352a6f588bc72490ae0f4ccd6dfc2bd3de5945b882a078e4e179"}, + {file = "websockets-10.4-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9b27d6c1c6cd53dc93614967e9ce00ae7f864a2d9f99fe5ed86706e1ecbf485"}, + {file = "websockets-10.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3d3cac3e32b2c8414f4f87c1b2ab686fa6284a980ba283617404377cd448f631"}, + {file = "websockets-10.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:da39dd03d130162deb63da51f6e66ed73032ae62e74aaccc4236e30edccddbb0"}, + {file = "websockets-10.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389f8dbb5c489e305fb113ca1b6bdcdaa130923f77485db5b189de343a179393"}, + {file = "websockets-10.4-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09a1814bb15eff7069e51fed0826df0bc0702652b5cb8f87697d469d79c23576"}, + {file = "websockets-10.4-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff64a1d38d156d429404aaa84b27305e957fd10c30e5880d1765c9480bea490f"}, + {file = "websockets-10.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b343f521b047493dc4022dd338fc6db9d9282658862756b4f6fd0e996c1380e1"}, + {file = "websockets-10.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:932af322458da7e4e35df32f050389e13d3d96b09d274b22a7aa1808f292fee4"}, + {file = "websockets-10.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a4162139374a49eb18ef5b2f4da1dd95c994588f5033d64e0bbfda4b6b6fcf"}, + {file = "websockets-10.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c57e4c1349fbe0e446c9fa7b19ed2f8a4417233b6984277cce392819123142d3"}, + {file = "websockets-10.4-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b627c266f295de9dea86bd1112ed3d5fafb69a348af30a2422e16590a8ecba13"}, + {file = "websockets-10.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:05a7233089f8bd355e8cbe127c2e8ca0b4ea55467861906b80d2ebc7db4d6b72"}, + {file = "websockets-10.4.tar.gz", hash = "sha256:eef610b23933c54d5d921c92578ae5f89813438fded840c2e9809d378dc765d3"}, +] + +[[package]] +name = "zipp" +version = "3.17.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, + {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.9, <=3.11" +content-hash = "b27b0f492407baac40cb57be6c4353488b0b8b11dbf24406e0278205621007f5" diff --git a/pyproject.toml b/pyproject.toml index f2bd017..719eafe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,9 +8,18 @@ readme = "README.md" [tool.poetry.dependencies] python = ">=3.9, <=3.11" +requests-html = "^0.10.0" +pandas = "^2.1.1" +html5lib = "^1.1" [tool.poetry.group.dev.dependencies] +[tool.poetry.group.test.dependencies] +pytest = "^7.4.3" + +[tool.poetry.group.doc.dependencies] +sphinx = "^7.2.6" + [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" From 23625679c56d3ca93ca8a6de37772939a463d710 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 25 Oct 2023 15:48:55 -0300 Subject: [PATCH 143/147] chore: upd package metadata --- poetry.lock | 2 +- pyproject.toml | 33 +++++++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index 26edeab..c67f9d9 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1166,4 +1166,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = ">=3.9, <=3.11" -content-hash = "b27b0f492407baac40cb57be6c4353488b0b8b11dbf24406e0278205621007f5" +content-hash = "92c2dcb3345b8ef8b894ac4020dffc89d09da24713c35e5bf164cf46eb8cf994" diff --git a/pyproject.toml b/pyproject.toml index 719eafe..88581e6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,6 +5,35 @@ description = "Get live, population, geography, projected, and historical data f authors = ["Matheus Felipe "] license = "MIT" readme = "README.md" +homepage = "https://github.com/matheusfelipeog/worldometer" +repository = "https://github.com/matheusfelipeog/worldometer" +documentation = "https://worldometer.readthedocs.io" +packages = [{include = "worldometer"}] +keywords = [ + "worldometer", "worldometers", "worldometer-api", "worldometer-scraping", + "world-data", "world-metrics", "metrics", "real-time-data", "real-time-metrics", + "api", "scraping", "requests-html", "livedata", "historical", "historical-data", + "live", "world", "data" +] +classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'License :: OSI Approved :: MIT License', + 'Natural Language :: English', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: Implementation', + 'Topic :: Software Development :: Libraries', + 'Topic :: Software Development :: Libraries :: Python Modules' +] + +[tool.poetry.urls] +"Bug Tracker" = "https://github.com/matheusfelipeog/worldometer/issues" +"Pull Requets" = "https://github.com/matheusfelipeog/worldometer/pulls" [tool.poetry.dependencies] python = ">=3.9, <=3.11" @@ -13,11 +42,7 @@ pandas = "^2.1.1" html5lib = "^1.1" [tool.poetry.group.dev.dependencies] - -[tool.poetry.group.test.dependencies] pytest = "^7.4.3" - -[tool.poetry.group.doc.dependencies] sphinx = "^7.2.6" [build-system] From 1adac616e640fb5cef6b7ee86a7899a1ffed4fe3 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 25 Oct 2023 15:50:19 -0300 Subject: [PATCH 144/147] chore: fix text of url --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 88581e6..11d2c46 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -33,7 +33,7 @@ classifiers = [ [tool.poetry.urls] "Bug Tracker" = "https://github.com/matheusfelipeog/worldometer/issues" -"Pull Requets" = "https://github.com/matheusfelipeog/worldometer/pulls" +"Pull Requests" = "https://github.com/matheusfelipeog/worldometer/pulls" [tool.poetry.dependencies] python = ">=3.9, <=3.11" From c3cfd458cb7f8e38c30d18b2d20910ed19acc9a4 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 25 Oct 2023 16:46:24 -0300 Subject: [PATCH 145/147] build: gh action to run tests --- .github/workflows/tests.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..6a03167 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,36 @@ +name: Tests + +on: + push: + branches: [master, dev] + pull_request: + branches: [master, dev] + +jobs: + unittests: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.9', '3.10', '3.11'] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install poetry + run: | + python -m pip install --upgrade pip + pip install poetry + + - name: Install dependencies + run: | + poetry install + + - name: Run unittests + run: | + poetry run pytest --verbose \ No newline at end of file From bcf81084e7779ae8bfdba9b366ecf7f2b6cf4687 Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 25 Oct 2023 17:08:17 -0300 Subject: [PATCH 146/147] chore: fix support to python 3.11 --- poetry.lock | 4 ++-- pyproject.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index c67f9d9..1fa92b1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1165,5 +1165,5 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" -python-versions = ">=3.9, <=3.11" -content-hash = "92c2dcb3345b8ef8b894ac4020dffc89d09da24713c35e5bf164cf46eb8cf994" +python-versions = ">=3.9, <3.12" +content-hash = "d0a7253d05c9fae987b2d7314a2fdac5a4de7d25ae6e6127d03e201192e408bd" diff --git a/pyproject.toml b/pyproject.toml index 11d2c46..7f46518 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ classifiers = [ "Pull Requests" = "https://github.com/matheusfelipeog/worldometer/pulls" [tool.poetry.dependencies] -python = ">=3.9, <=3.11" +python = ">=3.9, <3.12" requests-html = "^0.10.0" pandas = "^2.1.1" html5lib = "^1.1" From 5e89f17249a44bb816f816c38e3f03a2d579b28c Mon Sep 17 00:00:00 2001 From: Matheus Felipe Date: Wed, 25 Oct 2023 17:17:47 -0300 Subject: [PATCH 147/147] chore: delete files from old package manager --- Pipfile | 14 - Pipfile.lock | 948 --------------------------------------------------- 2 files changed, 962 deletions(-) delete mode 100644 Pipfile delete mode 100644 Pipfile.lock diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 34e8d7c..0000000 --- a/Pipfile +++ /dev/null @@ -1,14 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -requests-html = "0.10.0" -pandas = "*" -html5lib = "*" - -[dev-packages] -pylint = "*" -sphinx = "*" -pytest = "*" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index cc1061e..0000000 --- a/Pipfile.lock +++ /dev/null @@ -1,948 +0,0 @@ -{ - "_meta": { - "hash": { - "sha256": "47c5034649fe3fcf79ef440e14154f3e1fe867f1bfe7432a3633f74e3906f939" - }, - "pipfile-spec": 6, - "requires": {}, - "sources": [ - { - "name": "pypi", - "url": "https://pypi.org/simple", - "verify_ssl": true - } - ] - }, - "default": { - "appdirs": { - "hashes": [ - "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", - "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" - ], - "version": "==1.4.4" - }, - "beautifulsoup4": { - "hashes": [ - "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da", - "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a" - ], - "markers": "python_full_version >= '3.6.0'", - "version": "==4.12.2" - }, - "bs4": { - "hashes": [ - "sha256:36ecea1fd7cc5c0c6e4a1ff075df26d50da647b75376626cc186e2212886dd3a" - ], - "version": "==0.0.1" - }, - "certifi": { - "hashes": [ - "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082", - "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9" - ], - "markers": "python_version >= '3.6'", - "version": "==2023.7.22" - }, - "charset-normalizer": { - "hashes": [ - "sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843", - "sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786", - "sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e", - "sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8", - "sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4", - "sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa", - "sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d", - "sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82", - "sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7", - "sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895", - "sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d", - "sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a", - "sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382", - "sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678", - "sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b", - "sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e", - "sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741", - "sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4", - "sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596", - "sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9", - "sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69", - "sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c", - "sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77", - "sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13", - "sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459", - "sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e", - "sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7", - "sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908", - "sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a", - "sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f", - "sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8", - "sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482", - "sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d", - "sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d", - "sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545", - "sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34", - "sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86", - "sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6", - "sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe", - "sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e", - "sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc", - "sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7", - "sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd", - "sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c", - "sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557", - "sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a", - "sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89", - "sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078", - "sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e", - "sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4", - "sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403", - "sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0", - "sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89", - "sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115", - "sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9", - "sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05", - "sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a", - "sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec", - "sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56", - "sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38", - "sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479", - "sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c", - "sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e", - "sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd", - "sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186", - "sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455", - "sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c", - "sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65", - "sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78", - "sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287", - "sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df", - "sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43", - "sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1", - "sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7", - "sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989", - "sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a", - "sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63", - "sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884", - "sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649", - "sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810", - "sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828", - "sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4", - "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2", - "sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd", - "sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5", - "sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe", - "sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293", - "sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e", - "sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e", - "sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8" - ], - "markers": "python_full_version >= '3.7.0'", - "version": "==3.3.0" - }, - "cssselect": { - "hashes": [ - "sha256:666b19839cfaddb9ce9d36bfe4c969132c647b92fc9088c4e23f786b30f1b3dc", - "sha256:da1885f0c10b60c03ed5eccbb6b68d6eff248d91976fcde348f395d54c9fd35e" - ], - "markers": "python_version >= '3.7'", - "version": "==1.2.0" - }, - "fake-useragent": { - "hashes": [ - "sha256:0b3a223b4c03e3df46b0e9ff53ad26cf4690f68871396b9c59a7fa6ee830c395", - "sha256:73cee1d10bcd1deb25a15e916f6674c537d2d9088ecb4d7af98c2619f83827d1" - ], - "version": "==1.3.0" - }, - "html5lib": { - "hashes": [ - "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d", - "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f" - ], - "index": "pypi", - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==1.1" - }, - "idna": { - "hashes": [ - "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", - "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" - ], - "markers": "python_version >= '3.5'", - "version": "==3.4" - }, - "importlib-metadata": { - "hashes": [ - "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb", - "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743" - ], - "markers": "python_version >= '3.8'", - "version": "==6.8.0" - }, - "lxml": { - "hashes": [ - "sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3", - "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d", - "sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a", - "sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120", - "sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305", - "sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287", - "sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23", - "sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52", - "sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f", - "sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4", - "sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584", - "sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f", - "sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693", - "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef", - "sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5", - "sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02", - "sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc", - "sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7", - "sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da", - "sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a", - "sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40", - "sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8", - "sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd", - "sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601", - "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c", - "sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be", - "sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2", - "sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c", - "sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129", - "sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc", - "sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2", - "sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1", - "sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7", - "sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d", - "sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477", - "sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d", - "sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e", - "sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7", - "sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2", - "sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574", - "sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf", - "sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b", - "sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98", - "sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12", - "sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42", - "sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35", - "sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d", - "sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce", - "sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d", - "sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f", - "sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db", - "sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4", - "sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694", - "sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac", - "sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2", - "sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7", - "sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96", - "sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d", - "sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b", - "sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a", - "sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13", - "sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340", - "sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6", - "sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458", - "sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c", - "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c", - "sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9", - "sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432", - "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991", - "sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69", - "sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf", - "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb", - "sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b", - "sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833", - "sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76", - "sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85", - "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e", - "sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50", - "sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8", - "sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4", - "sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b", - "sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5", - "sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190", - "sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7", - "sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa", - "sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0", - "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9", - "sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0", - "sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b", - "sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5", - "sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7", - "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==4.9.3" - }, - "numpy": { - "hashes": [ - "sha256:06934e1a22c54636a059215d6da99e23286424f316fddd979f5071093b648668", - "sha256:1c59c046c31a43310ad0199d6299e59f57a289e22f0f36951ced1c9eac3665b9", - "sha256:1d1bd82d539607951cac963388534da3b7ea0e18b149a53cf883d8f699178c0f", - "sha256:1e11668d6f756ca5ef534b5be8653d16c5352cbb210a5c2a79ff288e937010d5", - "sha256:3649d566e2fc067597125428db15d60eb42a4e0897fc48d28cb75dc2e0454e53", - "sha256:59227c981d43425ca5e5c01094d59eb14e8772ce6975d4b2fc1e106a833d5ae2", - "sha256:6081aed64714a18c72b168a9276095ef9155dd7888b9e74b5987808f0dd0a974", - "sha256:6965888d65d2848e8768824ca8288db0a81263c1efccec881cb35a0d805fcd2f", - "sha256:76ff661a867d9272cd2a99eed002470f46dbe0943a5ffd140f49be84f68ffc42", - "sha256:78ca54b2f9daffa5f323f34cdf21e1d9779a54073f0018a3094ab907938331a2", - "sha256:82e871307a6331b5f09efda3c22e03c095d957f04bf6bc1804f30048d0e5e7af", - "sha256:8ab9163ca8aeb7fd32fe93866490654d2f7dda4e61bc6297bf72ce07fdc02f67", - "sha256:9696aa2e35cc41e398a6d42d147cf326f8f9d81befcb399bc1ed7ffea339b64e", - "sha256:97e5d6a9f0702c2863aaabf19f0d1b6c2628fbe476438ce0b5ce06e83085064c", - "sha256:9f42284ebf91bdf32fafac29d29d4c07e5e9d1af862ea73686581773ef9e73a7", - "sha256:a03fb25610ef560a6201ff06df4f8105292ba56e7cdd196ea350d123fc32e24e", - "sha256:a5b411040beead47a228bde3b2241100454a6abde9df139ed087bd73fc0a4908", - "sha256:af22f3d8e228d84d1c0c44c1fbdeb80f97a15a0abe4f080960393a00db733b66", - "sha256:afd5ced4e5a96dac6725daeb5242a35494243f2239244fad10a90ce58b071d24", - "sha256:b9d45d1dbb9de84894cc50efece5b09939752a2d75aab3a8b0cef6f3a35ecd6b", - "sha256:bb894accfd16b867d8643fc2ba6c8617c78ba2828051e9a69511644ce86ce83e", - "sha256:c8c6c72d4a9f831f328efb1312642a1cafafaa88981d9ab76368d50d07d93cbe", - "sha256:cd7837b2b734ca72959a1caf3309457a318c934abef7a43a14bb984e574bbb9a", - "sha256:cdd9ec98f0063d93baeb01aad472a1a0840dee302842a2746a7a8e92968f9575", - "sha256:d1cfc92db6af1fd37a7bb58e55c8383b4aa1ba23d012bdbba26b4bcca45ac297", - "sha256:d1d2c6b7dd618c41e202c59c1413ef9b2c8e8a15f5039e344af64195459e3104", - "sha256:d2984cb6caaf05294b8466966627e80bf6c7afd273279077679cb010acb0e5ab", - "sha256:d58e8c51a7cf43090d124d5073bc29ab2755822181fcad978b12e144e5e5a4b3", - "sha256:d78f269e0c4fd365fc2992c00353e4530d274ba68f15e968d8bc3c69ce5f5244", - "sha256:dcfaf015b79d1f9f9c9fd0731a907407dc3e45769262d657d754c3a028586124", - "sha256:e44ccb93f30c75dfc0c3aa3ce38f33486a75ec9abadabd4e59f114994a9c4617", - "sha256:e509cbc488c735b43b5ffea175235cec24bbc57b227ef1acc691725beb230d1c" - ], - "markers": "python_version == '3.11'", - "version": "==1.26.1" - }, - "pandas": { - "hashes": [ - "sha256:02304e11582c5d090e5a52aec726f31fe3f42895d6bfc1f28738f9b64b6f0614", - "sha256:0489b0e6aa3d907e909aef92975edae89b1ee1654db5eafb9be633b0124abe97", - "sha256:05674536bd477af36aa2effd4ec8f71b92234ce0cc174de34fd21e2ee99adbc2", - "sha256:25e8474a8eb258e391e30c288eecec565bfed3e026f312b0cbd709a63906b6f8", - "sha256:29deb61de5a8a93bdd033df328441a79fcf8dd3c12d5ed0b41a395eef9cd76f0", - "sha256:366da7b0e540d1b908886d4feb3d951f2f1e572e655c1160f5fde28ad4abb750", - "sha256:3bcad1e6fb34b727b016775bea407311f7721db87e5b409e6542f4546a4951ea", - "sha256:4c3f32fd7c4dccd035f71734df39231ac1a6ff95e8bdab8d891167197b7018d2", - "sha256:4cdb0fab0400c2cb46dafcf1a0fe084c8bb2480a1fa8d81e19d15e12e6d4ded2", - "sha256:4f99bebf19b7e03cf80a4e770a3e65eee9dd4e2679039f542d7c1ace7b7b1daa", - "sha256:58d997dbee0d4b64f3cb881a24f918b5f25dd64ddf31f467bb9b67ae4c63a1e4", - "sha256:75ce97667d06d69396d72be074f0556698c7f662029322027c226fd7a26965cb", - "sha256:84e7e910096416adec68075dc87b986ff202920fb8704e6d9c8c9897fe7332d6", - "sha256:9e2959720b70e106bb1d8b6eadd8ecd7c8e99ccdbe03ee03260877184bb2877d", - "sha256:9e50e72b667415a816ac27dfcfe686dc5a0b02202e06196b943d54c4f9c7693e", - "sha256:a0dbfea0dd3901ad4ce2306575c54348d98499c95be01b8d885a2737fe4d7a98", - "sha256:b407381258a667df49d58a1b637be33e514b07f9285feb27769cedb3ab3d0b3a", - "sha256:b8bd1685556f3374520466998929bade3076aeae77c3e67ada5ed2b90b4de7f0", - "sha256:c1f84c144dee086fe4f04a472b5cd51e680f061adf75c1ae4fc3a9275560f8f4", - "sha256:c747793c4e9dcece7bb20156179529898abf505fe32cb40c4052107a3c620b49", - "sha256:cc1ab6a25da197f03ebe6d8fa17273126120874386b4ac11c1d687df288542dd", - "sha256:dc3657869c7902810f32bd072f0740487f9e030c1a3ab03e0af093db35a9d14e", - "sha256:f5ec7740f9ccb90aec64edd71434711f58ee0ea7f5ed4ac48be11cfa9abf7317", - "sha256:fecb198dc389429be557cde50a2d46da8434a17fe37d7d41ff102e3987fd947b", - "sha256:ffa8f0966de2c22de408d0e322db2faed6f6e74265aa0856f3824813cf124363" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==2.1.1" - }, - "parse": { - "hashes": [ - "sha256:371ed3800dc63983832159cc9373156613947707bc448b5215473a219dbd4362", - "sha256:cc3a47236ff05da377617ddefa867b7ba983819c664e1afe46249e5b469be464" - ], - "version": "==1.19.1" - }, - "pyee": { - "hashes": [ - "sha256:5c7e60f8df95710dbe17550e16ce0153f83990c00ef744841b43f371ed53ebea", - "sha256:c09f56e36eb10bf23aa2aacf145f690ded75b990a3d9523fd478b005940303d2" - ], - "version": "==8.2.2" - }, - "pyppeteer": { - "hashes": [ - "sha256:11a734d8f02c6b128035aba8faf32748f2016310a6a1cbc6aa5b1e2580742e8f", - "sha256:ddb0d15cb644720160d49abb1ad0d97e87a55581febf1b7531be9e983aad7742" - ], - "markers": "python_version >= '3.7' and python_version < '4.0'", - "version": "==1.0.2" - }, - "pyquery": { - "hashes": [ - "sha256:8dfc9b4b7c5f877d619bbae74b1898d5743f6ca248cfd5d72b504dd614da312f", - "sha256:963e8d4e90262ff6d8dec072ea97285dc374a2f69cad7776f4082abcf6a1d8ae" - ], - "version": "==2.0.0" - }, - "python-dateutil": { - "hashes": [ - "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", - "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", - "version": "==2.8.2" - }, - "pytz": { - "hashes": [ - "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b", - "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7" - ], - "version": "==2023.3.post1" - }, - "requests": { - "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" - ], - "markers": "python_version >= '3.7'", - "version": "==2.31.0" - }, - "requests-html": { - "hashes": [ - "sha256:7e929ecfed95fb1d0994bb368295d6d7c4d06b03fcb900c33d7d0b17e6003947", - "sha256:cb8a78cf829c4eca9d6233f28524f65dd2bfaafb4bdbbc407f0a0b8f487df6e2" - ], - "index": "pypi", - "markers": "python_full_version >= '3.6.0'", - "version": "==0.10.0" - }, - "six": { - "hashes": [ - "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", - "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2'", - "version": "==1.16.0" - }, - "soupsieve": { - "hashes": [ - "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690", - "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7" - ], - "markers": "python_version >= '3.8'", - "version": "==2.5" - }, - "tqdm": { - "hashes": [ - "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386", - "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7" - ], - "markers": "python_version >= '3.7'", - "version": "==4.66.1" - }, - "tzdata": { - "hashes": [ - "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a", - "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda" - ], - "markers": "python_version >= '2'", - "version": "==2023.3" - }, - "urllib3": { - "hashes": [ - "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07", - "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.18" - }, - "w3lib": { - "hashes": [ - "sha256:c4432926e739caa8e3f49f5de783f336df563d9490416aebd5d39fb896d264e7", - "sha256:ed5b74e997eea2abe3c1321f916e344144ee8e9072a6f33463ee8e57f858a4b1" - ], - "markers": "python_version >= '3.7'", - "version": "==2.1.2" - }, - "webencodings": { - "hashes": [ - "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", - "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923" - ], - "version": "==0.5.1" - }, - "websockets": { - "hashes": [ - "sha256:00213676a2e46b6ebf6045bc11d0f529d9120baa6f58d122b4021ad92adabd41", - "sha256:00c870522cdb69cd625b93f002961ffb0c095394f06ba8c48f17eef7c1541f96", - "sha256:0154f7691e4fe6c2b2bc275b5701e8b158dae92a1ab229e2b940efe11905dff4", - "sha256:05a7233089f8bd355e8cbe127c2e8ca0b4ea55467861906b80d2ebc7db4d6b72", - "sha256:09a1814bb15eff7069e51fed0826df0bc0702652b5cb8f87697d469d79c23576", - "sha256:0cff816f51fb33c26d6e2b16b5c7d48eaa31dae5488ace6aae468b361f422b63", - "sha256:185929b4808b36a79c65b7865783b87b6841e852ef5407a2fb0c03381092fa3b", - "sha256:2fc8709c00704194213d45e455adc106ff9e87658297f72d544220e32029cd3d", - "sha256:33d69ca7612f0ddff3316b0c7b33ca180d464ecac2d115805c044bf0a3b0d032", - "sha256:389f8dbb5c489e305fb113ca1b6bdcdaa130923f77485db5b189de343a179393", - "sha256:38ea7b82bfcae927eeffc55d2ffa31665dc7fec7b8dc654506b8e5a518eb4d50", - "sha256:3d3cac3e32b2c8414f4f87c1b2ab686fa6284a980ba283617404377cd448f631", - "sha256:40e826de3085721dabc7cf9bfd41682dadc02286d8cf149b3ad05bff89311e4f", - "sha256:4239b6027e3d66a89446908ff3027d2737afc1a375f8fd3eea630a4842ec9a0c", - "sha256:45ec8e75b7dbc9539cbfafa570742fe4f676eb8b0d3694b67dabe2f2ceed8aa6", - "sha256:47a2964021f2110116cc1125b3e6d87ab5ad16dea161949e7244ec583b905bb4", - "sha256:48c08473563323f9c9debac781ecf66f94ad5a3680a38fe84dee5388cf5acaf6", - "sha256:4c6d2264f485f0b53adf22697ac11e261ce84805c232ed5dbe6b1bcb84b00ff0", - "sha256:4f72e5cd0f18f262f5da20efa9e241699e0cf3a766317a17392550c9ad7b37d8", - "sha256:56029457f219ade1f2fc12a6504ea61e14ee227a815531f9738e41203a429112", - "sha256:5c1289596042fad2cdceb05e1ebf7aadf9995c928e0da2b7a4e99494953b1b94", - "sha256:62e627f6b6d4aed919a2052efc408da7a545c606268d5ab5bfab4432734b82b4", - "sha256:74de2b894b47f1d21cbd0b37a5e2b2392ad95d17ae983e64727e18eb281fe7cb", - "sha256:7c584f366f46ba667cfa66020344886cf47088e79c9b9d39c84ce9ea98aaa331", - "sha256:7d27a7e34c313b3a7f91adcd05134315002aaf8540d7b4f90336beafaea6217c", - "sha256:7d3f0b61c45c3fa9a349cf484962c559a8a1d80dae6977276df8fd1fa5e3cb8c", - "sha256:82ff5e1cae4e855147fd57a2863376ed7454134c2bf49ec604dfe71e446e2193", - "sha256:84bc2a7d075f32f6ed98652db3a680a17a4edb21ca7f80fe42e38753a58ee02b", - "sha256:884be66c76a444c59f801ac13f40c76f176f1bfa815ef5b8ed44321e74f1600b", - "sha256:8a5cc00546e0a701da4639aa0bbcb0ae2bb678c87f46da01ac2d789e1f2d2038", - "sha256:8dc96f64ae43dde92530775e9cb169979f414dcf5cff670455d81a6823b42089", - "sha256:8f38706e0b15d3c20ef6259fd4bc1700cd133b06c3c1bb108ffe3f8947be15fa", - "sha256:90fcf8929836d4a0e964d799a58823547df5a5e9afa83081761630553be731f9", - "sha256:931c039af54fc195fe6ad536fde4b0de04da9d5916e78e55405436348cfb0e56", - "sha256:932af322458da7e4e35df32f050389e13d3d96b09d274b22a7aa1808f292fee4", - "sha256:942de28af58f352a6f588bc72490ae0f4ccd6dfc2bd3de5945b882a078e4e179", - "sha256:9bc42e8402dc5e9905fb8b9649f57efcb2056693b7e88faa8fb029256ba9c68c", - "sha256:a7a240d7a74bf8d5cb3bfe6be7f21697a28ec4b1a437607bae08ac7acf5b4882", - "sha256:a9f9a735deaf9a0cadc2d8c50d1a5bcdbae8b6e539c6e08237bc4082d7c13f28", - "sha256:ae5e95cfb53ab1da62185e23b3130e11d64431179debac6dc3c6acf08760e9b1", - "sha256:b029fb2032ae4724d8ae8d4f6b363f2cc39e4c7b12454df8df7f0f563ed3e61a", - "sha256:b0d15c968ea7a65211e084f523151dbf8ae44634de03c801b8bd070b74e85033", - "sha256:b343f521b047493dc4022dd338fc6db9d9282658862756b4f6fd0e996c1380e1", - "sha256:b627c266f295de9dea86bd1112ed3d5fafb69a348af30a2422e16590a8ecba13", - "sha256:b9968694c5f467bf67ef97ae7ad4d56d14be2751000c1207d31bf3bb8860bae8", - "sha256:ba089c499e1f4155d2a3c2a05d2878a3428cf321c848f2b5a45ce55f0d7d310c", - "sha256:bbccd847aa0c3a69b5f691a84d2341a4f8a629c6922558f2a70611305f902d74", - "sha256:bc0b82d728fe21a0d03e65f81980abbbcb13b5387f733a1a870672c5be26edab", - "sha256:c57e4c1349fbe0e446c9fa7b19ed2f8a4417233b6984277cce392819123142d3", - "sha256:c94ae4faf2d09f7c81847c63843f84fe47bf6253c9d60b20f25edfd30fb12588", - "sha256:c9b27d6c1c6cd53dc93614967e9ce00ae7f864a2d9f99fe5ed86706e1ecbf485", - "sha256:d210abe51b5da0ffdbf7b43eed0cfdff8a55a1ab17abbec4301c9ff077dd0342", - "sha256:d58804e996d7d2307173d56c297cf7bc132c52df27a3efaac5e8d43e36c21c48", - "sha256:d6a4162139374a49eb18ef5b2f4da1dd95c994588f5033d64e0bbfda4b6b6fcf", - "sha256:da39dd03d130162deb63da51f6e66ed73032ae62e74aaccc4236e30edccddbb0", - "sha256:db3c336f9eda2532ec0fd8ea49fef7a8df8f6c804cdf4f39e5c5c0d4a4ad9a7a", - "sha256:dd500e0a5e11969cdd3320935ca2ff1e936f2358f9c2e61f100a1660933320ea", - "sha256:dd9becd5fe29773d140d68d607d66a38f60e31b86df75332703757ee645b6faf", - "sha256:e0cb5cc6ece6ffa75baccfd5c02cffe776f3f5c8bf486811f9d3ea3453676ce8", - "sha256:e23173580d740bf8822fd0379e4bf30aa1d5a92a4f252d34e893070c081050df", - "sha256:e3a686ecb4aa0d64ae60c9c9f1a7d5d46cab9bfb5d91a2d303d00e2cd4c4c5cc", - "sha256:e789376b52c295c4946403bd0efecf27ab98f05319df4583d3c48e43c7342c2f", - "sha256:edc344de4dac1d89300a053ac973299e82d3db56330f3494905643bb68801269", - "sha256:eef610b23933c54d5d921c92578ae5f89813438fded840c2e9809d378dc765d3", - "sha256:f2c38d588887a609191d30e902df2a32711f708abfd85d318ca9b367258cfd0c", - "sha256:f55b5905705725af31ccef50e55391621532cd64fbf0bc6f4bac935f0fccec46", - "sha256:f5fc088b7a32f244c519a048c170f14cf2251b849ef0e20cbbb0fdf0fdaf556f", - "sha256:fe10ddc59b304cb19a1bdf5bd0a7719cbbc9fbdd57ac80ed436b709fcf889106", - "sha256:ff64a1d38d156d429404aaa84b27305e957fd10c30e5880d1765c9480bea490f" - ], - "markers": "python_version >= '3.7'", - "version": "==10.4" - }, - "zipp": { - "hashes": [ - "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31", - "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0" - ], - "markers": "python_version >= '3.8'", - "version": "==3.17.0" - } - }, - "develop": { - "alabaster": { - "hashes": [ - "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3", - "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2" - ], - "markers": "python_version >= '3.6'", - "version": "==0.7.13" - }, - "astroid": { - "hashes": [ - "sha256:7d5895c9825e18079c5aeac0572bc2e4c83205c95d416e0b4fee8bc361d2d9ca", - "sha256:86b0bb7d7da0be1a7c4aedb7974e391b32d4ed89e33de6ed6902b4b15c97577e" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==3.0.1" - }, - "babel": { - "hashes": [ - "sha256:04c3e2d28d2b7681644508f836be388ae49e0cfe91465095340395b60d00f210", - "sha256:fbfcae1575ff78e26c7449136f1abbefc3c13ce542eeb13d43d50d8b047216ec" - ], - "markers": "python_version >= '3.7'", - "version": "==2.13.0" - }, - "certifi": { - "hashes": [ - "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082", - "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9" - ], - "markers": "python_version >= '3.6'", - "version": "==2023.7.22" - }, - "charset-normalizer": { - "hashes": [ - "sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843", - "sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786", - "sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e", - "sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8", - "sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4", - "sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa", - "sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d", - "sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82", - "sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7", - "sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895", - "sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d", - "sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a", - "sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382", - "sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678", - "sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b", - "sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e", - "sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741", - "sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4", - "sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596", - "sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9", - "sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69", - "sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c", - "sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77", - "sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13", - "sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459", - "sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e", - "sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7", - "sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908", - "sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a", - "sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f", - "sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8", - "sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482", - "sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d", - "sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d", - "sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545", - "sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34", - "sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86", - "sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6", - "sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe", - "sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e", - "sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc", - "sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7", - "sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd", - "sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c", - "sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557", - "sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a", - "sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89", - "sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078", - "sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e", - "sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4", - "sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403", - "sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0", - "sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89", - "sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115", - "sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9", - "sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05", - "sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a", - "sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec", - "sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56", - "sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38", - "sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479", - "sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c", - "sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e", - "sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd", - "sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186", - "sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455", - "sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c", - "sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65", - "sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78", - "sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287", - "sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df", - "sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43", - "sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1", - "sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7", - "sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989", - "sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a", - "sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63", - "sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884", - "sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649", - "sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810", - "sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828", - "sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4", - "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2", - "sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd", - "sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5", - "sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe", - "sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293", - "sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e", - "sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e", - "sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8" - ], - "markers": "python_full_version >= '3.7.0'", - "version": "==3.3.0" - }, - "dill": { - "hashes": [ - "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e", - "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03" - ], - "markers": "python_version >= '3.11'", - "version": "==0.3.7" - }, - "docutils": { - "hashes": [ - "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6", - "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b" - ], - "markers": "python_version >= '3.7'", - "version": "==0.20.1" - }, - "idna": { - "hashes": [ - "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4", - "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2" - ], - "markers": "python_version >= '3.5'", - "version": "==3.4" - }, - "imagesize": { - "hashes": [ - "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", - "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.4.1" - }, - "iniconfig": { - "hashes": [ - "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", - "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374" - ], - "markers": "python_version >= '3.7'", - "version": "==2.0.0" - }, - "isort": { - "hashes": [ - "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504", - "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6" - ], - "markers": "python_full_version >= '3.8.0'", - "version": "==5.12.0" - }, - "jinja2": { - "hashes": [ - "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852", - "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61" - ], - "markers": "python_version >= '3.7'", - "version": "==3.1.2" - }, - "markupsafe": { - "hashes": [ - "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e", - "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e", - "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431", - "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686", - "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c", - "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559", - "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc", - "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb", - "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939", - "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c", - "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0", - "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4", - "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9", - "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575", - "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba", - "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d", - "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd", - "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3", - "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00", - "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155", - "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac", - "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52", - "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f", - "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8", - "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b", - "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007", - "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24", - "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea", - "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198", - "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0", - "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee", - "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be", - "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2", - "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1", - "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707", - "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6", - "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c", - "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58", - "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823", - "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779", - "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636", - "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c", - "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad", - "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee", - "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc", - "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2", - "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48", - "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7", - "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e", - "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b", - "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa", - "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5", - "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e", - "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb", - "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9", - "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57", - "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc", - "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc", - "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2", - "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11" - ], - "markers": "python_version >= '3.7'", - "version": "==2.1.3" - }, - "mccabe": { - "hashes": [ - "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", - "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e" - ], - "markers": "python_version >= '3.6'", - "version": "==0.7.0" - }, - "packaging": { - "hashes": [ - "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", - "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7" - ], - "markers": "python_version >= '3.7'", - "version": "==23.2" - }, - "platformdirs": { - "hashes": [ - "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3", - "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e" - ], - "markers": "python_version >= '3.7'", - "version": "==3.11.0" - }, - "pluggy": { - "hashes": [ - "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12", - "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7" - ], - "markers": "python_version >= '3.8'", - "version": "==1.3.0" - }, - "pygments": { - "hashes": [ - "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692", - "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29" - ], - "markers": "python_version >= '3.7'", - "version": "==2.16.1" - }, - "pylint": { - "hashes": [ - "sha256:81c6125637be216b4652ae50cc42b9f8208dfb725cdc7e04c48f6902f4dbdf40", - "sha256:9c90b89e2af7809a1697f6f5f93f1d0e518ac566e2ac4d2af881a69c13ad01ea" - ], - "index": "pypi", - "markers": "python_full_version >= '3.8.0'", - "version": "==3.0.1" - }, - "pytest": { - "hashes": [ - "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002", - "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069" - ], - "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==7.4.2" - }, - "requests": { - "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" - ], - "markers": "python_version >= '3.7'", - "version": "==2.31.0" - }, - "snowballstemmer": { - "hashes": [ - "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", - "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a" - ], - "version": "==2.2.0" - }, - "sphinx": { - "hashes": [ - "sha256:1e09160a40b956dc623c910118fa636da93bd3ca0b9876a7b3df90f07d691560", - "sha256:9a5160e1ea90688d5963ba09a2dcd8bdd526620edbb65c328728f1b2228d5ab5" - ], - "index": "pypi", - "markers": "python_version >= '3.9'", - "version": "==7.2.6" - }, - "sphinxcontrib-applehelp": { - "hashes": [ - "sha256:094c4d56209d1734e7d252f6e0b3ccc090bd52ee56807a5d9315b19c122ab15d", - "sha256:39fdc8d762d33b01a7d8f026a3b7d71563ea3b72787d5f00ad8465bd9d6dfbfa" - ], - "markers": "python_version >= '3.9'", - "version": "==1.0.7" - }, - "sphinxcontrib-devhelp": { - "hashes": [ - "sha256:63b41e0d38207ca40ebbeabcf4d8e51f76c03e78cd61abe118cf4435c73d4212", - "sha256:fe8009aed765188f08fcaadbb3ea0d90ce8ae2d76710b7e29ea7d047177dae2f" - ], - "markers": "python_version >= '3.9'", - "version": "==1.0.5" - }, - "sphinxcontrib-htmlhelp": { - "hashes": [ - "sha256:6c26a118a05b76000738429b724a0568dbde5b72391a688577da08f11891092a", - "sha256:8001661c077a73c29beaf4a79968d0726103c5605e27db92b9ebed8bab1359e9" - ], - "markers": "python_version >= '3.9'", - "version": "==2.0.4" - }, - "sphinxcontrib-jsmath": { - "hashes": [ - "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", - "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" - ], - "markers": "python_version >= '3.5'", - "version": "==1.0.1" - }, - "sphinxcontrib-qthelp": { - "hashes": [ - "sha256:62b9d1a186ab7f5ee3356d906f648cacb7a6bdb94d201ee7adf26db55092982d", - "sha256:bf76886ee7470b934e363da7a954ea2825650013d367728588732c7350f49ea4" - ], - "markers": "python_version >= '3.9'", - "version": "==1.0.6" - }, - "sphinxcontrib-serializinghtml": { - "hashes": [ - "sha256:0c64ff898339e1fac29abd2bf5f11078f3ec413cfe9c046d3120d7ca65530b54", - "sha256:9b36e503703ff04f20e9675771df105e58aa029cfcbc23b8ed716019b7416ae1" - ], - "markers": "python_version >= '3.9'", - "version": "==1.1.9" - }, - "tomlkit": { - "hashes": [ - "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86", - "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899" - ], - "markers": "python_version >= '3.7'", - "version": "==0.12.1" - }, - "urllib3": { - "hashes": [ - "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07", - "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'", - "version": "==1.26.18" - } - } -}