diff options
-rw-r--r-- | bot/constants.py | 536 | ||||
-rw-r--r-- | bot/exts/filtering/_filter_lists/antispam.py | 2 | ||||
-rw-r--r-- | bot/exts/filtering/_filters/filter.py | 4 | ||||
-rw-r--r-- | bot/exts/filtering/_settings.py | 2 | ||||
-rw-r--r-- | bot/exts/filtering/_settings_types/actions/infraction_and_notification.py | 16 | ||||
-rw-r--r-- | bot/exts/filtering/_settings_types/actions/ping.py | 4 | ||||
-rw-r--r-- | bot/exts/filtering/_settings_types/settings_entry.py | 2 | ||||
-rw-r--r-- | bot/exts/filtering/_settings_types/validations/bypass_roles.py | 25 | ||||
-rw-r--r-- | bot/exts/filtering/_settings_types/validations/channel_scope.py | 34 | ||||
-rw-r--r-- | bot/exts/filtering/_ui/filter.py | 6 | ||||
-rw-r--r-- | bot/exts/filtering/_ui/filter_list.py | 2 | ||||
-rw-r--r-- | bot/exts/filtering/_utils.py | 13 | ||||
-rw-r--r-- | bot/exts/filtering/filtering.py | 14 | ||||
-rw-r--r-- | bot/exts/recruitment/talentpool/_api.py | 12 | ||||
-rw-r--r-- | botstrap.py | 6 | ||||
-rw-r--r-- | poetry.lock | 234 | ||||
-rw-r--r-- | pyproject.toml | 3 | ||||
-rw-r--r-- | tests/bot/exts/filtering/test_settings_entries.py | 4 |
18 files changed, 508 insertions, 411 deletions
diff --git a/bot/constants.py b/bot/constants.py index fa72de19f..4e73fbe74 100644 --- a/bot/constants.py +++ b/bot/constants.py @@ -8,23 +8,23 @@ By default, the values defined in the classes are used, these can be overridden import os from enum import Enum -from pydantic import BaseModel, BaseSettings, root_validator +from pydantic import BaseModel +from pydantic_settings import BaseSettings -class EnvConfig(BaseSettings): +class EnvConfig( + BaseSettings, + env_file=(".env.server", ".env"), + env_file_encoding = "utf-8", + env_nested_delimiter = "__", + extra="ignore", +): """Our default configuration for models that should load from .env files.""" - class Config: - """Specify what .env files to load, and how to load them.""" - - env_file = ".env.server", ".env", - env_file_encoding = "utf-8" - env_nested_delimiter = "__" - class _Miscellaneous(EnvConfig): - debug = True - file_logs = False + debug: bool = True + file_logs: bool = False Miscellaneous = _Miscellaneous() @@ -34,192 +34,186 @@ FILE_LOGS = Miscellaneous.file_logs DEBUG_MODE = Miscellaneous.debug -class _Bot(EnvConfig): - EnvConfig.Config.env_prefix = "bot_" +class _Bot(EnvConfig, env_prefix="bot_"): - prefix = "!" - sentry_dsn = "" - token = "" - trace_loggers = "*" + prefix: str = "!" + sentry_dsn: str = "" + token: str + trace_loggers: str = "*" Bot = _Bot() -class _Channels(EnvConfig): - EnvConfig.Config.env_prefix = "channels_" +class _Channels(EnvConfig, env_prefix="channels_"): - announcements = 354619224620138496 - changelog = 748238795236704388 - mailing_lists = 704372456592506880 - python_events = 729674110270963822 - python_news = 704372456592506880 - reddit = 458224812528238616 + announcements: int = 354619224620138496 + changelog: int = 748238795236704388 + mailing_lists: int = 704372456592506880 + python_events: int = 729674110270963822 + python_news: int = 704372456592506880 + reddit: int = 458224812528238616 - dev_contrib = 635950537262759947 - dev_core = 411200599653351425 - dev_log = 622895325144940554 + dev_contrib: int = 635950537262759947 + dev_core: int = 411200599653351425 + dev_log: int = 622895325144940554 - meta = 429409067623251969 - python_general = 267624335836053506 + meta: int = 429409067623251969 + python_general: int = 267624335836053506 - python_help = 1035199133436354600 + python_help: int = 1035199133436354600 - attachment_log = 649243850006855680 - filter_log = 1014943924185473094 - message_log = 467752170159079424 - mod_log = 282638479504965634 - nomination_voting_archive = 833371042046148738 - user_log = 528976905546760203 - voice_log = 640292421988646961 + attachment_log: int = 649243850006855680 + filter_log: int = 1014943924185473094 + message_log: int = 467752170159079424 + mod_log: int = 282638479504965634 + nomination_voting_archive: int = 833371042046148738 + user_log: int = 528976905546760203 + voice_log: int = 640292421988646961 - off_topic_0 = 291284109232308226 - off_topic_1 = 463035241142026251 - off_topic_2 = 463035268514185226 + off_topic_0: int = 291284109232308226 + off_topic_1: int = 463035241142026251 + off_topic_2: int = 463035268514185226 - bot_commands = 267659945086812160 - discord_bots = 343944376055103488 - esoteric = 470884583684964352 - voice_gate = 764802555427029012 - code_jam_planning = 490217981872177157 + bot_commands: int = 267659945086812160 + discord_bots: int = 343944376055103488 + esoteric: int = 470884583684964352 + voice_gate: int = 764802555427029012 + code_jam_planning: int = 490217981872177157 # Staff - admins = 365960823622991872 - admin_spam = 563594791770914816 - defcon = 464469101889454091 - helpers = 385474242440986624 - incidents = 714214212200562749 - incidents_archive = 720668923636351037 - mod_alerts = 473092532147060736 - mod_meta = 775412552795947058 - mods = 305126844661760000 - nominations = 822920136150745168 - nomination_discussion = 798959130634747914 - nomination_voting = 822853512709931008 - organisation = 551789653284356126 + admins: int = 365960823622991872 + admin_spam: int = 563594791770914816 + defcon: int = 464469101889454091 + helpers: int = 385474242440986624 + incidents: int = 714214212200562749 + incidents_archive: int = 720668923636351037 + mod_alerts: int = 473092532147060736 + mod_meta: int = 775412552795947058 + mods: int = 305126844661760000 + nominations: int = 822920136150745168 + nomination_discussion: int = 798959130634747914 + nomination_voting: int = 822853512709931008 + organisation: int = 551789653284356126 # Staff announcement channels - admin_announcements = 749736155569848370 - mod_announcements = 372115205867700225 - staff_announcements = 464033278631084042 - staff_info = 396684402404622347 - staff_lounge = 464905259261755392 + admin_announcements: int = 749736155569848370 + mod_announcements: int = 372115205867700225 + staff_announcements: int = 464033278631084042 + staff_info: int = 396684402404622347 + staff_lounge: int = 464905259261755392 # Voice Channels - admins_voice = 500734494840717332 - code_help_voice_0 = 751592231726481530 - code_help_voice_1 = 764232549840846858 - general_voice_0 = 751591688538947646 - general_voice_1 = 799641437645701151 - staff_voice = 412375055910043655 + admins_voice: int = 500734494840717332 + code_help_voice_0: int = 751592231726481530 + code_help_voice_1: int = 764232549840846858 + general_voice_0: int = 751591688538947646 + general_voice_1: int = 799641437645701151 + staff_voice: int = 412375055910043655 - black_formatter = 846434317021741086 + black_formatter: int = 846434317021741086 # Voice Chat - code_help_chat_0 = 755154969761677312 - code_help_chat_1 = 766330079135268884 - staff_voice_chat = 541638762007101470 - voice_chat_0 = 412357430186344448 - voice_chat_1 = 799647045886541885 + code_help_chat_0: int = 755154969761677312 + code_help_chat_1: int = 766330079135268884 + staff_voice_chat: int = 541638762007101470 + voice_chat_0: int = 412357430186344448 + voice_chat_1: int = 799647045886541885 - big_brother = 468507907357409333 - duck_pond = 637820308341915648 - roles = 851270062434156586 + big_brother: int = 468507907357409333 + duck_pond: int = 637820308341915648 + roles: int = 851270062434156586 - rules = 693837295685730335 + rules: int = 693837295685730335 Channels = _Channels() -class _Roles(EnvConfig): - - EnvConfig.Config.env_prefix = "roles_" +class _Roles(EnvConfig, env_prefix="roles_"): # Self-assignable roles, see the Subscribe cog - advent_of_code = 518565788744024082 - announcements = 463658397560995840 - lovefest = 542431903886606399 - pyweek_announcements = 897568414044938310 - revival_of_code = 988801794668908655 - legacy_help_channels_access = 1074780483776417964 - - contributors = 295488872404484098 - help_cooldown = 699189276025421825 - partners = 323426753857191936 - python_community = 458226413825294336 - voice_verified = 764802720779337729 + advent_of_code: int = 518565788744024082 + announcements: int = 463658397560995840 + lovefest: int = 542431903886606399 + pyweek_announcements: int = 897568414044938310 + revival_of_code: int = 988801794668908655 + legacy_help_channels_access: int = 1074780483776417964 + + contributors: int = 295488872404484098 + help_cooldown: int = 699189276025421825 + partners: int = 323426753857191936 + python_community: int = 458226413825294336 + voice_verified: int = 764802720779337729 # Streaming - video = 764245844798079016 + video: int = 764245844798079016 # Staff - admins = 267628507062992896 - core_developers = 587606783669829632 - code_jam_event_team = 787816728474288181 - devops = 409416496733880320 - domain_leads = 807415650778742785 - events_lead = 778361735739998228 - helpers = 267630620367257601 - moderators = 831776746206265384 - mod_team = 267629731250176001 - owners = 267627879762755584 - project_leads = 815701647526330398 + admins: int = 267628507062992896 + core_developers: int = 587606783669829632 + code_jam_event_team: int = 787816728474288181 + devops: int = 409416496733880320 + domain_leads: int = 807415650778742785 + events_lead: int = 778361735739998228 + helpers: int = 267630620367257601 + moderators: int = 831776746206265384 + mod_team: int = 267629731250176001 + owners: int = 267627879762755584 + project_leads: int = 815701647526330398 # Code Jam - jammers = 737249140966162473 + jammers: int = 737249140966162473 # Patreon - patreon_tier_1 = 505040943800516611 - patreon_tier_2 = 743399725914390631 - patreon_tier_3 = 743400204367036520 + patreon_tier_1: int = 505040943800516611 + patreon_tier_2: int = 743399725914390631 + patreon_tier_3: int = 743400204367036520 Roles = _Roles() -class _Categories(EnvConfig): - EnvConfig.Config.env_prefix = "categories_" +class _Categories(EnvConfig, env_prefix="categories_"): - logs = 468520609152892958 - moderators = 749736277464842262 - modmail = 714494672835444826 - appeals = 890331800025563216 - appeals_2 = 895417395261341766 - voice = 356013253765234688 + logs: int = 468520609152892958 + moderators: int = 749736277464842262 + modmail: int = 714494672835444826 + appeals: int = 890331800025563216 + appeals_2: int = 895417395261341766 + voice: int = 356013253765234688 # 2021 Summer Code Jam - summer_code_jam = 861692638540857384 - python_help_system = 691405807388196926 + summer_code_jam: int = 861692638540857384 + python_help_system: int = 691405807388196926 Categories = _Categories() -class _Guild(EnvConfig): - EnvConfig.Config.env_prefix = "guild_" +class _Guild(EnvConfig, env_prefix="guild_"): - id = 267624335836053506 - invite = "https://discord.gg/python" + id: int = 267624335836053506 + invite: str = "https://discord.gg/python" - moderation_categories = [ + moderation_categories: tuple[int, ...] = ( Categories.moderators, Categories.modmail, Categories.logs, Categories.appeals, Categories.appeals_2 - ] - moderation_channels = [Channels.admins, Channels.admin_spam, Channels.mods] - modlog_blacklist = [ + ) + moderation_channels: tuple[int, ...] = (Channels.admins, Channels.admin_spam, Channels.mods) + modlog_blacklist: tuple[int, ...] = ( Channels.attachment_log, Channels.message_log, Channels.mod_log, Channels.staff_voice, Channels.filter_log - ] - reminder_whitelist = [Channels.bot_commands, Channels.dev_contrib, Channels.black_formatter] - moderation_roles = [Roles.admins, Roles.mod_team, Roles.moderators, Roles.owners] - staff_roles = [Roles.admins, Roles.helpers, Roles.mod_team, Roles.owners] + ) + reminder_whitelist: tuple[int, ...] = (Channels.bot_commands, Channels.dev_contrib, Channels.black_formatter) + moderation_roles: tuple[int, ...] = (Roles.admins, Roles.mod_team, Roles.moderators, Roles.owners) + staff_roles: tuple[int, ...] = (Roles.admins, Roles.helpers, Roles.mod_team, Roles.owners) Guild = _Guild() @@ -268,8 +262,7 @@ class Webhook(BaseModel): channel: int -class _Webhooks(EnvConfig): - EnvConfig.Config.env_prefix = "webhooks_" +class _Webhooks(EnvConfig, env_prefix="webhooks_"): big_brother: Webhook = Webhook(id=569133704568373283, channel=Channels.big_brother) dev_log: Webhook = Webhook(id=680501655111729222, channel=Channels.dev_log) @@ -282,85 +275,55 @@ class _Webhooks(EnvConfig): Webhooks = _Webhooks() -class _BigBrother(EnvConfig): - EnvConfig.Config.env_prefix = "big_brother_" +class _BigBrother(EnvConfig, env_prefix="big_brother_"): - header_message_limit = 15 - log_delay = 15 + header_message_limit: int = 15 + log_delay: int = 15 BigBrother = _BigBrother() -class _CodeBlock(EnvConfig): - EnvConfig.Config.env_prefix = "code_block_" +class _CodeBlock(EnvConfig, env_prefix="code_block_"): # The channels in which code blocks will be detected. They are not subject to a cooldown. - channel_whitelist: list[int] = [Channels.bot_commands] + channel_whitelist: tuple[int, ...] = (Channels.bot_commands,) # The channels which will be affected by a cooldown. These channels are also whitelisted. - cooldown_channels: list[int] = [Channels.python_general] + cooldown_channels: tuple[int, ...] = (Channels.python_general,) - cooldown_seconds = 300 - minimum_lines = 4 + cooldown_seconds: int = 300 + minimum_lines: int = 4 CodeBlock = _CodeBlock() -class _Colours(EnvConfig): - EnvConfig.Config.env_prefix = "colours_" - - blue = 0x3775a8 - bright_green = 0x01d277 - orange = 0xe67e22 - pink = 0xcf84e0 - purple = 0xb734eb - soft_green = 0x68c290 - soft_orange = 0xf9cb54 - soft_red = 0xcd6d6d - white = 0xfffffe - yellow = 0xffd241 - - @root_validator(pre=True) - def parse_hex_values(cls, values: dict) -> dict: # noqa: N805 - """Convert hex strings to ints.""" - for key, value in values.items(): - values[key] = int(value, 16) - return values - +class _HelpChannels(EnvConfig, env_prefix="help_channels_"): -Colours = _Colours() - - -class _HelpChannels(EnvConfig): - EnvConfig.Config.env_prefix = "help_channels_" - - enable = True - idle_minutes = 60 - deleted_idle_minutes = 5 + enable: bool = True + idle_minutes: int = 60 + deleted_idle_minutes: int = 5 # Roles which are allowed to use the command which makes channels dormant - cmd_whitelist = Guild.moderation_roles + cmd_whitelist: tuple[int, ...] = Guild.moderation_roles HelpChannels = _HelpChannels() -class _RedirectOutput(EnvConfig): - EnvConfig.Config.env_prefix = "redirect_output_" +class _RedirectOutput(EnvConfig, env_prefix="redirect_output_"): - delete_delay = 15 - delete_invocation = True + delete_delay: int = 15 + delete_invocation: bool = True RedirectOutput = _RedirectOutput() -class _DuckPond(EnvConfig): - EnvConfig.Config.env_prefix = "duck_pond_" +class _DuckPond(EnvConfig, env_prefix="duck_pond_"): - threshold = 7 + threshold: int = 7 - channel_blacklist: list[int] = [ + channel_blacklist: tuple[int, ...] = ( Channels.announcements, Channels.python_news, Channels.python_events, @@ -371,126 +334,114 @@ class _DuckPond(EnvConfig): Channels.staff_announcements, Channels.mod_announcements, Channels.admin_announcements, - Channels.staff_info - ] + Channels.staff_info, + ) DuckPond = _DuckPond() -class _PythonNews(EnvConfig): - EnvConfig.Config.env_prefix = "python_news_" +class _PythonNews(EnvConfig, env_prefix="python_news_"): channel: int = Webhooks.python_news.channel webhook: int = Webhooks.python_news.id - mail_lists = ["python-ideas", "python-announce-list", "pypi-announce", "python-dev"] + mail_lists: tuple[str, ...] = ("python-ideas", "python-announce-list", "pypi-announce", "python-dev") PythonNews = _PythonNews() -class _VoiceGate(EnvConfig): - EnvConfig.Config.env_prefix = "voice_gate_" +class _VoiceGate(EnvConfig, env_prefix="voice_gate_"): - bot_message_delete_delay = 10 - minimum_activity_blocks = 3 - minimum_days_member = 3 - minimum_messages = 50 - voice_ping_delete_delay = 60 + bot_message_delete_delay: int = 10 + minimum_activity_blocks: int = 3 + minimum_days_member: int = 3 + minimum_messages: int = 50 + voice_ping_delete_delay: int = 60 VoiceGate = _VoiceGate() -class _Branding(EnvConfig): - EnvConfig.Config.env_prefix = "branding_" +class _Branding(EnvConfig, env_prefix="branding_"): - cycle_frequency = 3 + cycle_frequency: int = 3 Branding = _Branding() -class _VideoPermission(EnvConfig): - EnvConfig.Config.env_prefix = "video_permission_" +class _VideoPermission(EnvConfig, env_prefix="video_permission_"): - default_permission_duration = 5 + default_permission_duration: int = 5 VideoPermission = _VideoPermission() -class _Redis(EnvConfig): - EnvConfig.Config.env_prefix = "redis_" +class _Redis(EnvConfig, env_prefix="redis_"): - host = "redis.default.svc.cluster.local" - password = "" - port = 6379 - use_fakeredis = False # If this is True, Bot will use fakeredis.aioredis + host: str = "redis.default.svc.cluster.local" + password: str = "" + port: int = 6379 + use_fakeredis: bool = False # If this is True, Bot will use fakeredis.aioredis Redis = _Redis() -class _CleanMessages(EnvConfig): - EnvConfig.Config.env_prefix = "clean_" +class _CleanMessages(EnvConfig, env_prefix="clean_"): - message_limit = 10_000 + message_limit: int = 10_000 CleanMessages = _CleanMessages() -class _Stats(EnvConfig): - EnvConfig.Config.env_prefix = "stats_" +class _Stats(EnvConfig, env_prefix="stats_"): - presence_update_timeout = 30 - statsd_host = "graphite.default.svc.cluster.local" + presence_update_timeout: int = 30 + statsd_host: str = "graphite.default.svc.cluster.local" Stats = _Stats() -class _Cooldowns(EnvConfig): - EnvConfig.Config.env_prefix = "cooldowns_" +class _Cooldowns(EnvConfig, env_prefix="cooldowns_"): - tags = 60 + tags: int = 60 Cooldowns = _Cooldowns() -class _Metabase(EnvConfig): - EnvConfig.Config.env_prefix = "metabase_" +class _Metabase(EnvConfig, env_prefix="metabase_"): - username = "" - password = "" - base_url = "http://metabase.default.svc.cluster.local" - public_url = "https://metabase.pythondiscord.com" - max_session_age = 20_160 + username: str = "" + password: str = "" + base_url: str = "http://metabase.default.svc.cluster.local" + public_url: str = "https://metabase.pythondiscord.com" + max_session_age: int = 20_160 Metabase = _Metabase() -class _BaseURLs(EnvConfig): - EnvConfig.Config.env_prefix = "urls_" +class _BaseURLs(EnvConfig, env_prefix="urls_"): # Snekbox endpoints - snekbox_eval_api = "http://snekbox.default.svc.cluster.local/eval" + snekbox_eval_api: str = "http://snekbox.default.svc.cluster.local/eval" # Discord API - discord_api = "https://discordapp.com/api/v7/" + discord_api: str = "https://discordapp.com/api/v7/" # Misc endpoints - bot_avatar = "https://raw.githubusercontent.com/python-discord/branding/main/logos/logo_circle/logo_circle.png" - - github_bot_repo = "https://github.com/python-discord/bot" + bot_avatar: str = "https://raw.githubusercontent.com/python-discord/branding/main/logos/logo_circle/logo_circle.png" + github_bot_repo: str = "https://github.com/python-discord/bot" # Site - site_api = "http://site.default.svc.cluster.local/api" - - paste_url = "https://paste.pythondiscord.com" + site_api: str = "http://site.default.svc.cluster.local/api" + paste_url: str = "https://paste.pythondiscord.com" BaseURLs = _BaseURLs() @@ -502,8 +453,8 @@ class _URLs(_BaseURLs): discord_invite_api: str = "".join([BaseURLs.discord_api, "invites"]) # Base site vars - connect_max_retries = 3 - connect_cooldown = 5 + connect_max_retries: int = 3 + connect_cooldown: int = 5 site_logs_view: str = "https://pythondiscord.com/staff/bot/logs" @@ -511,59 +462,58 @@ class _URLs(_BaseURLs): URLs = _URLs() -class _Emojis(EnvConfig): - EnvConfig.Config.env_prefix = "emojis_" +class _Emojis(EnvConfig, env_prefix="emojis_"): - badge_bug_hunter = "<:bug_hunter_lvl1:743882896372269137>" - badge_bug_hunter_level_2 = "<:bug_hunter_lvl2:743882896611344505>" - badge_early_supporter = "<:early_supporter:743882896909140058>" - badge_hypesquad = "<:hypesquad_events:743882896892362873>" - badge_hypesquad_balance = "<:hypesquad_balance:743882896460480625>" - badge_hypesquad_bravery = "<:hypesquad_bravery:743882896745693335>" - badge_hypesquad_brilliance = "<:hypesquad_brilliance:743882896938631248>" - badge_partner = "<:partner:748666453242413136>" - badge_staff = "<:discord_staff:743882896498098226>" - badge_verified_bot_developer = "<:verified_bot_dev:743882897299210310>" - badge_discord_certified_moderator = "<:discord_certified_moderator:1114130029547364434>" - badge_bot_http_interactions = "<:bot_http_interactions:1114130379754975283>" - badge_active_developer = "<:active_developer:1114130031036338176>" - verified_bot = "<:verified_bot:811645219220750347>" - bot = "<:bot:812712599464443914>" + badge_bug_hunter: str = "<:bug_hunter_lvl1:743882896372269137>" + badge_bug_hunter_level_2: str = "<:bug_hunter_lvl2:743882896611344505>" + badge_early_supporter: str = "<:early_supporter:743882896909140058>" + badge_hypesquad: str = "<:hypesquad_events:743882896892362873>" + badge_hypesquad_balance: str = "<:hypesquad_balance:743882896460480625>" + badge_hypesquad_bravery: str = "<:hypesquad_bravery:743882896745693335>" + badge_hypesquad_brilliance: str = "<:hypesquad_brilliance:743882896938631248>" + badge_partner: str = "<:partner:748666453242413136>" + badge_staff: str = "<:discord_staff:743882896498098226>" + badge_verified_bot_developer: str = "<:verified_bot_dev:743882897299210310>" + badge_discord_certified_moderator: str = "<:discord_certified_moderator:1114130029547364434>" + badge_bot_http_interactions: str = "<:bot_http_interactions:1114130379754975283>" + badge_active_developer: str = "<:active_developer:1114130031036338176>" + verified_bot: str = "<:verified_bot:811645219220750347>" + bot: str = "<:bot:812712599464443914>" - defcon_shutdown = "<:defcondisabled:470326273952972810>" - defcon_unshutdown = "<:defconenabled:470326274213150730>" - defcon_update = "<:defconsettingsupdated:470326274082996224>" + defcon_shutdown: str = "<:defcondisabled:470326273952972810>" + defcon_unshutdown: str = "<:defconenabled:470326274213150730>" + defcon_update: str = "<:defconsettingsupdated:470326274082996224>" - failmail = "<:failmail:633660039931887616>" - failed_file = "<:failed_file:1073298441968562226>" + failmail: str = "<:failmail:633660039931887616>" + failed_file: str = "<:failed_file:1073298441968562226>" - incident_actioned = "<:incident_actioned:714221559279255583>" - incident_investigating = "<:incident_investigating:714224190928191551>" - incident_unactioned = "<:incident_unactioned:714223099645526026>" + incident_actioned: str = "<:incident_actioned:714221559279255583>" + incident_investigating: str = "<:incident_investigating:714224190928191551>" + incident_unactioned: str = "<:incident_unactioned:714223099645526026>" - status_dnd = "<:status_dnd:470326272082313216>" - status_idle = "<:status_idle:470326266625785866>" - status_offline = "<:status_offline:470326266537705472>" - status_online = "<:status_online:470326272351010816>" + status_dnd: str = "<:status_dnd:470326272082313216>" + status_idle: str = "<:status_idle:470326266625785866>" + status_offline: str = "<:status_offline:470326266537705472>" + status_online: str = "<:status_online:470326272351010816>" - ducky_dave = "<:ducky_dave:742058418692423772>" + ducky_dave: str = "<:ducky_dave:742058418692423772>" - trashcan = "<:trashcan:637136429717389331>" + trashcan: str = "<:trashcan:637136429717389331>" - bullet = "\u2022" - check_mark = "\u2705" - cross_mark = "\u274C" - new = "\U0001F195" - pencil = "\u270F" + bullet: str = "\u2022" + check_mark: str = "\u2705" + cross_mark: str = "\u274C" + new: str = "\U0001F195" + pencil: str = "\u270F" - ok_hand = ":ok_hand:" + ok_hand: str = ":ok_hand:" Emojis = _Emojis() -class _Icons(EnvConfig): - EnvConfig.Config.env_prefix = "icons_" +class Icons: + """URLs to commonly used icons.""" crown_blurple = "https://cdn.discordapp.com/emojis/469964153289965568.png" crown_green = "https://cdn.discordapp.com/emojis/469964154719961088.png" @@ -617,15 +567,25 @@ class _Icons(EnvConfig): voice_state_red = "https://cdn.discordapp.com/emojis/656899769905709076.png" -Icons = _Icons() +class Colours: + """Colour codes, mostly used to set discord.Embed colours.""" + blue: int = 0x3775a8 + bright_green: int = 0x01d277 + orange: int = 0xe67e22 + pink: int = 0xcf84e0 + purple: int = 0xb734eb + soft_green: int = 0x68c290 + soft_orange: int = 0xf9cb54 + soft_red: int = 0xcd6d6d + white: int = 0xfffffe + yellow: int = 0xffd241 -class _Keys(EnvConfig): - EnvConfig.Config.env_prefix = "api_keys_" +class _Keys(EnvConfig, env_prefix="api_keys_"): - github = "" - site_api = "" + github: str = "" + site_api: str = "" Keys = _Keys() @@ -637,7 +597,7 @@ PROJECT_ROOT = os.path.abspath(os.path.join(BOT_DIR, os.pardir)) # Default role combinations MODERATION_ROLES = Guild.moderation_roles STAFF_ROLES = Guild.staff_roles -STAFF_PARTNERS_COMMUNITY_ROLES = STAFF_ROLES + [Roles.partners, Roles.python_community] +STAFF_PARTNERS_COMMUNITY_ROLES = STAFF_ROLES + (Roles.partners, Roles.python_community) # Channel combinations MODERATION_CHANNELS = Guild.moderation_channels @@ -650,7 +610,7 @@ GIT_SHA = os.environ.get("GIT_SHA", "development") # Bot replies -NEGATIVE_REPLIES = [ +NEGATIVE_REPLIES = ( "Noooooo!!", "Nope.", "I'm sorry Dave, I'm afraid I can't do that.", @@ -668,9 +628,9 @@ NEGATIVE_REPLIES = [ "NEGATORY.", "Nuh-uh.", "Not in my house!", -] +) -POSITIVE_REPLIES = [ +POSITIVE_REPLIES = ( "Yep.", "Absolutely!", "Can do!", @@ -688,9 +648,9 @@ POSITIVE_REPLIES = [ "Of course!", "Aye aye, cap'n!", "I'll allow it.", -] +) -ERROR_REPLIES = [ +ERROR_REPLIES = ( "Please don't do that.", "You have to stop.", "Do you mind?", @@ -701,4 +661,4 @@ ERROR_REPLIES = [ "Are you trying to kill me?", "Noooooo!!", "I can't believe you've done this", -] +) diff --git a/bot/exts/filtering/_filter_lists/antispam.py b/bot/exts/filtering/_filter_lists/antispam.py index 22f35f40e..f27412e1a 100644 --- a/bot/exts/filtering/_filter_lists/antispam.py +++ b/bot/exts/filtering/_filter_lists/antispam.py @@ -93,7 +93,7 @@ class AntispamList(UniquesListBase): current_actions.pop("ping", None) current_actions.pop("send_alert", None) - new_infraction = current_actions[InfractionAndNotification.name].copy() + new_infraction = current_actions[InfractionAndNotification.name].model_copy() # Smaller infraction value => higher in hierarchy. if not current_infraction or new_infraction.infraction_type.value < current_infraction.value: # Pick the first triggered filter for the reason, there's no good way to decide between them. diff --git a/bot/exts/filtering/_filters/filter.py b/bot/exts/filtering/_filters/filter.py index 6745e4f66..3f201cfde 100644 --- a/bot/exts/filtering/_filters/filter.py +++ b/bot/exts/filtering/_filters/filter.py @@ -31,7 +31,7 @@ class Filter(FieldRequiring): self.updated_at = arrow.get(filter_data["updated_at"]) self.actions, self.validations = create_settings(filter_data["settings"], defaults=defaults) if self.extra_fields_type: - self.extra_fields = self.extra_fields_type.parse_obj(filter_data["additional_settings"]) + self.extra_fields = self.extra_fields_type.model_validate(filter_data["additional_settings"]) else: self.extra_fields = None @@ -46,7 +46,7 @@ class Filter(FieldRequiring): filter_settings = {} if self.extra_fields: - filter_settings = self.extra_fields.dict(exclude_unset=True) + filter_settings = self.extra_fields.model_dump(exclude_unset=True) return settings, filter_settings diff --git a/bot/exts/filtering/_settings.py b/bot/exts/filtering/_settings.py index 766a5ea10..7005dd2d1 100644 --- a/bot/exts/filtering/_settings.py +++ b/bot/exts/filtering/_settings.py @@ -227,5 +227,5 @@ class Defaults(NamedTuple): """Return a dict representation of the stored fields across all entries.""" dict_ = {} for settings in self: - dict_ = reduce(operator.or_, (entry.dict() for entry in settings.values()), dict_) + dict_ = reduce(operator.or_, (entry.model_dump() for entry in settings.values()), dict_) return dict_ diff --git a/bot/exts/filtering/_settings_types/actions/infraction_and_notification.py b/bot/exts/filtering/_settings_types/actions/infraction_and_notification.py index f12538294..359aa7bc3 100644 --- a/bot/exts/filtering/_settings_types/actions/infraction_and_notification.py +++ b/bot/exts/filtering/_settings_types/actions/infraction_and_notification.py @@ -6,7 +6,7 @@ import discord.abc from dateutil.relativedelta import relativedelta from discord import Colour, Embed, Member, User from discord.errors import Forbidden -from pydantic import validator +from pydantic import field_validator from pydis_core.utils.logging import get_logger from pydis_core.utils.members import get_or_fetch_member @@ -151,7 +151,7 @@ class InfractionAndNotification(ActionEntry): infraction_duration: InfractionDuration infraction_channel: int - @validator("infraction_type", pre=True) + @field_validator("infraction_type", mode="before") @classmethod def convert_infraction_name(cls, infr_type: str | Infraction) -> Infraction: """Convert the string to an Infraction by name.""" @@ -221,14 +221,14 @@ class InfractionAndNotification(ActionEntry): """ # Lower number -> higher in the hierarchy if self.infraction_type is None: - return other.copy() + return other.model_copy() if other.infraction_type is None: - return self.copy() + return self.model_copy() if self.infraction_type.value < other.infraction_type.value: - result = self.copy() + result = self.model_copy() elif self.infraction_type.value > other.infraction_type.value: - result = other.copy() + result = other.model_copy() other = self else: now = arrow.utcnow().datetime @@ -236,9 +236,9 @@ class InfractionAndNotification(ActionEntry): other.infraction_duration is not None and now + self.infraction_duration.value > now + other.infraction_duration.value ): - result = self.copy() + result = self.model_copy() else: - result = other.copy() + result = other.model_copy() other = self # If the winner has no message but the loser does, copy the message to the winner. diff --git a/bot/exts/filtering/_settings_types/actions/ping.py b/bot/exts/filtering/_settings_types/actions/ping.py index fa3e2224f..4b38a19f3 100644 --- a/bot/exts/filtering/_settings_types/actions/ping.py +++ b/bot/exts/filtering/_settings_types/actions/ping.py @@ -1,6 +1,6 @@ from typing import ClassVar, Self -from pydantic import validator +from pydantic import field_validator from bot.exts.filtering._filter_context import FilterContext from bot.exts.filtering._settings_types.settings_entry import ActionEntry @@ -25,7 +25,7 @@ class Ping(ActionEntry): guild_pings: set[str] dm_pings: set[str] - @validator("*", pre=True) + @field_validator("*", mode="before") @classmethod def init_sequence_if_none(cls, pings: list[str] | None) -> list[str]: """Initialize an empty sequence if the value is None.""" diff --git a/bot/exts/filtering/_settings_types/settings_entry.py b/bot/exts/filtering/_settings_types/settings_entry.py index a3a2cbe1a..1cb9d9f2a 100644 --- a/bot/exts/filtering/_settings_types/settings_entry.py +++ b/bot/exts/filtering/_settings_types/settings_entry.py @@ -28,7 +28,7 @@ class SettingsEntry(BaseModel, FieldRequiring): def __init__(self, defaults: SettingsEntry | None = None, /, **data): overrides = set() if defaults: - defaults_dict = defaults.dict() + defaults_dict = defaults.model_dump() for field_name, field_value in list(data.items()): if field_value is None: data[field_name] = defaults_dict[field_name] diff --git a/bot/exts/filtering/_settings_types/validations/bypass_roles.py b/bot/exts/filtering/_settings_types/validations/bypass_roles.py index 50fb1e650..0ddb2fdb5 100644 --- a/bot/exts/filtering/_settings_types/validations/bypass_roles.py +++ b/bot/exts/filtering/_settings_types/validations/bypass_roles.py @@ -1,6 +1,8 @@ -from typing import ClassVar, Union +from collections.abc import Sequence +from typing import ClassVar from discord import Member +from pydantic import field_validator from bot.exts.filtering._filter_context import FilterContext from bot.exts.filtering._settings_types.settings_entry import ValidationEntry @@ -12,7 +14,26 @@ class RoleBypass(ValidationEntry): name: ClassVar[str] = "bypass_roles" description: ClassVar[str] = "A list of role IDs or role names. Users with these roles will not trigger the filter." - bypass_roles: set[Union[int, str]] # noqa: UP007 + bypass_roles: set[int | str] + + @field_validator("bypass_roles", mode="before") + @classmethod + def init_if_bypass_roles_none(cls, bypass_roles: Sequence[int | str] | None) -> Sequence[int | str]: + """ + Initialize an empty sequence if the value is None. + + This also coerces each element of bypass_roles to an int, if possible. + """ + if bypass_roles is None: + return [] + + def _coerce_to_int(input: int | str) -> int | str: + try: + return int(input) + except ValueError: + return input + + return map(_coerce_to_int, bypass_roles) def triggers_on(self, ctx: FilterContext) -> bool: """Return whether the filter should be triggered on this user given their roles.""" diff --git a/bot/exts/filtering/_settings_types/validations/channel_scope.py b/bot/exts/filtering/_settings_types/validations/channel_scope.py index 1880ae27e..3d31131af 100644 --- a/bot/exts/filtering/_settings_types/validations/channel_scope.py +++ b/bot/exts/filtering/_settings_types/validations/channel_scope.py @@ -1,6 +1,7 @@ -from typing import ClassVar, Union +from collections.abc import Sequence +from typing import ClassVar -from pydantic import validator +from pydantic import field_validator from bot.exts.filtering._filter_context import FilterContext from bot.exts.filtering._settings_types.settings_entry import ValidationEntry @@ -29,20 +30,29 @@ class ChannelScope(ValidationEntry): ) } - # NOTE: Don't change this to use the new 3.10 union syntax unless you ensure Pydantic type validation and coercion - # work properly. At the time of writing this code there's a difference. - disabled_channels: set[Union[int, str]] # noqa: UP007 - disabled_categories: set[Union[int, str]] # noqa: UP007 - enabled_channels: set[Union[int, str]] # noqa: UP007 - enabled_categories: set[Union[int, str]] # noqa: UP007 + disabled_channels: set[int | str] + disabled_categories: set[int | str] + enabled_channels: set[int | str] + enabled_categories: set[int | str] - @validator("*", pre=True) + @field_validator("*", mode="before") @classmethod - def init_if_sequence_none(cls, sequence: list[str] | None) -> list[str]: - """Initialize an empty sequence if the value is None.""" + def init_if_sequence_none(cls, sequence: Sequence[int | str] | None) -> Sequence[int | str]: + """ + Initialize an empty sequence if the value is None. + + This also coerces each element of sequence to an int, if possible. + """ if sequence is None: return [] - return sequence + + def _coerce_to_int(input: int | str) -> int | str: + try: + return int(input) + except ValueError: + return input + + return map(_coerce_to_int, sequence) def triggers_on(self, ctx: FilterContext) -> bool: """ diff --git a/bot/exts/filtering/_ui/filter.py b/bot/exts/filtering/_ui/filter.py index 4300de19c..6927a5d41 100644 --- a/bot/exts/filtering/_ui/filter.py +++ b/bot/exts/filtering/_ui/filter.py @@ -34,7 +34,7 @@ def build_filter_repr_dict( default_setting_values = {} for settings_group in filter_list[list_type].defaults: for _, setting in settings_group.items(): - default_setting_values.update(to_serializable(setting.dict(), ui_repr=True)) + default_setting_values.update(to_serializable(setting.model_dump(), ui_repr=True)) # Add overrides. It's done in this way to preserve field order, since the filter won't have all settings. total_values = {} @@ -47,7 +47,7 @@ def build_filter_repr_dict( # Add the filter-specific settings. if filter_type.extra_fields_type: # This iterates over the default values of the extra fields model. - for name, value in filter_type.extra_fields_type().dict().items(): + for name, value in filter_type.extra_fields_type().model_dump().items(): if name not in extra_fields_overrides or repr_equals(extra_fields_overrides[name], value): total_values[f"{filter_type.name}/{name}"] = value else: @@ -287,7 +287,7 @@ class FilterEditView(EditBaseView): if "/" in setting_name: filter_name, setting_name = setting_name.split("/", maxsplit=1) dict_to_edit = self.filter_settings_overrides - default_value = self.filter_type.extra_fields_type().dict()[setting_name] + default_value = self.filter_type.extra_fields_type().model_dump()[setting_name] else: dict_to_edit = self.settings_overrides default_value = self.filter_list[self.list_type].default(setting_name) diff --git a/bot/exts/filtering/_ui/filter_list.py b/bot/exts/filtering/_ui/filter_list.py index 062975ad7..2858817e3 100644 --- a/bot/exts/filtering/_ui/filter_list.py +++ b/bot/exts/filtering/_ui/filter_list.py @@ -50,7 +50,7 @@ def build_filterlist_repr_dict(filter_list: FilterList, list_type: ListType, new default_setting_values = {} for settings_group in filter_list[list_type].defaults: for _, setting in settings_group.items(): - default_setting_values.update(to_serializable(setting.dict(), ui_repr=True)) + default_setting_values.update(to_serializable(setting.model_dump(), ui_repr=True)) # Add new values. It's done in this way to preserve field order, since the new_values won't have all settings. total_values = {} diff --git a/bot/exts/filtering/_utils.py b/bot/exts/filtering/_utils.py index e109a47ee..944cf3837 100644 --- a/bot/exts/filtering/_utils.py +++ b/bot/exts/filtering/_utils.py @@ -7,7 +7,7 @@ import pkgutil import types from abc import ABC, abstractmethod from collections import defaultdict -from collections.abc import Iterable +from collections.abc import Callable, Iterable from dataclasses import dataclass from functools import cache from typing import Any, Self, TypeVar, Union, get_args, get_origin @@ -15,6 +15,7 @@ from typing import Any, Self, TypeVar, Union, get_args, get_origin import discord import regex from discord.ext.commands import Command +from pydantic_core import core_schema import bot from bot.bot import Bot @@ -252,12 +253,16 @@ class CustomIOField: self.value = self.process_value(value) @classmethod - def __get_validators__(cls): + def __get_pydantic_core_schema__( + cls, + _source: type[Any], + _handler: Callable[[Any], core_schema.CoreSchema], + ) -> core_schema.CoreSchema: """Boilerplate for Pydantic.""" - yield cls.validate + return core_schema.general_plain_validator_function(cls.validate) @classmethod - def validate(cls, v: Any) -> Self: + def validate(cls, v: Any, _info: core_schema.ValidationInfo) -> Self: """Takes the given value and returns a class instance with that value.""" if isinstance(v, CustomIOField): return cls(v.value) diff --git a/bot/exts/filtering/filtering.py b/bot/exts/filtering/filtering.py index 2b7ad2ff3..bedd9958f 100644 --- a/bot/exts/filtering/filtering.py +++ b/bot/exts/filtering/filtering.py @@ -181,7 +181,7 @@ class Filtering(Cog): extra_fields_type, type_hints[field_name] ) - for field_name in extra_fields_type.__fields__ + for field_name in extra_fields_type.model_fields } async def schedule_offending_messages_deletion(self) -> None: @@ -754,7 +754,7 @@ class Filtering(Cog): setting_values = {} for settings_group in filter_list[list_type].defaults: for _, setting in settings_group.items(): - setting_values.update(to_serializable(setting.dict(), ui_repr=True)) + setting_values.update(to_serializable(setting.model_dump(), ui_repr=True)) embed = Embed(colour=Colour.blue()) populate_embed_from_dict(embed, setting_values) @@ -1239,7 +1239,13 @@ class Filtering(Cog): for current_settings in (filter_.actions, filter_.validations): if current_settings: for setting_entry in current_settings.values(): - settings.update({setting: None for setting in setting_entry.dict() if setting not in settings}) + settings.update( + { + setting: None + for setting in setting_entry.model_dump() + if setting not in settings + } + ) # Even though the list ID remains unchanged, it still needs to be provided for correct serializer validation. list_id = filter_list[list_type].id @@ -1295,7 +1301,7 @@ class Filtering(Cog): if not (differ_by_default <= override_matches): # The overrides didn't cover for the default mismatches. return False - filter_settings = filter_.extra_fields.dict() if filter_.extra_fields else {} + filter_settings = filter_.extra_fields.model_dump() if filter_.extra_fields else {} # If the dict changes then some fields were not the same. return (filter_settings | filter_settings_query) == filter_settings diff --git a/bot/exts/recruitment/talentpool/_api.py b/bot/exts/recruitment/talentpool/_api.py index e12111de5..f7b243209 100644 --- a/bot/exts/recruitment/talentpool/_api.py +++ b/bot/exts/recruitment/talentpool/_api.py @@ -1,6 +1,6 @@ from datetime import datetime -from pydantic import BaseModel, Field, parse_obj_as +from pydantic import BaseModel, Field, TypeAdapter from pydis_core.site_api import APIClient @@ -50,13 +50,13 @@ class NominationAPI: params["user__id"] = str(user_id) data = await self.site_api.get("bot/nominations", params=params) - nominations = parse_obj_as(list[Nomination], data) + nominations = TypeAdapter(list[Nomination]).validate_python(data) return nominations async def get_nomination(self, nomination_id: int) -> Nomination: """Fetch a nomination by ID.""" data = await self.site_api.get(f"bot/nominations/{nomination_id}") - nomination = Nomination.parse_obj(data) + nomination = Nomination.model_validate(data) return nomination async def edit_nomination( @@ -84,7 +84,7 @@ class NominationAPI: data["thread_id"] = thread_id result = await self.site_api.patch(f"bot/nominations/{nomination_id}", json=data) - return Nomination.parse_obj(result) + return Nomination.model_validate(result) async def edit_nomination_entry( self, @@ -96,7 +96,7 @@ class NominationAPI: """Edit a nomination entry.""" data = {"actor": actor_id, "reason": reason} result = await self.site_api.patch(f"bot/nominations/{nomination_id}", json=data) - return Nomination.parse_obj(result) + return Nomination.model_validate(result) async def post_nomination( self, @@ -111,7 +111,7 @@ class NominationAPI: "user": user_id, } result = await self.site_api.post("bot/nominations", json=data) - return Nomination.parse_obj(result) + return Nomination.model_validate(result) async def get_activity( self, diff --git a/botstrap.py b/botstrap.py index c57a254a3..7a9d94d8b 100644 --- a/botstrap.py +++ b/botstrap.py @@ -176,7 +176,7 @@ with DiscordClient(guild_id=GUILD_ID) as discord_client: all_roles = discord_client.get_all_roles() - for role_name in _Roles.__fields__: + for role_name in _Roles.model_fields: role_id = all_roles.get(role_name, None) if not role_id: @@ -209,7 +209,7 @@ with DiscordClient(guild_id=GUILD_ID) as discord_client: python_help_channel_id = discord_client.create_forum_channel(python_help_channel_name, python_help_category_id) all_channels[PYTHON_HELP_CHANNEL_NAME] = python_help_channel_id - for channel_name in _Channels.__fields__: + for channel_name in _Channels.model_fields: channel_id = all_channels.get(channel_name, None) if not channel_id: log.warning( @@ -222,7 +222,7 @@ with DiscordClient(guild_id=GUILD_ID) as discord_client: config_str += "\n#Categories\n" - for category_name in _Categories.__fields__: + for category_name in _Categories.model_fields: category_id = all_categories.get(category_name, None) if not category_id: log.warning( diff --git a/poetry.lock b/poetry.lock index e45697329..b467300fe 100644 --- a/poetry.lock +++ b/poetry.lock @@ -137,6 +137,17 @@ files = [ frozenlist = ">=1.1.0" [[package]] +name = "annotated-types" +version = "0.5.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.7" +files = [ + {file = "annotated_types-0.5.0-py3-none-any.whl", hash = "sha256:58da39888f92c276ad970249761ebea80ba544b77acddaa1a4d6cf78287d45fd"}, + {file = "annotated_types-0.5.0.tar.gz", hash = "sha256:47cdc3490d9ac1506ce92c7aaa76c579dc3509ff11e098fc867e5130ab7be802"}, +] + +[[package]] name = "anyio" version = "3.7.1" description = "High level compatibility layer for multiple asynchronous event loop implementations" @@ -190,13 +201,13 @@ fakeredis = ["fakeredis[lua] (>=1.7.1)"] [[package]] name = "async-timeout" -version = "4.0.2" +version = "4.0.3" description = "Timeout context manager for asyncio programs" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"}, - {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"}, + {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, + {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, ] [[package]] @@ -931,13 +942,10 @@ 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"}, @@ -946,7 +954,6 @@ files = [ {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"}, @@ -966,7 +973,6 @@ files = [ {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"}, @@ -976,7 +982,6 @@ files = [ {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"}, @@ -986,7 +991,6 @@ files = [ {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"}, @@ -996,7 +1000,6 @@ files = [ {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"}, @@ -1007,16 +1010,13 @@ files = [ {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"}, @@ -1206,18 +1206,18 @@ test = ["docutils", "mypy", "pytest-cov", "pytest-pycodestyle", "pytest-runner"] [[package]] name = "platformdirs" -version = "3.9.1" +version = "3.10.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.9.1-py3-none-any.whl", hash = "sha256:ad8291ae0ae5072f66c16945166cb11c63394c7a3ad1b1bc9828ca3162da8c2f"}, - {file = "platformdirs-3.9.1.tar.gz", hash = "sha256:1b42b450ad933e981d56e59f1b97495428c9bd60698baab9f3eb3d00d5822421"}, + {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, + {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, ] [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] [[package]] name = "pluggy" @@ -1375,56 +1375,150 @@ files = [ [[package]] name = "pydantic" -version = "1.10.9" -description = "Data validation and settings management using python type hints" +version = "2.0.3" +description = "Data validation using Python type hints" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e692dec4a40bfb40ca530e07805b1208c1de071a18d26af4a2a0d79015b352ca"}, - {file = "pydantic-1.10.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3c52eb595db83e189419bf337b59154bdcca642ee4b2a09e5d7797e41ace783f"}, - {file = "pydantic-1.10.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:939328fd539b8d0edf244327398a667b6b140afd3bf7e347cf9813c736211896"}, - {file = "pydantic-1.10.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b48d3d634bca23b172f47f2335c617d3fcb4b3ba18481c96b7943a4c634f5c8d"}, - {file = "pydantic-1.10.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:f0b7628fb8efe60fe66fd4adadd7ad2304014770cdc1f4934db41fe46cc8825f"}, - {file = "pydantic-1.10.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e1aa5c2410769ca28aa9a7841b80d9d9a1c5f223928ca8bec7e7c9a34d26b1d4"}, - {file = "pydantic-1.10.9-cp310-cp310-win_amd64.whl", hash = "sha256:eec39224b2b2e861259d6f3c8b6290d4e0fbdce147adb797484a42278a1a486f"}, - {file = "pydantic-1.10.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d111a21bbbfd85c17248130deac02bbd9b5e20b303338e0dbe0faa78330e37e0"}, - {file = "pydantic-1.10.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e9aec8627a1a6823fc62fb96480abe3eb10168fd0d859ee3d3b395105ae19a7"}, - {file = "pydantic-1.10.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07293ab08e7b4d3c9d7de4949a0ea571f11e4557d19ea24dd3ae0c524c0c334d"}, - {file = "pydantic-1.10.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ee829b86ce984261d99ff2fd6e88f2230068d96c2a582f29583ed602ef3fc2c"}, - {file = "pydantic-1.10.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4b466a23009ff5cdd7076eb56aca537c745ca491293cc38e72bf1e0e00de5b91"}, - {file = "pydantic-1.10.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7847ca62e581e6088d9000f3c497267868ca2fa89432714e21a4fb33a04d52e8"}, - {file = "pydantic-1.10.9-cp311-cp311-win_amd64.whl", hash = "sha256:7845b31959468bc5b78d7b95ec52fe5be32b55d0d09983a877cca6aedc51068f"}, - {file = "pydantic-1.10.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:517a681919bf880ce1dac7e5bc0c3af1e58ba118fd774da2ffcd93c5f96eaece"}, - {file = "pydantic-1.10.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67195274fd27780f15c4c372f4ba9a5c02dad6d50647b917b6a92bf00b3d301a"}, - {file = "pydantic-1.10.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2196c06484da2b3fded1ab6dbe182bdabeb09f6318b7fdc412609ee2b564c49a"}, - {file = "pydantic-1.10.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6257bb45ad78abacda13f15bde5886efd6bf549dd71085e64b8dcf9919c38b60"}, - {file = "pydantic-1.10.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3283b574b01e8dbc982080d8287c968489d25329a463b29a90d4157de4f2baaf"}, - {file = "pydantic-1.10.9-cp37-cp37m-win_amd64.whl", hash = "sha256:5f8bbaf4013b9a50e8100333cc4e3fa2f81214033e05ac5aa44fa24a98670a29"}, - {file = "pydantic-1.10.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b9cd67fb763248cbe38f0593cd8611bfe4b8ad82acb3bdf2b0898c23415a1f82"}, - {file = "pydantic-1.10.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f50e1764ce9353be67267e7fd0da08349397c7db17a562ad036aa7c8f4adfdb6"}, - {file = "pydantic-1.10.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73ef93e5e1d3c8e83f1ff2e7fdd026d9e063c7e089394869a6e2985696693766"}, - {file = "pydantic-1.10.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:128d9453d92e6e81e881dd7e2484e08d8b164da5507f62d06ceecf84bf2e21d3"}, - {file = "pydantic-1.10.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ad428e92ab68798d9326bb3e5515bc927444a3d71a93b4a2ca02a8a5d795c572"}, - {file = "pydantic-1.10.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fab81a92f42d6d525dd47ced310b0c3e10c416bbfae5d59523e63ea22f82b31e"}, - {file = "pydantic-1.10.9-cp38-cp38-win_amd64.whl", hash = "sha256:963671eda0b6ba6926d8fc759e3e10335e1dc1b71ff2a43ed2efd6996634dafb"}, - {file = "pydantic-1.10.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:970b1bdc6243ef663ba5c7e36ac9ab1f2bfecb8ad297c9824b542d41a750b298"}, - {file = "pydantic-1.10.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7e1d5290044f620f80cf1c969c542a5468f3656de47b41aa78100c5baa2b8276"}, - {file = "pydantic-1.10.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83fcff3c7df7adff880622a98022626f4f6dbce6639a88a15a3ce0f96466cb60"}, - {file = "pydantic-1.10.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0da48717dc9495d3a8f215e0d012599db6b8092db02acac5e0d58a65248ec5bc"}, - {file = "pydantic-1.10.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0a2aabdc73c2a5960e87c3ffebca6ccde88665616d1fd6d3db3178ef427b267a"}, - {file = "pydantic-1.10.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9863b9420d99dfa9c064042304868e8ba08e89081428a1c471858aa2af6f57c4"}, - {file = "pydantic-1.10.9-cp39-cp39-win_amd64.whl", hash = "sha256:e7c9900b43ac14110efa977be3da28931ffc74c27e96ee89fbcaaf0b0fe338e1"}, - {file = "pydantic-1.10.9-py3-none-any.whl", hash = "sha256:6cafde02f6699ce4ff643417d1a9223716ec25e228ddc3b436fe7e2d25a1f305"}, - {file = "pydantic-1.10.9.tar.gz", hash = "sha256:95c70da2cd3b6ddf3b9645ecaa8d98f3d80c606624b6d245558d202cd23ea3be"}, + {file = "pydantic-2.0.3-py3-none-any.whl", hash = "sha256:614eb3321eb600c81899a88fa9858b008e3c79e0d4f1b49ab1f516b4b0c27cfb"}, + {file = "pydantic-2.0.3.tar.gz", hash = "sha256:94f13e0dcf139a5125e88283fc999788d894e14ed90cf478bcc2ee50bd4fc630"}, ] [package.dependencies] -python-dotenv = {version = ">=0.10.4", optional = true, markers = "extra == \"dotenv\""} -typing-extensions = ">=4.2.0" +annotated-types = ">=0.4.0" +pydantic-core = "2.3.0" +typing-extensions = ">=4.6.1" [package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.3.0" +description = "" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic_core-2.3.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:4542c98b8364b976593703a2dda97377433b102f380b61bc3a2cbc2fbdae1d1f"}, + {file = "pydantic_core-2.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9342de50824b40f55d2600f66c6f9a91a3a24851eca39145a749a3dc804ee599"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:539432f911686cb80284c30b33eaf9f4fd9a11e1111fe0dc98fdbdce69b49821"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38a0e7ee65c8999394d92d9c724434cb629279d19844f2b69d9bbc46dc8b8b61"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_24_armv7l.whl", hash = "sha256:e3ed6834cc005798187a56c248a2240207cb8ffdda1c89e9afda4c3d526c2ea0"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:e72ac299a6bf732a60852d052acf3999d234686755a02ba111e85e7ebf8155b1"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_24_s390x.whl", hash = "sha256:616b3451b05ca63b8f433c627f68046b39543faeaa4e50d8c6699a2a1e4b85a5"}, + {file = "pydantic_core-2.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:adcb9c8848e15c613e483e0b99767ae325af27fe0dbd866df01fe5849d06e6e1"}, + {file = "pydantic_core-2.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:464bf799b422be662e5e562e62beeffc9eaa907d381a9d63a2556615bbda286d"}, + {file = "pydantic_core-2.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4638ebc17de08c2f3acba557efeb6f195c88b7299d8c55c0bb4e20638bbd4d03"}, + {file = "pydantic_core-2.3.0-cp310-none-win32.whl", hash = "sha256:9ff322c7e1030543d35d83bb521b69114d3d150750528d7757544f639def9ad6"}, + {file = "pydantic_core-2.3.0-cp310-none-win_amd64.whl", hash = "sha256:4824eb018f0a4680b1e434697a9bf3f41c7799b80076d06530cbbd212e040ccc"}, + {file = "pydantic_core-2.3.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:0aa429578e23885b3984c49d687cd05ab06f0b908ea1711a8bf7e503b7f97160"}, + {file = "pydantic_core-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:20d710c1f79af930b8891bcebd84096798e4387ab64023ef41521d58f21277d3"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:309f45d4d7481d6f09cb9e35c72caa0e50add4a30bb08c04c5fe5956a0158633"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bcfb7be905aa849bd882262e1df3f75b564e2f708b4b4c7ad2d3deaf5410562"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_24_armv7l.whl", hash = "sha256:85cd9c0af34e371390e3cb2f3a470b0b40cc07568c1e966c638c49062be6352d"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_24_ppc64le.whl", hash = "sha256:37c5028cebdf731298724070838fb3a71ef1fbd201d193d311ac2cbdbca25a23"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_24_s390x.whl", hash = "sha256:e4208f23f12d0ad206a07a489ef4cb15722c10b62774c4460ee4123250be938e"}, + {file = "pydantic_core-2.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c24465dd11b65c8510f251b095fc788c7c91481c81840112fe3f76c30793a455"}, + {file = "pydantic_core-2.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3cd7ee8bbfab277ab56e272221886fd33a1b5943fbf45ae9195aa6a48715a8a0"}, + {file = "pydantic_core-2.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0fc7e0b056b66cc536e97ef60f48b3b289f6b3b62ac225afd4b22a42434617bf"}, + {file = "pydantic_core-2.3.0-cp311-none-win32.whl", hash = "sha256:4788135db4bd83a5edc3522b11544b013be7d25b74b155e08dd3b20cd6663bbb"}, + {file = "pydantic_core-2.3.0-cp311-none-win_amd64.whl", hash = "sha256:f93c867e5e85584a28c6a6feb6f2086d717266eb5d1210d096dd717b7f4dec04"}, + {file = "pydantic_core-2.3.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:73f62bb7fd862d9bcd886e10612bade6fe042eda8b47e8c129892bcfb7b45e84"}, + {file = "pydantic_core-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d889d498fce64bfcd8adf1a78579a7f626f825cbeb2956a24a29b35f9a1df32"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d55e38a89ec2ae17b2fa7ffeda6b70f63afab1888bd0d57aaa7b7879760acb4"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1aefebb506bc1fe355d91d25f12bcdea7f4d7c2d9f0f6716dd025543777c99a5"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_24_armv7l.whl", hash = "sha256:6441a29f42585f085db0c04cd0557d4cbbb46fa68a0972409b1cfe9f430280c1"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_24_ppc64le.whl", hash = "sha256:47e8f034be31390a8f525431eb5e803a78ce7e2e11b32abf5361a972e14e6b61"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_24_s390x.whl", hash = "sha256:ad814864aba263be9c83ada44a95f72d10caabbf91589321f95c29c902bdcff0"}, + {file = "pydantic_core-2.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9eff3837d447fccf2ac38c259b14ab9cbde700df355a45a1f3ff244d5e78f8b6"}, + {file = "pydantic_core-2.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:534f3f63c000f08050c6f7f4378bf2b52d7ba9214e9d35e3f60f7ad24a4d6425"}, + {file = "pydantic_core-2.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ef6a222d54f742c24f6b143aab088702db3a827b224e75b9dd28b38597c595fe"}, + {file = "pydantic_core-2.3.0-cp312-none-win32.whl", hash = "sha256:4e26944e64ecc1d7b19db954c0f7b471f3b141ec8e1a9f57cfe27671525cd248"}, + {file = "pydantic_core-2.3.0-cp312-none-win_amd64.whl", hash = "sha256:019c5c41941438570dfc7d3f0ae389b2425add1775a357ce1e83ed1434f943d6"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:27c1bbfb9d84a75cf33b7f19b53c29eb7ead99b235fce52aced5507174ab8f98"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:7cb496e934b71f1ade844ab91d6ccac78a3520e5df02fdb2357f85a71e541e69"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5af2d43b1978958d91351afbcc9b4d0cfe144c46c61740e82aaac8bb39ab1a4d"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d3097c39d7d4e8dba2ef86de171dcccad876c36d8379415ba18a5a4d0533510"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_24_armv7l.whl", hash = "sha256:dd3b023f3317dbbbc775e43651ce1a31a9cea46216ad0b5be37afc18a2007699"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:27babb9879bf2c45ed655d02639f4c30e2b9ef1b71ce59c2305bbf7287910a18"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_24_s390x.whl", hash = "sha256:2183a9e18cdc0de53bdaa1675f237259162abeb62d6ac9e527c359c1074dc55d"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c089d8e7f1b4db08b2f8e4107304eec338df046275dad432635a9be9531e2fc8"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f10aa5452b865818dd0137f568d443f5e93b60a27080a01aa4b7512c7ba13a3"}, + {file = "pydantic_core-2.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:f642313d559f9d9a00c4de6820124059cc3342a0d0127b18301de2c680d5ea40"}, + {file = "pydantic_core-2.3.0-cp37-none-win32.whl", hash = "sha256:45327fc57afbe3f2c3d7f54a335d5cecee8a9fdb3906a2fbed8af4092f4926df"}, + {file = "pydantic_core-2.3.0-cp37-none-win_amd64.whl", hash = "sha256:e427b66596a6441a5607dfc0085b47d36073f88da7ac48afd284263b9b99e6ce"}, + {file = "pydantic_core-2.3.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:0b3d781c71b8bfb621ef23b9c874933e2cd33237c1a65cc20eeb37437f8e7e18"}, + {file = "pydantic_core-2.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ad46027dbd5c1db87dc0b49becbe23093b143a20302028d387dae37ee5ef95f5"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39aa09ed7ce2a648c904f79032d16dda29e6913112af8465a7bf710eef23c7ca"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05b4bf8c58409586a7a04c858a86ab10f28c6c1a7c33da65e0326c59d5b0ab16"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_24_armv7l.whl", hash = "sha256:ba2b807d2b62c446120906b8580cddae1d76d3de4efbb95ccc87f5e35c75b4b2"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:ea955e4ed21f4bbb9b83fea09fc6af0bed82e69ecf6b35ec89237a0a49633033"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_24_s390x.whl", hash = "sha256:06884c07956526ac9ebfef40fe21a11605569b8fc0e2054a375fb39c978bf48f"}, + {file = "pydantic_core-2.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f868e731a18b403b88aa434d960489ceeed0ddeb44ebc02389540731a67705e0"}, + {file = "pydantic_core-2.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cb08fab0fc1db15c277b72e33ac74ad9c0c789413da8984a3eacb22a94b42ef4"}, + {file = "pydantic_core-2.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6ca34c29fbd6592de5fd39e80c1993634d704c4e7e14ba54c87b2c7c53da68fe"}, + {file = "pydantic_core-2.3.0-cp38-none-win32.whl", hash = "sha256:cd782807d35c8a41aaa7d30b5107784420eefd9fdc1c760d86007d43ae00b15d"}, + {file = "pydantic_core-2.3.0-cp38-none-win_amd64.whl", hash = "sha256:01f56d5ee70b1d39c0fd08372cc5142274070ab7181d17c86035f130eebc05b8"}, + {file = "pydantic_core-2.3.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:78b1ac0151271ce62bc2b33755f1043eda6a310373143a2f27e2bcd3d5fc8633"}, + {file = "pydantic_core-2.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:64bfd2c35a2c350f73ac52dc134d8775f93359c4c969280a6fe5301b5b6e7431"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:937c0fe9538f1212b62df6a68f8d78df3572fe3682d9a0dd8851eac8a4e46063"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d965c7c4b40d1cedec9188782e98bd576f9a04868835604200c3a6e817b824f"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_24_armv7l.whl", hash = "sha256:ad442b8585ed4a3c2d22e4bf7b465d9b7d281e055b09719a8aeb5b576422dc9b"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:4bf20c9722821fce766e685718e739deeccc60d6bc7be5029281db41f999ee0c"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_24_s390x.whl", hash = "sha256:f3dd5333049b5b3faa739e0f40b77cc8b7a1aded2f2da0e28794c81586d7b08a"}, + {file = "pydantic_core-2.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dc5f516b24d24bc9e8dd9305460899f38302b3c4f9752663b396ef9848557bf"}, + {file = "pydantic_core-2.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:055f7ea6b1fbb37880d66d70eefd22dd319b09c79d2cb99b1dbfeb34b653b0b2"}, + {file = "pydantic_core-2.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:af693a89db6d6ac97dd84dd7769b3f2bd9007b578127d0e7dda03053f4d3b34b"}, + {file = "pydantic_core-2.3.0-cp39-none-win32.whl", hash = "sha256:f60e31e3e15e8c294bf70c60f8ae4d0c3caf3af8f26466e9aa8ea4c01302749b"}, + {file = "pydantic_core-2.3.0-cp39-none-win_amd64.whl", hash = "sha256:2b79f3681481f4424d7845cc7a261d5a4baa810d656b631fa844dc9967b36a7b"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:a666134b41712e30a71afaa26deeb4da374179f769fa49784cdf0e7698880fab"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c119e9227487ad3d7c3c737d896afe548a6be554091f9745da1f4b489c40561"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73929a2fb600a2333fce2efd92596cff5e6bf8946e20e93c067b220760064862"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:41bbc2678a5b6a19371b2cb51f30ccea71f0c14b26477d2d884fed761cea42c7"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:dcbff997f47d45bf028bda4c3036bb3101e89a3df271281d392b6175f71c71d1"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:afa8808159169368b66e4fbeafac6c6fd8f26246dc4d0dcc2caf94bd9cf1b828"}, + {file = "pydantic_core-2.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:12be3b5f54f8111ca38e6b7277f26c23ba5cb3344fae06f879a0a93dfc8b479e"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ed5babdcd3d052ba5cf8832561f18df20778c7ccf12587b2d82f7bf3bf259a0e"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d642e5c029e2acfacf6aa0a7a3e822086b3b777c70d364742561f9ca64c1ffc"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ba3073eb38a1294e8c7902989fb80a7a147a69db2396818722bd078476586a0"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5146a6749b1905e04e62e0ad4622f079e5582f8b3abef5fb64516c623127908"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:deeb64335f489c3c11949cbd1d1668b3f1fb2d1c6a5bf40e126ef7bf95f9fa40"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:31acc37288b8e69e4849f618c3d5cf13b58077c1a1ff9ade0b3065ba974cd385"}, + {file = "pydantic_core-2.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e09d9f6d722de9d4c1c5f122ea9bc6b25a05f975457805af4dcab7b0128aacbf"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ba6a8cf089222a171b8f84e6ec2d10f7a9d14f26be3a347b14775a8741810676"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1fd1b24e9bcddcb168437686677104e205c8e25b066e73ffdf331d3bb8792b"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eda1a89c4526826c0a87d33596a4cd15b8f58e9250f503e39af1699ba9c878e8"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3e9a18401a28db4358da2e191508702dbf065f2664c710708cdf9552b9fa50c"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:a439fd0d45d51245bbde799726adda5bd18aed3fa2b01ab2e6a64d6d13776fa3"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:bf6a1d2c920cc9528e884850a4b2ee7629e3d362d5c44c66526d4097bbb07a1a"}, + {file = "pydantic_core-2.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e33fcbea3b63a339dd94de0fc442fefacfe681cc7027ce63f67af9f7ceec7422"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:bf3ed993bdf4754909f175ff348cf8f78d4451215b8aa338633f149ca3b1f37a"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7584171eb3115acd4aba699bc836634783f5bd5aab131e88d8eeb8a3328a4a72"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1624baa76d1740711b2048f302ae9a6d73d277c55a8c3e88b53b773ebf73a971"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:06f33f695527f5a86e090f208978f9fd252c9cfc7e869d3b679bd71f7cb2c1fa"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7ecf0a67b212900e92f328181fed02840d74ed39553cdb38d27314e2b9c89dfa"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:45fa1e8ad6f4367ad73674ca560da8e827cc890eaf371f3ee063d6d7366a207b"}, + {file = "pydantic_core-2.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8d0dbcc57839831ae79fd24b1b83d42bc9448d79feaf3ed3fb5cbf94ffbf3eb7"}, + {file = "pydantic_core-2.3.0.tar.gz", hash = "sha256:5cfb5ac4e82c47d5dc25b209dd4c3989e284b80109f9e08b33c895080c424b4f"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pydantic-settings" +version = "2.0.2" +description = "Settings management using Pydantic" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic_settings-2.0.2-py3-none-any.whl", hash = "sha256:6183a2abeab465d5a3ab69758e9a22d38b0cc2ba193f0b85f6971a252ea630f6"}, + {file = "pydantic_settings-2.0.2.tar.gz", hash = "sha256:342337fff50b23585e807a86dec85037900972364435c55c2fc00d16ff080539"}, +] + +[package.dependencies] +pydantic = ">=2.0.1" +python-dotenv = ">=0.21.0" [[package]] name = "pydis-core" @@ -2104,23 +2198,23 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.24.1" +version = "20.24.2" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.1-py3-none-any.whl", hash = "sha256:01aacf8decd346cf9a865ae85c0cdc7f64c8caa07ff0d8b1dfc1733d10677442"}, - {file = "virtualenv-20.24.1.tar.gz", hash = "sha256:2ef6a237c31629da6442b0bcaa3999748108c7166318d1f55cc9f8d7294e97bd"}, + {file = "virtualenv-20.24.2-py3-none-any.whl", hash = "sha256:43a3052be36080548bdee0b42919c88072037d50d56c28bd3f853cbe92b953ff"}, + {file = "virtualenv-20.24.2.tar.gz", hash = "sha256:fd8a78f46f6b99a67b7ec5cf73f92357891a7b3a40fd97637c27f854aae3b9e0"}, ] [package.dependencies] -distlib = ">=0.3.6,<1" -filelock = ">=3.12,<4" -platformdirs = ">=3.5.1,<4" +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<4" [package.extras] docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezer (>=0.4.6)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.8)", "time-machine (>=2.9)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "wcwidth" @@ -2223,4 +2317,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "3.11.*" -content-hash = "60353f299efeb38128df337aabef6ec53c5018c9a1fe14254737b5079f094f41" +content-hash = "e7e58f19c35b45ba8b1ee279e852fbe5111ad70b1bb9f5f5de0941dd966bb6ed" diff --git a/pyproject.toml b/pyproject.toml index 68aa2685f..af17a1ed9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,8 @@ rapidfuzz = "3.2.0" regex = "2023.8.8" sentry-sdk = "1.29.2" tldextract = "3.4.4" -pydantic = { version = "1.10.9", extras = ["dotenv"]} +pydantic = "2.0.3" +pydantic-settings = "2.0.2" [tool.poetry.dev-dependencies] coverage = "7.2.7" diff --git a/tests/bot/exts/filtering/test_settings_entries.py b/tests/bot/exts/filtering/test_settings_entries.py index 3ae0b5ab5..988435022 100644 --- a/tests/bot/exts/filtering/test_settings_entries.py +++ b/tests/bot/exts/filtering/test_settings_entries.py @@ -173,7 +173,7 @@ class FilterTests(unittest.TestCase): result = infraction1.union(infraction2) self.assertDictEqual( - result.dict(), + result.model_dump(), { "infraction_type": Infraction.TIMEOUT, "infraction_reason": "there", @@ -206,7 +206,7 @@ class FilterTests(unittest.TestCase): result = infraction1.union(infraction2) self.assertDictEqual( - result.dict(), + result.model_dump(), { "infraction_type": Infraction.BAN, "infraction_reason": "", |