diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 0885eee3..bbece48c 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -17,6 +17,10 @@ on: type: boolean description: Only parse English localizations default: false + dry-run: + type: boolean + description: Run in dry-run mode — logs wiki actions without actually saving + default: false workflow_call: inputs: @@ -155,9 +159,10 @@ jobs: PARSE_MAP: true DECOMPILE: true PARSE: true - CHANGELOGS: false + CHANGELOGS: true CLEANUP: false - WIKI_UPLOAD: ${{ needs.get-branch.outputs.branch == 'master' }} + WIKI_UPLOAD: ${{ needs.get-branch.outputs.branch == 'master' || github.event.inputs.dry-run == 'true' }} + DRY_RUN: ${{ github.event.inputs.dry-run == 'true' }} STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }} STEAM_PASSWORD: ${{ secrets.STEAM_PASSWORD }} BOT_WIKI_USER: ${{ vars.BOT_WIKI_USER }} diff --git a/docker-compose.yml b/docker-compose.yml index c4a86a37..041fc554 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,6 +15,7 @@ services: WIKI_UPLOAD: ${WIKI_UPLOAD} FORCE: ${FORCE} CLEANUP: ${CLEANUP} + DRY_RUN: ${DRY_RUN} VERBOSE: ${VERBOSE} STEAM_USERNAME: ${STEAM_USERNAME} STEAM_PASSWORD: ${STEAM_PASSWORD} diff --git a/input-data/changelogs/changelog_configs.json b/input-data/changelogs/changelog_configs.json index d433e5de..177eccd5 100644 --- a/input-data/changelogs/changelog_configs.json +++ b/input-data/changelogs/changelog_configs.json @@ -760,5 +760,37 @@ "date": "2026-05-31", "link": "https://forums.playdeadlock.com/threads/05-22-2026-update.135477/post-263371", "is_hero_lab": false + }, + "2026-06-04": { + "source_id": "1834602721188293", + "date": "2026-06-04", + "link": "https://steamstore-a.akamaihd.net/news/externalpost/steam_community_announcements/1834602721188293", + "is_hero_lab": false, + "title": "Minor Update - 06-04-2026", + "steam_hash": "041d77eede2596e9445f6376c1f0a200" + }, + "2026-06-11": { + "source_id": "1835236783562074", + "date": "2026-06-11", + "link": "https://steamstore-a.akamaihd.net/news/externalpost/steam_community_announcements/1835236783562074", + "is_hero_lab": false, + "title": "Minor Update - 06-11-2026", + "steam_hash": "13544b2f29881ee0c7e9748c08831276" + }, + "2026-06-30": { + "source_id": "1836506165563227", + "date": "2026-06-30", + "link": "https://steamstore-a.akamaihd.net/news/externalpost/steam_community_announcements/1836506165563227", + "is_hero_lab": false, + "title": "Minor Update - 06-30-2026", + "steam_hash": "1f5c55a3db4f6a97dd2e045da399bb65" + }, + "2026-07-01": { + "source_id": "1836506165566600", + "date": "2026-07-01", + "link": "https://steamstore-a.akamaihd.net/news/externalpost/steam_community_announcements/1836506165566600", + "is_hero_lab": false, + "title": "Minor Update - 07-01-2026", + "steam_hash": "82ac2c2a5a6746e2b783104cb233396e" } } \ No newline at end of file diff --git a/input-data/changelogs/raw/2026-06-04.txt b/input-data/changelogs/raw/2026-06-04.txt new file mode 100644 index 00000000..3a89127d --- /dev/null +++ b/input-data/changelogs/raw/2026-06-04.txt @@ -0,0 +1,18 @@ +- Urn mechanics have been reworked. + +Primary details: +- Delivering the urn now starts a king of the hill style capture point, rather than using melee to flip the urn back and forth. +- Both teams can progress at the same time, but the urn will only be fully claimed once there is only one team in the circle. +- The Urn runner now gets their normal 35% bonus bounty and stats immediately on initial deposit (rather than on deposit conclusion only if your team won it) + +Other Details: +- Urn overall bounty reduced by 20% (unreduced for trailing team) +- Progress radius is 20m +- Progress rate is fixed regardless the number of allies in the area +- Progress duration for favored/neutral/unfavored is 6/12/18s +- If Urn has been in progress for over 75s, it will give up and throw all the souls as orbs into the sky (they will float for a long time) +- Increased time allowed to run the urn before taking damage by 10s +- Trailing team sprint speed bonus from +4m to +5m +- Urn comeback resistance now also grants +35% Debuff Resistance ontop of the 35% Bullet and Spirit Resistance +- Urn comeback resistance aura reduced from 60m to match the 20m progress radius +- Drop off location is above the bridges on the side lanes, rather than below. \ No newline at end of file diff --git a/input-data/changelogs/raw/2026-06-11.txt b/input-data/changelogs/raw/2026-06-11.txt new file mode 100644 index 00000000..bd71b0cf --- /dev/null +++ b/input-data/changelogs/raw/2026-06-11.txt @@ -0,0 +1,105 @@ +- Urn give up time reduced from 75s to 60s +- Urn bounty reduced by 10% (unreduced for trailing team) + +- Breakables health permanent bonus reduced from 15/25/35 to 15/20/30 for level 1/2/3 + +- Kill comeback bounty values increased by 8% + +- Street Brawl: All ability and item range/radius values are reduced by 10% + +- Opening Rounds: Conditional Weapon Damage bonus reduced from 30% to 25% +- Opening Rounds: Spirit Power increased from +4 to +7 +- Arcane Surge: Fixed various cases with the bonuses not working + +- Apollo: Disengaging Sigil velocity increased by 50% +- Apollo: Disengaging Sigil velocity's vertical:horizontal ratio changed from 1.5:1 to 1:1 +- Apollo: Disengaging Sigil now allows input to alter the direction apollo launches himself (A/D biases to the left/right and W/S affect how much backwards motion is applied +- Apollo: Disengaging Sigil T1 changed from "+30 Damage" to "Gain +25% Fire Rate and Bullet Speed for 8s" +- Apollo: Disengaging Sigil T2 changed from "Gain +30% Fire Rate and +50% Bullet Speed for 10s" to "On Player Hit: +1 Stamina restored and resets Air Jump/Dash limit" +- Apollo: Disengaging Sigil T3 changed from "On Player Hit: +2 stamina restored and reset Air Jump/Dash limit" to "Recast within 4s" +- Apollo: Flawless Advance now allows Apollo to parry during it + +- Bebop: Exploding Uppercut T3 increased from +17% Missing Health to +18% +- Bebop: Fixed Sticky Bomb T3 duration ending once the bomb went off rather than the 5s duration +- Bebop: Sticky Bomb T3 changed from "On Cast: +5m Move Speed and +20% Fire Rate for 5s" to "On Cast: +5m Move Speed and +25% Debuff Resistance for 6s" (applies retroactively) + +- Calico: Gloom Bombs melee resist debuff now stacks additively +- Calico: Gloom Bombs T2 increased from -5% Melee Resist for 5s to -6% for 6s +- Calico: Gloom Bombs melee resist now applies on impact rather than explosion +- Calico: Return to Shadows damage increased from 140 to 150 +- Calico: Return to Shadows T2 damage increased from +65 to +75 +- Calico: Return to Shadows T3 heal increased from 350 to 450 + +- Doorman: Call Bell explosion damage spirit scaling reduced from 1.3 to 1.2 +- Doorman: Call Bell T3 spirit scaling reduced from 0.4 to 0.35 + +- Graves: Jar of Dead collection rate reduced by 20% (takes longer to gain a charge) +- Graves: Jar of Dead damage reduced from 17+0.27 to 16+0.25 +- Graves: Jar of Dead bounty increased from 5+0.25/boon to 7+0.5/boon +- Graves: Grasping Hands T3 Immobilize duration reduced from +1s to +0.75s + +- Grey Talon: Gun cycle time increased from 0.5775 to 0.6 (~4% DPS nerf) +- Grey Talon: Bullet damage growth reduced from +1.0 to +0.85 +- Grey Talon: Rain of Arrows cooldown increased from 22s to 23s +- Grey Talon: Rain of Arrows T2 reduced from -13s Cooldown to -12s + +- Holliday: Powder Keg now has an alt cast behavior to place the barrel at her feet +- Holliday: Powder Keg various improvements to the launch angles, velocities and feel of casting +- Holliday: Powder Keg now starts with 2 charges +- Holliday: Powder Keg Charge Time increased from 3.5s to 7s +- Holliday: Powder Keg spirit scaling reduced from 1.6 to 1.4 +- Holliday: Powder Keg T2 changed from "+58 Damage" to "+1 Charge" +- Holliday: Powder Keg T3 changed from "+2 Charges and +0.4s Displacement" to "+100 Damage, +0.5 Spirit Scaling and -5s Charge Time" +- Holliday: Fixed various issues with placing bounce pad on elevated areas +- Holliday: Bounce Pad landing radius reduced from 12m to 9m +- Holliday: Bounce Pad T3 changed from "+68 Stomp Damage and Improved Spirit Scaling" to "+0.7s Stomp Stun" (only triggers from Holliday) + +- Infernus: Fixed Afterburn Max duration refreshing not properly accounting for both Debuff Resist and +Ability Duration +- Infernus: Fixed Concussive Combustion cooldown not updating when getting the T2 or other CD reducing items when the ability is on cooldown + +- Ivy: Fixed a bug where Stone Form could sometimes do significantly more damage than intended + +- McGinnis: Mini Turret DPS rescaled from 30+0.39 to 24+0.42 (break even at 200 spirit power) +- McGinnis: Mini Turrets T3 Fire Rate reduced from +30% to +25% +- McGinnis: Fixed some rare cases where Heavy Barrage would stop working +- McGinnis: Heavy Barrage DPS reduced from 22.5 to 21 + +- Paige: Rallying Charge distance for max amp reduced from 350m to 250m +- Paige: Rallying Charge T2 increased from -30s Cooldown to -50s +- Paige: Plot Armor barrier spirit scaling increased from 1.3 to 1.5 +- Paige: Plot Armor T3 barrier spirit scaling increased from +0.3 to +0.5 + +- Pocket: Bullet damage growth reduced from +0.2 to +0.16 +- Pocket: Flying Cloak T3 reduced from -13s Cooldown to -12s +- Pocket: Affliction now does half damage on objectives + +- Seven: Bullet damage growth reduced from 0.337 to 0.24 +- Seven: Power Surge T3 reduced from +12s Duration to +10s +- Seven: Storm Cloud now hits breakables + +- Shiv: Killing Blow now has +30% more cooldown whenever it does not impact a player + +- Silver: Lycan Curse cooldown increased from 40s to 70s +- Silver: Lycan Curse T3 no longer heals + +- Viscous: Puddle Punch T2 increased from +40% Lifesteal to +60% +- Viscous: Goo Ball T2 now also increases Bullet and Spirit Resist by +10% + +- Victor: Aura of Suffering radius reduced from 9m to 8m +- Victor: Aura of Suffering T3 now also increases radius by +1m +- Victor: Fixed some client performance issues when using Aura of Suffering +- Victor: Shocking Reanimation cooldown increased from 230s to 240s +- Victor: Shocking Reanimation T3 reduced from -120s Cooldown to -110s +- Victor: Shocking Reanimation T3 increased from +150 Damage to +175 + +- Vindicta: Assassinate Max Bonus Damage spirit scaling increased from 1.7 to 2.0 + +- Warden: Bullet falloff reduced from 20m->58m to 18m->47m +- Warden: Alchemical Flask spirit scaling reduced from 0.73 to 0.63 +- Warden: Alchemical Flask T2 reduced from +40 Damage to +35 +- Warden: Alchemical Flask T2 increased from -20% Weapon Damage to -25% +- Warden: Willpower spirit scaling increased from +0.5 to +0.8 +- Warden: Binding Word T3 reduced from -18s Cooldown to -14s +- Warden: Last Stand lifesteal increased from 65% to 75% +- Warden: Last Stand T2 increased from -30s Cooldown to -35s +- Warden: Last Stand T3 increased from +3s Duration to +4s \ No newline at end of file diff --git a/input-data/changelogs/raw/2026-06-30.txt b/input-data/changelogs/raw/2026-06-30.txt new file mode 100644 index 00000000..c0eb4076 --- /dev/null +++ b/input-data/changelogs/raw/2026-06-30.txt @@ -0,0 +1,187 @@ +[ Urn / King of the Hill ] + +- King of the Hill objective has been rethemed and renamed to "Unstable Rift" +- Unstable Rift no longer requires an Urn delivery to trigger the start of the event. It now has a variable start time of +/- 1 minute. There is a global announcement 25s before it spawns. 60s before that there is also an in-world only visual effect to let you know which lane it'll randomly spawn in. +- Unstable Rift spawn interval increased from every 6 minutes to every 7 minutes +- Unstable Rift comeback bonuses (resists in the area, extra comeback bounty, and trailing/leading team claiming timer) now all scale linearly based on the amount of NW they are trailing (scales from no bonus at 0% NW behind to full bonus at 15% NW behind) +- The team that secures the Unstable Rift now also has a wave of 5 Rift Troopers sent down from the rift location. When trailing, spawns up to 12 troopers instead (using the same linear ramp from 0% NW to -15% NW) +- Rift Troopers drop no souls when killed +- Rift Troopers spawn with 100% extra health and damage (they also look larger and have custom VFX). Their bonus health and damage grow slightly per event (first one is 100%, then 120%, 140%, etc) +- Any players in the Unstable Rift Zone are now revealed on the minimap +- Unstable Rift bounty increased by 35% (to account for the 35% loss with no urn runner bounty, overall objective bounty is unchanged) +- Unstable Rift no longer grants +1 permanent buff to each player (there is also no +3 buffs to the urn runner) + +- Urn running is now its own objective. Spawns on either end of the map (where the previous neutral pickup locations were), and gets delivered to the opposite end. Spawns at 10/15/20/25/etc. +- Urn runner is no longer revealed and is not disarmed or silenced (going through a doorway or mirage teleport still drops it) +- Urn cannot be manually dropped. It gets dropped when you get hit with a light or heavy melee, are stunned or are killed. It stays where it drops and does not walk back home. +- Urn runner can no longer parry +- Urn bounty value starts decaying after 45s from being picked up. It drains gradually over another 45s and then the urn is removed when the bounty is empty. +- Urn is deposited immediately at the drop off point. +- Urn bounty when deposited is worth 250 + 70/min for just the urn runner. Still has the comeback bounty component. Upon deposit all of the souls are released as orbs into the air (if another ally secures the orbs, they share the bounty with the urn runner). +- Urn runner gets +4 permanent buffs on deposit +- Urn is now louder when it talks and is easier to hear by nearby enemies +- After 3 Minutes from spawn the Urn will start walking very slowly on his own towards the deposit location +- Urn runner's passive bonuses while holding it now scales based on how behind you are, rather than being on or off (same as the Unstable Rift 0%-15% NW linear scaling). Bonuses are the same as the previous urn runner bonuses. + +There are two debug commands you can use to test these out +- citadel_force_spawn_idol - This spawns the Urn +- citadel_koth_dev_test_spawn - This moves your hero and spawns the Unstable Rift in the early warning state then quickly transitions to the 25s broadcasted timer + +[ General ] + +- Reworked Boon reward table + +- Health per boon reduced by 5% +- All ultimate base and upgrade cooldowns nerfed by 15% (rounded to the nearest multiple of 5) +- Rejuv buff duration reduced from 4 minutes to 3 +- Respawn ramp changed from 8-30s from 5-19m to 8-35s from 5-20m +- Guardian bounty reduced from 1500 to 1250 +- Walker bounty reduced from 4000 to 3500 +- First blood bounty reduced from 150 to 125 +- Base kill bounty reduced from 250 to 200 (max is still 2200 at 40m) +- Trooper bounty rescaled from 116 + 1.16/m to 100 + 2/m (less before 20m, more after) +- Trooper bounty ratio in the deniable flying orb increased from 40% to 50% +- Minimum unsecured souls allowed to drop reduced from 150 to 50 + 5/min + +- Dash Jump input window increased from 0.2s to 0.25s duration (start time: 0.3s to end time: 0.55s) +- Dash Jump distance increased from 18m to 19m +- Dash Jump vertical impulse increased from 400 to 425 + +- Jump Pads on top of the double sinner buildings have been removed + +- Hovering an item in the shop now shows you a preview for your investment bars + +- Street Brawl: No longer locks you out of getting off the zipline in the first few seconds +- Street Brawl: Increased item randomness a bit +- Street Brawl: Fixed Enhanced Sharpshooter and Enhanced Spiritual Overflow not maintaining the bonuses from their enhanced components + +[ Items ] + +- Mystic Shot: Cooldown increased from 8s to 9s +- Toxic Bullets: Bleed damage increased from 1.7% to 1.9% +- Scourge: Max Health DPS reduced from 3.5% to 2.6% +- Scourge: Max Health DPS now scales with spirit power (0.0055) +- Cursed Relic: Damage Penalty increased from -10% to -14% + +[ Heroes ] + +- Abrams: Siphon Life T3 reduced from +3m Radius to +2m +- Abrams: Shoulder Charge T3 reduced from -20s Cooldown to -18s + +- Apollo: Riposte T1 increased from -7s Cooldown to -8s +- Apollo: Riposte grace window to target after channel increased from +1s to +1.3s +- Apollo: Riposte cast range increased from 25m to 35m +- Apollo: Riposte targeting angle increased from 70 to 90 +- Apollo: Flawless Advance Heal on hero hit spirit scaling increased from 1 to 1.3 +- Apollo: Itani Lo Sahn T3 increased from +40% Bonus Damage to +50% + +- Billy: Bullet damage per boon reduced by 10% +- Billy: Bashdown melee scaling reduced from 1.1 to 0.9 +- Billy: Bashdown T3 reduced from 60% Heavy Melee damage to 50% +- Billy: Rising Ram T3 Max HP Damage reduced from 10% to 8% +- Billy: Rising Ram T3 Max HP Damage spirit scaling increased from 0.017 to 0.035 (break even at 111 spirit power) + +- Celeste: Dazzling Trick cooldown reduced from 35s to 32s +- Celeste: Radiant Daggers buff duration increased from 25s to 30s +- Celeste: Radiant Daggers spirit scaling increased from 0.56 to 0.63 +- Celeste: Shining Wonder bounce range increased from 15.5m to 16.5m +- Celeste: Shining Wonder damage increased by 10% + +- Doorman: Doorway cooldown increased from 40s to 45s + +- Drifter: Health per boon increased from 41 to 43 (global hp boon reduction is after this) +- Drifter: Rend cast time reduced from 0.5s to 0.4s +- Drifter: Rend post cast time reduced from 0.5s to 0.4s +- Drifter: Rend T2 increased from -7s Cooldown to -8s +- Drifter: Bloodscent T1 increased from +2m/s while near an isolated enemy to +3m/s +- Drifter: Bloodscent T2 increased from 18% missing health heal to +24% + +- Dynamo: Rejuvenating Aurora regeneration increased from 25/s to 30/s + +- Grey Talon: Rain of Arrows cooldown increased from 23s to 25s +- Grey Talon: Guided Owl permanent spirit bonus reduced from 10 to 8 + +- Holliday: Powder Keg velocity reduced slightly +- Holliday: Powder Keg charge delay increased from 7s to 7.5s +- Holliday: Powder Keg spirit scaling reduced from 1.4 to 1.2 +- Holliday: Powder Keg T3 reduced from +100 Damage to +80 + +- Haze: Sleep Dagger T1 increased from -8% Bullet Resist to -10% +- Haze: Sleep Dagger T2 increased from -17s Cooldown to -18s +- Haze: Smoke Bomb T3 increased from +40% Bullet Lifesteal to +50% + +- Ivy: Entangling Thorns spirit scaling increased from 0.45 to 0.55 +- Ivy: Kudzu Connection Replicated Healing per boon scale increased from +0.5 to +0.85 +- Ivy: Air Drop cooldown reduction when used on allies increased from -25% to -30% + +- Lash: Ground Strike cooldown reduced from 21s to 18s +- Lash: Flog angle increased from 30 to 38 + +- Mina: Rake missing health as damage increased from 5% to 6% +- Mina: Sanguine Retreat T3 now also increases range by +3m +- Mina: Nox Nostra damage increased from 4.45 to 4.6 +- Mina: Nox Nostra T1 damage increased from +1.74 to +1.9 + +- Mo & Krill: Sand Blast T2 slow increased from -25% to -30% +- Mo & Krill: Sand Blast T3 increased from -20s Cooldown to -25s +- Mo & Krill: Combo bonus max health per kill increased from 30+1/boon to 40+2/boon + +- Paige: Health per boon increased from 29 to 33 +- Paige: Bookwyrm T1 changed from "+2s Trail Duration and +1m Radius" to "-12s Cooldown" +- Paige: Bookwyrm T2 changed from "+10m Range and -12s Cooldown" to "+1 Charge, +1m Radius and +2s Trail Duration" +- Paige: Bookworm T3 changed from "+100 Damage, +30 DPS and +1 Charge" to "+100 Damage, +30 DPS and +12m Travel Range" +- Paige: Plot Armor T1 fire rate spirit scaling increased from 0.13 to 0.16 +- Paige: Plot Armor T3 increased from 75% Barrier to 100% +- Paige: Rallying Charge is now properly counted as a "miss" (for the -50% CD Reduction) if the only thing that was impacted were non-heroes +- Paige: Rallying Charge T3 Max Amp increased from +50% to +70% + +- Paradox: Kinetic Carbine T2 now also increases move speed spirit scaling (0.06) +- Paradox: Kinetic Carbine T3 changed from affecting Max Damage Scaling to affecting both Min and Max Damage Scaling + +- Pocket: Bullet damage per boon reduced from 0.16 to 0.14 +- Pocket: Flying Cloak T3 reduced from -12s Cooldown to -11s + +- Rem: Tag Along healing per second spirit scaling reduced from 0.66 to 0.4 +- Rem: Tag Along T3 missing health spirit scaling reduced from +0.02 to +0.016 +- Rem: Lil Helpers Spirit Resist reduced from 15% to 12% +- Rem: Lil Helpers T1 changed from "+1 Helper" to "+1 Helper and +1.5m/s Move Speed" +- Rem: Lil Helpers T2 changed from "+8% Spirit Resist and +1.5m/s Move Speed" to "+1 Helper and +15% Trooper Damage and Resist" +- Rem: Lil Helpers T3 changed from "+2 Helpers and +20% Trooper Damage and Resist" to "+1 Helper and +15% Spirit Resist" + +- Seven: Lightning Ball charge delay reduced from 7s to 6s +- Seven: Storm Cloud time to expand increased from 1.5s to 3.5s +- Seven: Storm Cloud damage interval increased from 0.25s to 0.3s (DPS unchanged) +- Seven: Storm Cloud T2 now also increases Initial Radius by +5m + +- Shiv: Alt Fire damage now has a custom value per boon (+0.2) +- Shiv: Alt Fire ammo consumed per shot increased from 3 to 5 +- Shiv: Alt Fire knockback movement is now disabled by slowing hex state +- Shiv: Serrated Knives cooldown reduced from 18s to 16s +- Shiv: Slice and Dice now deals +25 light melee damage (75 total) instead of 60 spirit damage +- Shiv: Slice and Dice changed from -6% Spirit Resist to +4% Damage Amp +- Shiv: Bloodletting T2 changed from "+15% Incoming Damage Deferred" to "+35% Deferred Damage Cleared" +- Shiv: Bloodletting T3 changed from "+50% Deferred Damage Cleared" to "+15% Incoming Damage Deferred" +- Shiv: Killing Blow now deals damage to troopers and neutrals along the way +- Shiv: Killing Blow executing a hero now instantly fills the rage bar +- Shiv: Killing Blow now has the T3 "recast within 20s on a hero kill" as part of the base ability +- Shiv: Killing Blow Full Rage Damage Bonus reduced from +12% to +8% +- Shiv: Killing Blow range reduced from 18m to 12m +- Shiv: Killing Blow T1 now also increases range by +6m +- Shiv: Killing Blow T2 increased from +10% Full Rage Bonus Damage to +16% +- Shiv: Killing Blow T3 increased from +5% Enemy health Threshold to +10% + +- Vindicta: Stake T2 reduced from -20s Cooldown to -22s +- Vindicta: Crow Familiar T2 increased from -12s Cooldown to -16s +- Vindicta: Crow Familiar collision radius between each crow increased slightly +- Vindicta: Assassinate Max Bonus Damage spirit scaling increased from 2 to 2.3 + +- Viscous: Splatter T3 spirit scaling reduced from +1.1 to +1.0 +- Viscous: Puddle Punch T3 increased from -12s Cooldown to -14s +- Viscous: Goo Ball T3 increased from +6s Duration to +7s + +- Vyper: Screwjab Dagger T3 now also reduces charge delay from 4s to 2s +- Vyper: Slither T3 spirit scaling increased from 0.6 to 0.8 + +- Warden: Bullet damage per boon reduced from 0.34 to 0.28 +- Warden: Willpower T2 increased from -22s Cooldown to -24s +- Warden: Willpower T3 increased from +2.5 spirit power scaling to +2.7 \ No newline at end of file diff --git a/input-data/changelogs/raw/2026-07-01.txt b/input-data/changelogs/raw/2026-07-01.txt new file mode 100644 index 00000000..1523f88b --- /dev/null +++ b/input-data/changelogs/raw/2026-07-01.txt @@ -0,0 +1,5 @@ +- Shiv: Alt Fire ammo cost reduced from 5 to 4 +- Shiv: Weapon now has fixed pellet spread +- Shiv: Slice and Dice is now back to doing spirit damage and reducing Spirit Resistance from enemies +- Shiv: Slice and Dice damage increased from 60 to 75 +- Shiv: Killing Blow T3 reduced from +10% Enemy Health Threshold to +8% \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 52ba9822..0ae762f5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,53 +1,15 @@ # This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. -[[package]] -name = "beautifulsoup4" -version = "4.14.3" -description = "Screen-scraping library" -optional = false -python-versions = ">=3.7.0" -groups = ["main"] -files = [ - {file = "beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb"}, - {file = "beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86"}, -] - -[package.dependencies] -soupsieve = ">=1.6.1" -typing-extensions = ">=4.0.0" - -[package.extras] -cchardet = ["cchardet"] -chardet = ["chardet"] -charset-normalizer = ["charset-normalizer"] -html5lib = ["html5lib"] -lxml = ["lxml"] - -[[package]] -name = "bs4" -version = "0.0.2" -description = "Dummy package for Beautiful Soup (beautifulsoup4)" -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "bs4-0.0.2-py2.py3-none-any.whl", hash = "sha256:abf8742c0805ef7f662dce4b51cca104cffe52b835238afc169142ab9b3fbccc"}, - {file = "bs4-0.0.2.tar.gz", hash = "sha256:a48685c58f50fe127722417bae83fe6badf500d54b55f7e39ffe43b798653925"}, -] - -[package.dependencies] -beautifulsoup4 = "*" - [[package]] name = "certifi" -version = "2026.5.20" +version = "2026.6.17" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" groups = ["main"] files = [ - {file = "certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897"}, - {file = "certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d"}, + {file = "certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db"}, + {file = "certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432"}, ] [[package]] @@ -216,41 +178,26 @@ files = [ [[package]] name = "distlib" -version = "0.4.1" +version = "0.4.3" description = "Distribution utilities" optional = false python-versions = "*" groups = ["dev"] files = [ - {file = "distlib-0.4.1-py2.py3-none-any.whl", hash = "sha256:9c2c552c68cbadc619f2d0ed3a69e27c351a3f4c9baa9ffb7df9e9cdc3d19a97"}, - {file = "distlib-0.4.1.tar.gz", hash = "sha256:c3804d0d2d4b5fcd44036eb860cb6660485fcdf5c2aba53dc324d805837ea65b"}, + {file = "distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b"}, + {file = "distlib-0.4.3.tar.gz", hash = "sha256:f152097224a0ae24be5a0f6bae1b9359af82133bce63f98a95f86cae1aede9ed"}, ] -[[package]] -name = "feedparser" -version = "6.0.12" -description = "Universal feed parser, handles RSS 0.9x, RSS 1.0, RSS 2.0, CDF, Atom 0.3, and Atom 1.0 feeds" -optional = false -python-versions = ">=3.6" -groups = ["main"] -files = [ - {file = "feedparser-6.0.12-py3-none-any.whl", hash = "sha256:6bbff10f5a52662c00a2e3f86a38928c37c48f77b3c511aedcd51de933549324"}, - {file = "feedparser-6.0.12.tar.gz", hash = "sha256:64f76ce90ae3e8ef5d1ede0f8d3b50ce26bcce71dd8ae5e82b1cd2d4a5f94228"}, -] - -[package.dependencies] -sgmllib3k = "*" - [[package]] name = "filelock" -version = "3.29.1" +version = "3.29.5" description = "A platform independent file lock." optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "filelock-3.29.1-py3-none-any.whl", hash = "sha256:85199dfd706869641b72b2e8955d5416a4b2b7dc4b0e8e6d97b4cc1299a6983b"}, - {file = "filelock-3.29.1.tar.gz", hash = "sha256:d97e6b1b9757569626c58caa07dc4beb1613f4a2938b1e8cc81afca398906c9e"}, + {file = "filelock-3.29.5-py3-none-any.whl", hash = "sha256:8af830889ba3a0ffcefbd6c7d2af8a54012058103771f2e10848222f476a1693"}, + {file = "filelock-3.29.5.tar.gz", hash = "sha256:6e6034c57a00a020e767f2614a5539863f056de7e7991d6d1473aef7ff73f156"}, ] [[package]] @@ -422,13 +369,13 @@ files = [ [[package]] name = "nuitka" -version = "4.1.2" +version = "4.1.3" description = "Python compiler with full language support and CPython compatibility" optional = false python-versions = "*" groups = ["build"] files = [ - {file = "nuitka-4.1.2.tar.gz", hash = "sha256:efc2359b171d7b63046ca8ec8dee57015c3466a9df74b68a049c2c1a7e93ecee"}, + {file = "nuitka-4.1.3.tar.gz", hash = "sha256:838ff8899dc2f0b652d4fcf6c5d7466cb7ad5abcb005668ac622d1e40f4d8a8d"}, ] [package.extras] @@ -475,103 +422,99 @@ testing = ["pytest"] [[package]] name = "pillow" -version = "12.2.0" +version = "12.3.0" description = "Python Imaging Library (fork)" optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "pillow-12.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:a4e8f36e677d3336f35089648c8955c51c6d386a13cf6ee9c189c5f5bd713a9f"}, - {file = "pillow-12.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e589959f10d9824d39b350472b92f0ce3b443c0a3442ebf41c40cb8361c5b97"}, - {file = "pillow-12.2.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a52edc8bfff4429aaabdf4d9ee0daadbbf8562364f940937b941f87a4290f5ff"}, - {file = "pillow-12.2.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:975385f4776fafde056abb318f612ef6285b10a1f12b8570f3647ad0d74b48ec"}, - {file = "pillow-12.2.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bd9c0c7a0c681a347b3194c500cb1e6ca9cab053ea4d82a5cf45b6b754560136"}, - {file = "pillow-12.2.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:88d387ff40b3ff7c274947ed3125dedf5262ec6919d83946753b5f3d7c67ea4c"}, - {file = "pillow-12.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:51c4167c34b0d8ba05b547a3bb23578d0ba17b80a5593f93bd8ecb123dd336a3"}, - {file = "pillow-12.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:34c0d99ecccea270c04882cb3b86e7b57296079c9a4aff88cb3b33563d95afaa"}, - {file = "pillow-12.2.0-cp310-cp310-win32.whl", hash = "sha256:b85f66ae9eb53e860a873b858b789217ba505e5e405a24b85c0464822fe88032"}, - {file = "pillow-12.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:673aa32138f3e7531ccdbca7b3901dba9b70940a19ccecc6a37c77d5fdeb05b5"}, - {file = "pillow-12.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:3e080565d8d7c671db5802eedfb438e5565ffa40115216eabb8cd52d0ecce024"}, - {file = "pillow-12.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:8be29e59487a79f173507c30ddf57e733a357f67881430449bb32614075a40ab"}, - {file = "pillow-12.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:71cde9a1e1551df7d34a25462fc60325e8a11a82cc2e2f54578e5e9a1e153d65"}, - {file = "pillow-12.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f490f9368b6fc026f021db16d7ec2fbf7d89e2edb42e8ec09d2c60505f5729c7"}, - {file = "pillow-12.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8bd7903a5f2a4545f6fd5935c90058b89d30045568985a71c79f5fd6edf9b91e"}, - {file = "pillow-12.2.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3997232e10d2920a68d25191392e3a4487d8183039e1c74c2297f00ed1c50705"}, - {file = "pillow-12.2.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e74473c875d78b8e9d5da2a70f7099549f9eb37ded4e2f6a463e60125bccd176"}, - {file = "pillow-12.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:56a3f9c60a13133a98ecff6197af34d7824de9b7b38c3654861a725c970c197b"}, - {file = "pillow-12.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:90e6f81de50ad6b534cab6e5aef77ff6e37722b2f5d908686f4a5c9eba17a909"}, - {file = "pillow-12.2.0-cp311-cp311-win32.whl", hash = "sha256:8c984051042858021a54926eb597d6ee3012393ce9c181814115df4c60b9a808"}, - {file = "pillow-12.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e6b2a0c538fc200b38ff9eb6628228b77908c319a005815f2dde585a0664b60"}, - {file = "pillow-12.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:9a8a34cc89c67a65ea7437ce257cea81a9dad65b29805f3ecee8c8fe8ff25ffe"}, - {file = "pillow-12.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d192a155bbcec180f8564f693e6fd9bccff5a7af9b32e2e4bf8c9c69dbad6b5"}, - {file = "pillow-12.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3f40b3c5a968281fd507d519e444c35f0ff171237f4fdde090dd60699458421"}, - {file = "pillow-12.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:03e7e372d5240cc23e9f07deca4d775c0817bffc641b01e9c3af208dbd300987"}, - {file = "pillow-12.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b86024e52a1b269467a802258c25521e6d742349d760728092e1bc2d135b4d76"}, - {file = "pillow-12.2.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7371b48c4fa448d20d2714c9a1f775a81155050d383333e0a6c15b1123dda005"}, - {file = "pillow-12.2.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62f5409336adb0663b7caa0da5c7d9e7bdbaae9ce761d34669420c2a801b2780"}, - {file = "pillow-12.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:01afa7cf67f74f09523699b4e88c73fb55c13346d212a59a2db1f86b0a63e8c5"}, - {file = "pillow-12.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc3d34d4a8fbec3e88a79b92e5465e0f9b842b628675850d860b8bd300b159f5"}, - {file = "pillow-12.2.0-cp312-cp312-win32.whl", hash = "sha256:58f62cc0f00fd29e64b29f4fd923ffdb3859c9f9e6105bfc37ba1d08994e8940"}, - {file = "pillow-12.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f84204dee22a783350679a0333981df803dac21a0190d706a50475e361c93f5"}, - {file = "pillow-12.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:af73337013e0b3b46f175e79492d96845b16126ddf79c438d7ea7ff27783a414"}, - {file = "pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8297651f5b5679c19968abefd6bb84d95fe30ef712eb1b2d9b2d31ca61267f4c"}, - {file = "pillow-12.2.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:50d8520da2a6ce0af445fa6d648c4273c3eeefbc32d7ce049f22e8b5c3daecc2"}, - {file = "pillow-12.2.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:766cef22385fa1091258ad7e6216792b156dc16d8d3fa607e7545b2b72061f1c"}, - {file = "pillow-12.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5d2fd0fa6b5d9d1de415060363433f28da8b1526c1c129020435e186794b3795"}, - {file = "pillow-12.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:56b25336f502b6ed02e889f4ece894a72612fe885889a6e8c4c80239ff6e5f5f"}, - {file = "pillow-12.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f1c943e96e85df3d3478f7b691f229887e143f81fedab9b20205349ab04d73ed"}, - {file = "pillow-12.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03f6fab9219220f041c74aeaa2939ff0062bd5c364ba9ce037197f4c6d498cd9"}, - {file = "pillow-12.2.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cdfebd752ec52bf5bb4e35d9c64b40826bc5b40a13df7c3cda20a2c03a0f5ed"}, - {file = "pillow-12.2.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eedf4b74eda2b5a4b2b2fb4c006d6295df3bf29e459e198c90ea48e130dc75c3"}, - {file = "pillow-12.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:00a2865911330191c0b818c59103b58a5e697cae67042366970a6b6f1b20b7f9"}, - {file = "pillow-12.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1e1757442ed87f4912397c6d35a0db6a7b52592156014706f17658ff58bbf795"}, - {file = "pillow-12.2.0-cp313-cp313-win32.whl", hash = "sha256:144748b3af2d1b358d41286056d0003f47cb339b8c43a9ea42f5fea4d8c66b6e"}, - {file = "pillow-12.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:390ede346628ccc626e5730107cde16c42d3836b89662a115a921f28440e6a3b"}, - {file = "pillow-12.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:8023abc91fba39036dbce14a7d6535632f99c0b857807cbbbf21ecc9f4717f06"}, - {file = "pillow-12.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:042db20a421b9bafecc4b84a8b6e444686bd9d836c7fd24542db3e7df7baad9b"}, - {file = "pillow-12.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:dd025009355c926a84a612fecf58bb315a3f6814b17ead51a8e48d3823d9087f"}, - {file = "pillow-12.2.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88ddbc66737e277852913bd1e07c150cc7bb124539f94c4e2df5344494e0a612"}, - {file = "pillow-12.2.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d362d1878f00c142b7e1a16e6e5e780f02be8195123f164edf7eddd911eefe7c"}, - {file = "pillow-12.2.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c727a6d53cb0018aadd8018c2b938376af27914a68a492f59dfcaca650d5eea"}, - {file = "pillow-12.2.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:efd8c21c98c5cc60653bcb311bef2ce0401642b7ce9d09e03a7da87c878289d4"}, - {file = "pillow-12.2.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f08483a632889536b8139663db60f6724bfcb443c96f1b18855860d7d5c0fd4"}, - {file = "pillow-12.2.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dac8d77255a37e81a2efcbd1fc05f1c15ee82200e6c240d7e127e25e365c39ea"}, - {file = "pillow-12.2.0-cp313-cp313t-win32.whl", hash = "sha256:ee3120ae9dff32f121610bb08e4313be87e03efeadfc6c0d18f89127e24d0c24"}, - {file = "pillow-12.2.0-cp313-cp313t-win_amd64.whl", hash = "sha256:325ca0528c6788d2a6c3d40e3568639398137346c3d6e66bb61db96b96511c98"}, - {file = "pillow-12.2.0-cp313-cp313t-win_arm64.whl", hash = "sha256:2e5a76d03a6c6dcef67edabda7a52494afa4035021a79c8558e14af25313d453"}, - {file = "pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:3adc9215e8be0448ed6e814966ecf3d9952f0ea40eb14e89a102b87f450660d8"}, - {file = "pillow-12.2.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:6a9adfc6d24b10f89588096364cc726174118c62130c817c2837c60cf08a392b"}, - {file = "pillow-12.2.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:6a6e67ea2e6feda684ed370f9a1c52e7a243631c025ba42149a2cc5934dec295"}, - {file = "pillow-12.2.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:2bb4a8d594eacdfc59d9e5ad972aa8afdd48d584ffd5f13a937a664c3e7db0ed"}, - {file = "pillow-12.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:80b2da48193b2f33ed0c32c38140f9d3186583ce7d516526d462645fd98660ae"}, - {file = "pillow-12.2.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22db17c68434de69d8ecfc2fe821569195c0c373b25cccb9cbdacf2c6e53c601"}, - {file = "pillow-12.2.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7b14cc0106cd9aecda615dd6903840a058b4700fcb817687d0ee4fc8b6e389be"}, - {file = "pillow-12.2.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8cbeb542b2ebc6fcdacabf8aca8c1a97c9b3ad3927d46b8723f9d4f033288a0f"}, - {file = "pillow-12.2.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4bfd07bc812fbd20395212969e41931001fd59eb55a60658b0e5710872e95286"}, - {file = "pillow-12.2.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:9aba9a17b623ef750a4d11b742cbafffeb48a869821252b30ee21b5e91392c50"}, - {file = "pillow-12.2.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:deede7c263feb25dba4e82ea23058a235dcc2fe1f6021025dc71f2b618e26104"}, - {file = "pillow-12.2.0-cp314-cp314-win32.whl", hash = "sha256:632ff19b2778e43162304d50da0181ce24ac5bb8180122cbe1bf4673428328c7"}, - {file = "pillow-12.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:4e6c62e9d237e9b65fac06857d511e90d8461a32adcc1b9065ea0c0fa3a28150"}, - {file = "pillow-12.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:b1c1fbd8a5a1af3412a0810d060a78b5136ec0836c8a4ef9aa11807f2a22f4e1"}, - {file = "pillow-12.2.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:57850958fe9c751670e49b2cecf6294acc99e562531f4bd317fa5ddee2068463"}, - {file = "pillow-12.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:d5d38f1411c0ed9f97bcb49b7bd59b6b7c314e0e27420e34d99d844b9ce3b6f3"}, - {file = "pillow-12.2.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c0a9f29ca8e79f09de89293f82fc9b0270bb4af1d58bc98f540cc4aedf03166"}, - {file = "pillow-12.2.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1610dd6c61621ae1cf811bef44d77e149ce3f7b95afe66a4512f8c59f25d9ebe"}, - {file = "pillow-12.2.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a34329707af4f73cf1782a36cd2289c0368880654a2c11f027bcee9052d35dd"}, - {file = "pillow-12.2.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e9c4f5b3c546fa3458a29ab22646c1c6c787ea8f5ef51300e5a60300736905e"}, - {file = "pillow-12.2.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fb043ee2f06b41473269765c2feae53fc2e2fbf96e5e22ca94fb5ad677856f06"}, - {file = "pillow-12.2.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f278f034eb75b4e8a13a54a876cc4a5ab39173d2cdd93a638e1b467fc545ac43"}, - {file = "pillow-12.2.0-cp314-cp314t-win32.whl", hash = "sha256:6bb77b2dcb06b20f9f4b4a8454caa581cd4dd0643a08bacf821216a16d9c8354"}, - {file = "pillow-12.2.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6562ace0d3fb5f20ed7290f1f929cae41b25ae29528f2af1722966a0a02e2aa1"}, - {file = "pillow-12.2.0-cp314-cp314t-win_arm64.whl", hash = "sha256:aa88ccfe4e32d362816319ed727a004423aab09c5cea43c01a4b435643fa34eb"}, - {file = "pillow-12.2.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0538bd5e05efec03ae613fd89c4ce0368ecd2ba239cc25b9f9be7ed426b0af1f"}, - {file = "pillow-12.2.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:394167b21da716608eac917c60aa9b969421b5dcbbe02ae7f013e7b85811c69d"}, - {file = "pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5d04bfa02cc2d23b497d1e90a0f927070043f6cbf303e738300532379a4b4e0f"}, - {file = "pillow-12.2.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0c838a5125cee37e68edec915651521191cef1e6aa336b855f495766e77a366e"}, - {file = "pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a6c9fa44005fa37a91ebfc95d081e8079757d2e904b27103f4f5fa6f0bf78c0"}, - {file = "pillow-12.2.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:25373b66e0dd5905ed63fa3cae13c82fbddf3079f2c8bf15c6fb6a35586324c1"}, - {file = "pillow-12.2.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bfa9c230d2fe991bed5318a5f119bd6780cda2915cca595393649fc118ab895e"}, - {file = "pillow-12.2.0.tar.gz", hash = "sha256:a830b1a40919539d07806aa58e1b114df53ddd43213d9c8b75847eee6c0182b5"}, + {file = "pillow-12.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6c0016e7b354317c4e9e525b937ac8596c38d2d232b419529b9cd7a1cd46e39a"}, + {file = "pillow-12.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bcc33feacfaefce60c12fd500a277533bdc02b10a19f7f6d348763d8140bbba7"}, + {file = "pillow-12.3.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5594fc43d548a7ed94949d139aa1341b270f1863f11cfd37f5a6c8b778a6b67f"}, + {file = "pillow-12.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f0606c8bf2cdefea14a43530f7657cbbb7ecf1c4222512492ef4a4434a9501ec"}, + {file = "pillow-12.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:85f998ea1848bc6757289e739cfbdda3a04adfd58b02fc018ce54d754a5ce468"}, + {file = "pillow-12.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:25b9b82bb22e6e2b3cd07b39c68b7b862001226cb3dff7130d1cb914121b39ed"}, + {file = "pillow-12.3.0-cp310-cp310-win32.whl", hash = "sha256:37dc8f7bbb66efe481bb60defacef820c950c24713fb44962ed6aa2a50966de1"}, + {file = "pillow-12.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:300557495eb45ebb8aec96c2da9c4be642fbf7cd937278b4013ba894ea8eb0eb"}, + {file = "pillow-12.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:514435a37670e3e5e08f3945b68718b6ed329bb84367777e16f9f4dfe1e61a0f"}, + {file = "pillow-12.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:00808c5e14ef63ac5161091d242999076604ff74b883423a11e5d7bbb38bf756"}, + {file = "pillow-12.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37d6d0a00072fd2948eb22bce7e1475f34569d90c87c59f7a2ec59541b77f7a6"}, + {file = "pillow-12.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bcb46e2f9feff8d06323983bd83ed00c201fdcab3d74973e7072a889b3979fcd"}, + {file = "pillow-12.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23d27a3e0307ec2244cc51e7287b919aa68d097504ebe19df4e76a98a3eea5bd"}, + {file = "pillow-12.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4f883547d4b7f0495ebe7056b0cc2aea76094e7a4abc8e933540f3271df27d9c"}, + {file = "pillow-12.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:236ff70b9312fb68943c703aa842ca6a758abfa45ac187a5e7c1452e96ef72b5"}, + {file = "pillow-12.3.0-cp311-cp311-win32.whl", hash = "sha256:10e41f0fbf1eec8cfd234b8fe17a4caac7c9d0db4c204d3c173a8f9f6ef3232b"}, + {file = "pillow-12.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8e95e1385e4998ae9694eeaa4730ba5457ff61185b3a55e2e7bea0880aef452a"}, + {file = "pillow-12.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:ebaea975e03d3141d9d3a507df75c9b3ec90fa9d2ffd07567b3a978d9d790b26"}, + {file = "pillow-12.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ba09209fbe443b4acccebe845d8a138b89a8f4fbaeedd44953490b5315d5e965"}, + {file = "pillow-12.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ffd0c5368496f41b0944be820fcb7a838aa6e623d250b01acf2643939c3f99d7"}, + {file = "pillow-12.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d9c7f76c0673154f044e9d78c8655fb4213f6ca31a836df48b40fe5d187717b9"}, + {file = "pillow-12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:78cb2c6865a35ab8ff8b75fd122f6033b92a62c82801110e48ddd6c936a45d91"}, + {file = "pillow-12.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e491916b378fba47242221bb9ead245211b70d504f495d105d17b14a24b4907c"}, + {file = "pillow-12.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0dd2064cbc55aaec028ef5fbb60fa47bb6c3e7918e07ff17935284b227a9d2df"}, + {file = "pillow-12.3.0-cp312-cp312-win32.whl", hash = "sha256:dbce0b29841537a2fa4a214c2bbf14de3587c9680caa9b4e217568472490b28f"}, + {file = "pillow-12.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a2b55dd6b2a4c4b7d87ffa56bdb33fdc5fdb9a462173861a7bc097f17d91cb09"}, + {file = "pillow-12.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:331b624368d4f1d069149002f25f44bc61c8919ce8ddb3c45bdad8f6e2d89510"}, + {file = "pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:21900ce7ba264168cd50defae43cd75d25c833ad4ad6e73ffc5596d12e25ac89"}, + {file = "pillow-12.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:4e8c2a84d977f50b9daed6eeaf3baef67d00d5d74d932288f02cb94518ee3ace"}, + {file = "pillow-12.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:ae26d61dfa7a47befdc7572b521024e8745f3d809bd95ca9505a7bba9ef849ec"}, + {file = "pillow-12.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7a743ff716f746fc19a9557f60dab1600d4613255f8a7aeb3cdde4db7eb15a66"}, + {file = "pillow-12.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d69141514cc30b774ceea5e3ed3a6635c8d8a96edf664689b890f4089111fb35"}, + {file = "pillow-12.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f7401aebd7f581d7f83a439d87d474999317ee099218e5ad25d125290990ba65"}, + {file = "pillow-12.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0847a763afefb695bc912d7c131e7e0632d4edc1d8698f58ddabec8e46b8b6d3"}, + {file = "pillow-12.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:571b9fcb07b97ef3a492028fb3d2dc0993ca23a06138b0315286566d29ef718a"}, + {file = "pillow-12.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:756c768d0c9c2955feb7a56c37ea24aea2e369f8d36a88da270b6a9f19e62b5e"}, + {file = "pillow-12.3.0-cp313-cp313-win32.whl", hash = "sha256:a876864214e136f0eb367788dbd7df045f4806801518e2cfe9e13229cfe06d8f"}, + {file = "pillow-12.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1cca606cd25738df4ed873d5ad46bbdb3d83b5cbca291f6b4ff13a4df6b0bbe8"}, + {file = "pillow-12.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:b629de27fda84b42cde7edef0d85f13b958b47f6e9bbcbba9b673c562a89bd8b"}, + {file = "pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:9cf95fe4d0f84c82d282745d9bb08ad9f926efa00be4697e767b814ce40d4330"}, + {file = "pillow-12.3.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:8728f216dcdb6e6d555cf971cb34076139ad74b31fc2c14da4fafc741c5f6217"}, + {file = "pillow-12.3.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:a45650e8ce7fafffd731db8550230db6b0d306d181a90b67d3e6bca2f1990930"}, + {file = "pillow-12.3.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ba54cfebe86920a559a7c4d6b9050791c20513650a1952ebe3368c7dc70306f8"}, + {file = "pillow-12.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e158cb00350dc278f3b91551101aa7d12415a66ebf2c91d8d5ac14e56ddd3ad0"}, + {file = "pillow-12.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e9aeb04d6aef139de265b29683e119b638208f88cf73cdd1658aa07221165321"}, + {file = "pillow-12.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:251bf95b67017e27b13d82f5b326234ca62d70f9cf4c2b9032de2358a3b12c7b"}, + {file = "pillow-12.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fe3cca2e4e8a592be0f269a1ca4835c25199d9f3ce815c8491048f785b0a0198"}, + {file = "pillow-12.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:23aceaa007d6172b02c277f0cd359c79492bbb14f7072b4ede9fbcaf20648130"}, + {file = "pillow-12.3.0-cp314-cp314-win32.whl", hash = "sha256:af8d94b0db561cf68b88a267c5c44b49e134f525d0dc2cb7ed413a66bc23559a"}, + {file = "pillow-12.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:fdafc9cce40277e0f7a0feabce0ee50dd2fa1800f3b38015e51296b5e814048d"}, + {file = "pillow-12.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:e91206ee562682b51b98ef4b26a6ef48fd84e15fd4c4bc5ec768eb641d206838"}, + {file = "pillow-12.3.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:164b31cd1a0490ab6efae01aa5df49da7061be0af1b30e035b6e9a1bfe34ee6e"}, + {file = "pillow-12.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5afb51d599ea772b8365ae807ae557f18bccfe46ab261fd1c2a9ed700fc6eb17"}, + {file = "pillow-12.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3edce1d53195db527e0191f84b71d02022de0540bf43a16ed734ed7537b07385"}, + {file = "pillow-12.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bf16ba1b4d0b6b7c8e534936632270cf70eb00dbe09005bc345b2677b726855c"}, + {file = "pillow-12.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:24870b09b224f7ae3c39ed07d10e819d06f8720bc551847b1d623832b5b0e28d"}, + {file = "pillow-12.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:30f2aa603c41533cc25c05acd0da21636e84a315768feb631c937177db558931"}, + {file = "pillow-12.3.0-cp314-cp314t-win32.whl", hash = "sha256:4b0a7fe987b14c31ebda6083f74f22b561fd3739bc0ac51e019622e3d72668c7"}, + {file = "pillow-12.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:962864dc93511324d51ddbb5b9f8731bf71675b93ca612a07441896f4688fb8c"}, + {file = "pillow-12.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0740a512dc522224c77d9aa5a8d70d8b7d73fb91f2c21125d8d025d3b8990e45"}, + {file = "pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0feb2e9d6ad6c9e3c06effe9d00f3f1e618a6643273576b016f591e9315a7139"}, + {file = "pillow-12.3.0-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:9e881fca225083806662a5c43d627d215f258ff43c890f831966c7d7ba9c7402"}, + {file = "pillow-12.3.0-cp315-cp315-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:4998562bf62a445225f22e07c896bb04b35b1b1f2eb6d760584c9c51d7a5f78c"}, + {file = "pillow-12.3.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:dc624f6bc473dacdf7ef7eb8678d0d08edf15cd94fad6ae5c7d6cc67a4e4902f"}, + {file = "pillow-12.3.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:71d6097b330eea8fd15097780c8e89cb1a8ce7838669f48c5bacd6f663dd4701"}, + {file = "pillow-12.3.0-cp315-cp315-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:28ce87c5ab450a9dd970b52e5aca5fe63ed432d18a2eaddd1979a00a1ba24ace"}, + {file = "pillow-12.3.0-cp315-cp315-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6b02afb9b97f65fbca5f31db6a2a3ba21aa93030225f150fa3f249717e938fb4"}, + {file = "pillow-12.3.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:1182d52bc2d5e5d7d0949503aa7e36d12f42205dc287e4883f407b1988820d39"}, + {file = "pillow-12.3.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e795b7eb908249c4e43c7c99fac7c2c75dab0c43566e37db472a355f63693d71"}, + {file = "pillow-12.3.0-cp315-cp315-win32.whl", hash = "sha256:57b3d78c95ba9059768b10e28b813002261d3f3dfc55cc48b0c988f625175827"}, + {file = "pillow-12.3.0-cp315-cp315-win_amd64.whl", hash = "sha256:fa4ecea169a355be7a3ade2c783e2ed12f0e40d2c5621cda8b3297faf7fbb9f5"}, + {file = "pillow-12.3.0-cp315-cp315-win_arm64.whl", hash = "sha256:877c3f311ff35410f690861c4409e7ccbf0cd2f878e50628a28e5a0bb689e658"}, + {file = "pillow-12.3.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:e9871b1ffbfa9656b60aeee92ed5136a5742696006fa322b29ea3d8da0ecc9cf"}, + {file = "pillow-12.3.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:53aa02d20d10c3d814d536aa4e5ac9b84ca0ff5a88377963b085ad6822f93e64"}, + {file = "pillow-12.3.0-cp315-cp315t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:446c34dcc4324b084a53b705127dc15717b22c5e140ae0a3c38349d4efec071e"}, + {file = "pillow-12.3.0-cp315-cp315t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf1845d02ad822a369a49f2bb9345b1614744267682e7a03527dc3bf6eea1777"}, + {file = "pillow-12.3.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:186941b6aef820ad110fb01fb06eb925374dc3a21b17e37ec9a53b250c6fe2d1"}, + {file = "pillow-12.3.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:f13c32a3abd6079a66d9526e18dad9b6d280384d49d7c54040cd57b6424041d9"}, + {file = "pillow-12.3.0-cp315-cp315t-win32.whl", hash = "sha256:1657923d2d45afb66526e5b933e5b3052e6bdea196c90d3abb2424e18c77dae8"}, + {file = "pillow-12.3.0-cp315-cp315t-win_amd64.whl", hash = "sha256:8cd2f7bdda092d99c9fc2fb7391354f306d01443d22785d0cbfafa2e2c8bb418"}, + {file = "pillow-12.3.0-cp315-cp315t-win_arm64.whl", hash = "sha256:06ff022112bc9cbf83b60f8e028d94ad87b60621706487e65f673de61610ab59"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b3c777e849237620b022f7f297dd67705f9f5cf1685f09f02e46f93e92725468"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b343699e8308bdc51978310e1c959c584e7869cc8c40780058c87da7781a1e94"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbd139c8447d25dd750ab79ee274cc5e1fe80fc56340ab10b18a195e1b6eca3e"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e7e480451b9fa137494bccd3a7d69adbe8ac65a87d97be61e11f1b1050a5bac3"}, + {file = "pillow-12.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:04f01d28a6aaff387bf842a13be313df23ba0597a44f1a976c9feb3c6ff4711a"}, + {file = "pillow-12.3.0.tar.gz", hash = "sha256:3b8182a766685eaa002637e28b4ec8d6b18819a0c71f579bf0dbaa5830297cce"}, ] [package.extras] @@ -579,7 +522,7 @@ docs = ["furo", "olefile", "sphinx (>=8.2)", "sphinx-autobuild", "sphinx-copybut fpx = ["olefile"] mic = ["olefile"] test-arrow = ["arro3-compute", "arro3-core", "nanoarrow", "pyarrow"] -tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma (>=5)", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "trove-classifiers (>=2024.10.12)"] +tests = ["coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "setuptools", "trove-classifiers (>=2024.10.12)"] xmp = ["defusedxml"] [[package]] @@ -615,14 +558,14 @@ virtualenv = ">=20.10.0" [[package]] name = "python-discovery" -version = "1.4.0" +version = "1.4.3" description = "Python interpreter discovery" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "python_discovery-1.4.0-py3-none-any.whl", hash = "sha256:26ed78d703e234879a66244c7d4114563fb13ec5cd30a2d1357e5fb4850782da"}, - {file = "python_discovery-1.4.0.tar.gz", hash = "sha256:eb8bc7daad3c226c147e45bb4e970a1feb1bf4048ee178e6db59e197b8010ce3"}, + {file = "python_discovery-1.4.3-py3-none-any.whl", hash = "sha256:b6e1e4a7d9e3f6948c39746ffe8218225162d738ba39d05ab1d2f6c1cac4878c"}, + {file = "python_discovery-1.4.3.tar.gz", hash = "sha256:ad57d7045a862460d4a235986c33f13ed707d3aeb9153fa47eb7dfd0d4673289"}, ] [package.dependencies] @@ -748,126 +691,126 @@ files = [ [[package]] name = "regex" -version = "2026.5.9" +version = "2026.6.28" description = "Alternative regular expression module, to replace re." optional = false python-versions = ">=3.10" groups = ["main"] files = [ - {file = "regex-2026.5.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a9e1328e17c84c1a5d22ec9f785ecef4a967fab9a42b6a8dc3bcbebd0a0c9e44"}, - {file = "regex-2026.5.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bfe1ce50cbfb569d74e1e4337da6468961f31dbea55fd85aa5de59c0947a805a"}, - {file = "regex-2026.5.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15ee42209947f4ca045412eae98416317238163618ace2a8e54f99586a466733"}, - {file = "regex-2026.5.9-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4bb445ff3f725f59df8f6014edb547ee928ec7023a774f6a39a3f953038cbb2"}, - {file = "regex-2026.5.9-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:446ddd671e43ab535810c4b21cff7104945c701d4a14d1e6d1cd6f4e445a8bea"}, - {file = "regex-2026.5.9-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7b92817338591505f282cf3864c145244b1edcf5381d237038df955001091538"}, - {file = "regex-2026.5.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6b8a143aca6c39b446ea8092cde25cc8fe9304d4f5fecfbc1a9dbb0282703c2"}, - {file = "regex-2026.5.9-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0f03aa6898aaaac4592479821df16e68e8d0e29e903e65d8f2dfb2f19028a989"}, - {file = "regex-2026.5.9-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ed457d8e98ae812ed7732bef7bf78de78e834eae0372a74e23ca90ef21d910f9"}, - {file = "regex-2026.5.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:71b61c5bfe1c806332defc42ad6c780b3c55f661986d7f40283a3a88274b4c00"}, - {file = "regex-2026.5.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:3b1e39888c5e0c7d92cea4fc777396c4a90363b05de75d02eb459a4752200808"}, - {file = "regex-2026.5.9-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:6ba42b2e7e7f46cf68cc6a5ca36fa07959f9bbd9c6bdcc47b6ee76549a590248"}, - {file = "regex-2026.5.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:c010eb8caca74bdb40c07498d7ece26b4428fd3f04aa8a72c9ac6f79e8faaac6"}, - {file = "regex-2026.5.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a6a563446a41adc451393dc6b8e6ad87979efaee3c8738690a8d1b08ebead1b4"}, - {file = "regex-2026.5.9-cp310-cp310-win32.whl", hash = "sha256:954cc214c04663ee6d266fc61739cad83054683048de65c5bd1d640ad28098ac"}, - {file = "regex-2026.5.9-cp310-cp310-win_amd64.whl", hash = "sha256:b310768746dd314ea6e2ff4cc89ef215426813396ff4e94ee8e6f7096c8b6e03"}, - {file = "regex-2026.5.9-cp310-cp310-win_arm64.whl", hash = "sha256:19c16ceb4a267a8789e25733e583983eeab9f0f8664e66b0bd1c5d21f14c2d4b"}, - {file = "regex-2026.5.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ccf5249114cc3e772ecdd88a98a86eca0fd74c61ce32a94743758c083fc05d48"}, - {file = "regex-2026.5.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46f1326ca6e65b0879d23ca302c0f2415aad42ff0309b9c818e7949fe19a41d8"}, - {file = "regex-2026.5.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef31cbfe458e21c6122ba8150ff060e0c7789ed0d26eb423f25472584920b555"}, - {file = "regex-2026.5.9-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:992604d02e6d9c6d786c24a706a71ecffe1020fc1ef264044474cd81fa2c3919"}, - {file = "regex-2026.5.9-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c9411dd64ca95477225734a93dfc8583b51916b8d5942f99d6cac21e09965451"}, - {file = "regex-2026.5.9-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3dd4a3ff360dfb836fecdb93a4598f9d6e2ac81e3e397125145c6221bf58cf4c"}, - {file = "regex-2026.5.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a661a7d270a61f7cf460caee8b9fa2d5ef9e5c681234bcb9e0fe14f488e7dfc"}, - {file = "regex-2026.5.9-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f079e50a0d3cc3cd5091fa9ff45869a2e6b2cd35895731edafb0327901a8d86d"}, - {file = "regex-2026.5.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4ebe8f0b5ec5a5024dc4a4c59f444c4e9afc5f2abdbb8962065b75d27fb971f9"}, - {file = "regex-2026.5.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:97cf3bc1b7d7d2306772ec07366c80d9df00ff79e79cea32898883a646d2fae2"}, - {file = "regex-2026.5.9-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0f9eede6a5cbdc02d4978090186390936e1776a7d1359b21e41014c609880bcf"}, - {file = "regex-2026.5.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:01f0f5f55f4b64dacec85dc116d3c05fd23ad3ff037bbc73a2085775953c2611"}, - {file = "regex-2026.5.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1268eddd8486dc561d08eee1156e40aa3a8fe10f4bdec8fa653b455fcbffd12c"}, - {file = "regex-2026.5.9-cp311-cp311-win32.whl", hash = "sha256:8676474c07469d6f33dd1085ca2cd45f65785f32518f2b20e36d9953ca07f994"}, - {file = "regex-2026.5.9-cp311-cp311-win_amd64.whl", hash = "sha256:246de9d60aa3f8538b519834dd95cbf276ea263d6a7bd5a3666dc3fa0230505b"}, - {file = "regex-2026.5.9-cp311-cp311-win_arm64.whl", hash = "sha256:d726ca3f0d76969bf1e8e477d160d3d666bbf999f6860bd314889e5345782046"}, - {file = "regex-2026.5.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:57eeeb05db7979413dec5438f2db21d7ecbba787cde7a711df1a6f6df672aa06"}, - {file = "regex-2026.5.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:398c521292f4c7fb807001dcd54694d3a1fcafc179a36ad9cc56f98df85930b6"}, - {file = "regex-2026.5.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f7a7c26137296beba7784de6eba69c6a93a63ccebc385e4962fe67e267a91225"}, - {file = "regex-2026.5.9-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6441cc660d76107934a09c22167200839a0e89604a6297f78a974e66e931d2c0"}, - {file = "regex-2026.5.9-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:91328f1c23d47595ca3ef0a7557fa129c5a23404b775c770697d2f35b33e0107"}, - {file = "regex-2026.5.9-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:93a7860539414dddaefba2b40f8771765ae17949d4c7182b876ce429e11a8309"}, - {file = "regex-2026.5.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd2810d22146b6d838acc5ec15602cb6b47920aa4e33015df3868eedfd20bab8"}, - {file = "regex-2026.5.9-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:daff2bdbaf1d23e52fdff7c0b7bc2048b68f978df6a4d107ac981f94caef2e66"}, - {file = "regex-2026.5.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4eeb011098fcb77af513dcef521a3dbecbf8849b1e38940759d293b7a93f5026"}, - {file = "regex-2026.5.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:ea9c8ecfa1b73c73b626534d6626e5340d429630943672b8480724f44e84b962"}, - {file = "regex-2026.5.9-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:cd2846168eb9ee3c513902bc8225409cb1caab31d04728b145171fa1625d9621"}, - {file = "regex-2026.5.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:39617fb0cde9c0e6306dc70e3bfc096f3da793219879f7ae7aa341a69fbdcf6d"}, - {file = "regex-2026.5.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fd03c4f0e33280d15cae17159b899245d6b7c53d21def19b263b39655061f5ce"}, - {file = "regex-2026.5.9-cp312-cp312-win32.whl", hash = "sha256:164eba9b755ea6f244b0d881196fbc1fac09714e9782c9e2732b813142033c8e"}, - {file = "regex-2026.5.9-cp312-cp312-win_amd64.whl", hash = "sha256:86f40a5d6444db30a125c9c9177e6b25dad981cbc37451fd838f145e6edac92e"}, - {file = "regex-2026.5.9-cp312-cp312-win_arm64.whl", hash = "sha256:96f5f58b54a063d7ea9dca08e1cf57bfe10499c4d579ee672da284f57f5f0070"}, - {file = "regex-2026.5.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d626b84406444b165fc0ba981604edea39f0588ff1f92baa23fe50799ea9afdb"}, - {file = "regex-2026.5.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d7bdc0ab8f3dd7e1b4f9ab88634e13374669db86bb3c72e8292f07ae313f539f"}, - {file = "regex-2026.5.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a8820737949116ffff55fe18f9fc644530063ba6ebfcb8314239416e78f1347c"}, - {file = "regex-2026.5.9-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0fbdbac82cb3e4450d0ccde7d7a35607f4cb2dd9fba4b8b69bfaf8c9fa6aed"}, - {file = "regex-2026.5.9-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:57e8915c7986aa33d25e4d3629cef711cd2863f2961b10409f0c04cb8b7d9020"}, - {file = "regex-2026.5.9-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:508f56a89ba9cb26e4168cbc37dbd60a28d82430a9e18ad1d25fe0883c314ca2"}, - {file = "regex-2026.5.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b6d189041f15691cfa2b6c4290448ec221244d225b3f5fe9e7771b34ffcdf6e2"}, - {file = "regex-2026.5.9-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e82db382b44d0111b22601c509c89f64434816c9e0eef9d1989cda8cc6ff1c04"}, - {file = "regex-2026.5.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2acfb48634f64996b57f90f39afa692ff362162722581921fe92239a59960f3c"}, - {file = "regex-2026.5.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d29eebfc9525db68cad3c97eedd7f754fa265aa5cd0cf4f863b2421e1b48fc9f"}, - {file = "regex-2026.5.9-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:debb893095e944091c16e641a6e33c1b0f4cb61ab945ec5afbf53ce7068834d8"}, - {file = "regex-2026.5.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d659eee77986549c9ea45b861c7567e44d6287c3dc9a4565478853f7b9fe2ff6"}, - {file = "regex-2026.5.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2efa205e6d98b24d1f3ab395c11aa15cdf10935bca283d0285e0499c284fba21"}, - {file = "regex-2026.5.9-cp313-cp313-win32.whl", hash = "sha256:f3844f134e834076677dd369976e9f5068679fcb8e50102fdf6b7ac96a3ec127"}, - {file = "regex-2026.5.9-cp313-cp313-win_amd64.whl", hash = "sha256:3527bb4942d2c14552155406cdedd906567456821848aed1cb4933a391bf5eca"}, - {file = "regex-2026.5.9-cp313-cp313-win_arm64.whl", hash = "sha256:56a33f191f17d8c417f99945ebdc1e691d3af9605d86ec68c7e54a57e3e17af6"}, - {file = "regex-2026.5.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:01f28d868834624c934b8d2e0aa1c8341337e37831f4a012f18a5afcba4cbaf3"}, - {file = "regex-2026.5.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:48036f6374aaa79eb3b754ec29c61d1c6b1606749d705a13f8854fa2539671f6"}, - {file = "regex-2026.5.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b96350aa424e79d4fd6b567b344dcbe2b2d6bfc48dfe7717587e1fa6d43da6ff"}, - {file = "regex-2026.5.9-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f3af7a4903c5c04a11a196a5aa75cdd7dd3f8508132f9fb3259d9f5908e3b88"}, - {file = "regex-2026.5.9-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7e87577720152d2caae19fe2baaf1f8d5ca12091e9e229f03915c37d1e4b9178"}, - {file = "regex-2026.5.9-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c8b9b9d294cfea3cd19c718ade7cc93492b2c4991abd9a68d0b3477ae6d8e100"}, - {file = "regex-2026.5.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:728d8bfd28a8845c8b6bc5dc7ce010453d206396786c0765c2740cb65f37791e"}, - {file = "regex-2026.5.9-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7e30b874d341fac767d7df5a0870540541c2c054b80cfaac116e8d367a8a7ff2"}, - {file = "regex-2026.5.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:fd190e88a895a8901325fad284a3f74ea52b1da8525b76cc811fa9b1edf0ce2b"}, - {file = "regex-2026.5.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:8e76e8161ad00694cfce6767d5dea860c6391ac5b83e5c3a39661e696f11fc7e"}, - {file = "regex-2026.5.9-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:ddda5340e6c01a293027dd46232fa79eaff1b48058ce7a98f572b6445b088041"}, - {file = "regex-2026.5.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:205109e96b3cf5adf8f4cd62bedde9487feb282b9497a3535451e5a24cd706a0"}, - {file = "regex-2026.5.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dfbe4579b9f08036aa7d101d1835437a20783574ac66327e6b29b4018a138081"}, - {file = "regex-2026.5.9-cp313-cp313t-win32.whl", hash = "sha256:ed2c9e8068b614c574d8d30e543d617cf5379b0535d46f97ef00e904745a08b5"}, - {file = "regex-2026.5.9-cp313-cp313t-win_amd64.whl", hash = "sha256:b46b0f094dc1d3b90356c85a0bd2c9bafc4a6a190b9d6f8ddd5a033b6e088ed4"}, - {file = "regex-2026.5.9-cp313-cp313t-win_arm64.whl", hash = "sha256:872acc074bd29ffc9913ecdfedf6ea77502312ca44a4aa0d3779089c6069d8de"}, - {file = "regex-2026.5.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:1bd7587a2948b4085195d5a3374eaf4a425dc3e55784c038175355ecf3bbbf8a"}, - {file = "regex-2026.5.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:dea2e88e1cce4522496cce630e11e67b98b7076620bc4336c3f674bc21a375f4"}, - {file = "regex-2026.5.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2099f7e7ff7b6aa3192312650a56e91cc091e49d50b04e4f6f8b6e28b3b27f1c"}, - {file = "regex-2026.5.9-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecd353045824e4477562a2ac718c25799cdaaa41f7aa925a806a8a3e6848a5b9"}, - {file = "regex-2026.5.9-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:65c8c8c37377794bd5b2f3ebe51919042bf17aec802e23c833d89782ed0c78af"}, - {file = "regex-2026.5.9-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b73ab8afcf66c622db143d1c6fda4e58e4d537ee4f125229ad47b1ab80f34c0"}, - {file = "regex-2026.5.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0de5cf193997384ed2ca6f1cd4f78055b255d93d82d5a8cd6ba0d11c10b167e4"}, - {file = "regex-2026.5.9-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d641a8c9a61618047796d572a39a79b26167b0411d2c3031937b2fe2d081e2cf"}, - {file = "regex-2026.5.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:24b2355ef5cc9aa5b8f07d17704face1c166fdcc2290fa7bd6e6c925655a8346"}, - {file = "regex-2026.5.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:a24852d3c29ad9e47593593d8a247c44ccc3d0548ef12c822d6ed0810affe676"}, - {file = "regex-2026.5.9-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:916714069da19329ef7de197dcbc77bb3104145c7c2c864dbfbe318f46b88b14"}, - {file = "regex-2026.5.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:fa411799ca8da32a8d38d020a88faa5b6f91657d284761352940ecf9f7c3bbdd"}, - {file = "regex-2026.5.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1e6da47d679b7010ef27556b6e0f99771b744936db1792a10ceac6547ae1503e"}, - {file = "regex-2026.5.9-cp314-cp314-win32.whl", hash = "sha256:98bd73080e8756255137e1bd3f3f00295bbc5aa383c0e0f973920e9134d7c4ad"}, - {file = "regex-2026.5.9-cp314-cp314-win_amd64.whl", hash = "sha256:ff8d372ac2acdc048d1c19916f27ee61bc5722728458ba6ca5052f2c72d51763"}, - {file = "regex-2026.5.9-cp314-cp314-win_arm64.whl", hash = "sha256:e1d93bf647916292e8edcec150c07ddf3dc50179ccaf770c04a7f9e452155372"}, - {file = "regex-2026.5.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:83d0ee4a57d1c87cb549e195ec300b8f0ec3a82eba66d835e4e2ed8634fe4499"}, - {file = "regex-2026.5.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d3d7eb5c9a7f6df82ed3cfac9beb93882a5cbcb5b8b157b56cb2b3b276574ac1"}, - {file = "regex-2026.5.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:075160bf16658e16d35233300b8453aac25de4cbea808d22348b6979668e924d"}, - {file = "regex-2026.5.9-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:45375819235558a4ff1c4971dc32881f022613abdb180128f5cb4768c1765a1c"}, - {file = "regex-2026.5.9-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ead4b163ac30a29574510cd4b3e2e985ac5290c05fc7095557d6a5f403fc31b5"}, - {file = "regex-2026.5.9-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c6e4218fbdfbcd4f6c19efca40930d24a621bf4b48cb76bc6640543bd28ef20"}, - {file = "regex-2026.5.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6351571c8a42b505eb555c0dc47d740d0fb66977dc142919eea6f4325b7c56a0"}, - {file = "regex-2026.5.9-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:002205cafd2a9e78c6290c7d1df277bf3277b3b7a30e0b4bb0dac2e2e3f7cb2d"}, - {file = "regex-2026.5.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8abd33fef90b2a9efac5557d6033ca82d1195ed3a15fea5af15ba7b463c6a63b"}, - {file = "regex-2026.5.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:31037c82eccb44b7ea2e9e221d7c01429430e989a1f4b91ea5a855f6017b509a"}, - {file = "regex-2026.5.9-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:5604dfd046dc37eca90250fc3be938b076c8059fa772ac0ed6f499b0f0fb0415"}, - {file = "regex-2026.5.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:0e1b1b4e496afbb24f4a62aba855ee4f88f25578927697b340702e48c9ee6bc2"}, - {file = "regex-2026.5.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:be3372b9df6ddecff6486d37e19095a7b4973137caf5512407a89f4455361f41"}, - {file = "regex-2026.5.9-cp314-cp314t-win32.whl", hash = "sha256:3ddd90103f9e5c471c49c7852ecc1fe27c7e45eb99e977aefe7caa4e779f4f58"}, - {file = "regex-2026.5.9-cp314-cp314t-win_amd64.whl", hash = "sha256:ca518ed29c46eecba6010b15f1b9a479314d2de409536e71b6a13aa04e3b8a77"}, - {file = "regex-2026.5.9-cp314-cp314t-win_arm64.whl", hash = "sha256:5e41809d2683fcde7d5a8c87a6567ba1fb1ce0de9f31bff578de00a4b2d76daa"}, - {file = "regex-2026.5.9.tar.gz", hash = "sha256:a8234aa23ec39894bfe4a3f1b85616a7032481964a13ac6fc9f10de4f6fca270"}, + {file = "regex-2026.6.28-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b83932645630965fd860fdb70ebbf964bf3e8007f08851ea424d01f8d35454a8"}, + {file = "regex-2026.6.28-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e81f1952355042e517dc9861ce65c676e4a098f42402993c40461786d1f794d4"}, + {file = "regex-2026.6.28-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2097591101d70bcc108af64c46f6066bb698ee067fec5f75beac0be317639311"}, + {file = "regex-2026.6.28-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:31d7538a614b5842bf53ce329d07b43f97754ca7e6db8d69f347e071bce1c953"}, + {file = "regex-2026.6.28-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f5561e47bbe2b75373b695326507743fcdd4d2cc7f5022312024ccf39fa094e0"}, + {file = "regex-2026.6.28-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c10f2c5a55ab3dd8318d8ad5f11b530e2691c0edebebde7713066f484902c3fb"}, + {file = "regex-2026.6.28-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:23f7e0cc60c72486b42a685f1ff4eec90d50d4fb05e4f9c7d5363b03aa02600d"}, + {file = "regex-2026.6.28-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:76493755f79a88d5ed2c9e63a41d3c05997e0a7ffbe76ed8c4ded8be35b8b14c"}, + {file = "regex-2026.6.28-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ff0f41a00f23ea5054acb61901380c41813d813eee3f80f800995710bcc52ecd"}, + {file = "regex-2026.6.28-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3c60b297292e7e1ef5d02a4759f9e452ee4c8bb95e168d8fd0b5db01bd806f9f"}, + {file = "regex-2026.6.28-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a7cf03c87f7b9cbc25a8894cf9be83818406677b6b391b003ec7c884923387b5"}, + {file = "regex-2026.6.28-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:418208ea0af51cfed4f46eb9b1ea7cfc990ca284f0084ecbd951460fb089421e"}, + {file = "regex-2026.6.28-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:7635fa2cddb917a6bbfac7890602573d2d8c4e470703b0640e6f86a988817ec3"}, + {file = "regex-2026.6.28-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7bb96c13d6cf5880d31bbef84ca701a64d738aa491c2b79975cc33f8ad00a31e"}, + {file = "regex-2026.6.28-cp310-cp310-win32.whl", hash = "sha256:56f05194c4843957dd8b3af87eb0c52d8cf0509e7f18e172d727f5f8ff840646"}, + {file = "regex-2026.6.28-cp310-cp310-win_amd64.whl", hash = "sha256:70710927033af3b54369f17aaba1343b97a23d0b1aa994fa1512b08b1b8c136a"}, + {file = "regex-2026.6.28-cp310-cp310-win_arm64.whl", hash = "sha256:ed7b30185ee3f8b9b053b0be567b4d226016e2afbebc17fde1c6a4580937b688"}, + {file = "regex-2026.6.28-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a71b51dd08b9b62f055fafab3dee8af8bd2ec81b373a44caef18d6c5ca28f43a"}, + {file = "regex-2026.6.28-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9c26a47770d30a0f85c01e261d2a3ebc342c4af6fd666dbd8c1fe4cbf3adf726"}, + {file = "regex-2026.6.28-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e5efbc1af38f97e300d43028e5a92e752d924bcfb7f465d8669d5d5a6e78c233"}, + {file = "regex-2026.6.28-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f1758df6fdd8c800620a5638958720e8a635e1da49a2f09df2dd63e94a24ec4a"}, + {file = "regex-2026.6.28-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ad73ecf20c1ef5c975639f8bf845a9370fcf7dada7edc1e3b0bca20e2f8202f6"}, + {file = "regex-2026.6.28-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4d80c798b0eec6ea3d45f8816a1e8886c5664615d347d89e8c075b576a1b5a5d"}, + {file = "regex-2026.6.28-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a361feeaf1b6ba1df060f2ff5c5947092edf537a35ce78e76387ac56d3e0f4a4"}, + {file = "regex-2026.6.28-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8b92366d9c8bba9642989534073662abdd9b41faf7603a7ae71597833f3b88f0"}, + {file = "regex-2026.6.28-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:11251768cc23f097dd61b18f67966e70f74da822784d17e12a444eb6b29d4288"}, + {file = "regex-2026.6.28-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ad5c67786145ec28a71a267d9f9d92bdc8d70d65541eea852c253f520a01f918"}, + {file = "regex-2026.6.28-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:f1da438e739765c3e85175ede05816cbede3caaacb1e0680568bda6119bfdfca"}, + {file = "regex-2026.6.28-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d98b639046e51c5de64d9f77351532105e99ca271cb6f7640e1f903d6ab63032"}, + {file = "regex-2026.6.28-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e164ace4dbab5c6ad4a4ac7c41a2638fe226d0c770a86f2eb041f594bac6ee7"}, + {file = "regex-2026.6.28-cp311-cp311-win32.whl", hash = "sha256:3169a3159e4d99d9ae85ff0ed90ef3b8906cc3152653b6078b842ace6c8f72c3"}, + {file = "regex-2026.6.28-cp311-cp311-win_amd64.whl", hash = "sha256:5977295b0a74e8241df8a4b3b27b12412a831f6fa32ee8b755039592cd768c3d"}, + {file = "regex-2026.6.28-cp311-cp311-win_arm64.whl", hash = "sha256:f5fbaef40c3e9282ccee4b075f5600a0d858aa0c34147732f1baa69c8188a95d"}, + {file = "regex-2026.6.28-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:81cc5793ad33a10444445e8d29d3c73e752c8fb2e120772d70fcb6d41df40fe1"}, + {file = "regex-2026.6.28-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e18225243250a1f7d7e5e5d883f3b96465cd79031acf5c6db902b7025f2125d9"}, + {file = "regex-2026.6.28-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ecd1638b1c2db1f2d01c182a4b0d3e2e88b0e99910320a745c1727ee3638ddab"}, + {file = "regex-2026.6.28-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4303ebe16b74eeb3fe2715745023266fea92fd44a23f3e7bb2fb48c7a7bbc195"}, + {file = "regex-2026.6.28-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56b856b70b96c381d837f609eee442a1bd320cd2159f5c294b679552fb1a7eaf"}, + {file = "regex-2026.6.28-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f74675ab76ab1d005ffba4dee308e53e89efc22be6e9f9fae5b539a3f81bdff2"}, + {file = "regex-2026.6.28-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90581684565a93f7258af1e5d3f41ef20d7d7c61f2a428183a342bcb65485e38"}, + {file = "regex-2026.6.28-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:28f9e6c28f9b90f6f784595a33240a57e181e61b6ee3dc259b25c61e356d1aa3"}, + {file = "regex-2026.6.28-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:378a71d861fc7c8806b04ac5b133d53c0e774f92f5d9663a539872d3fa2b0417"}, + {file = "regex-2026.6.28-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4cc199874ecd6267a49b111052250825bfe19b5101b23b2ba80f54efa3e0994e"}, + {file = "regex-2026.6.28-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:b916a10431494ef4b4d62c6c89cab6426af7873125b8cd6c15811bf5fc58eec8"}, + {file = "regex-2026.6.28-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2e27727fba075f1e4409416d2f537d4c30fc11f012ea507f7bd74d3e19ecb57a"}, + {file = "regex-2026.6.28-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:700fc6a7844bb2c4149292ac79d1df8841a00acd4d45cd32c1ebc7bcc1fd0da8"}, + {file = "regex-2026.6.28-cp312-cp312-win32.whl", hash = "sha256:03376d60b6a11aecb88a79fa2be06b40faa01c6693bc31ef69435cd4818b9463"}, + {file = "regex-2026.6.28-cp312-cp312-win_amd64.whl", hash = "sha256:fbd2ded482bf99e6651992bbfcde460272724d4bbc49ef3d6b46d9312867ec84"}, + {file = "regex-2026.6.28-cp312-cp312-win_arm64.whl", hash = "sha256:37294d3d7ddb64c7e89184b2894e0f8f0a19c514bc59513d71fe692c3a8d5fc6"}, + {file = "regex-2026.6.28-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:b295a83426e0e44e9e60fde99789e181bd26788a1890ae7fe2a24c69bb6246ca"}, + {file = "regex-2026.6.28-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0c31665c0deb5c111557a1cac8c27bd5629e2f9e7fd5058900a03576c33b601c"}, + {file = "regex-2026.6.28-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6bf295f2c59de77d1ea7de053607ae4dc9ceb3d57bbb6c7ec51ef4acc4ccff94"}, + {file = "regex-2026.6.28-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17c077586770f67e05bbffeba07fbee6b2b22244f4d4caf8d94e59d574befe04"}, + {file = "regex-2026.6.28-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0e6cb5a61486f9062397d2e189573b39d38ecfaed698fd9fb6e2756a8ebb8762"}, + {file = "regex-2026.6.28-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e86e91a2664f44c3a4e363a7d78fb17c27d5046882e30ea5a877f5e89b28d2ba"}, + {file = "regex-2026.6.28-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4dfd1331c49233998d84fc5f1f4436cf7a435a7655f6cf0f490229bb5c7254e5"}, + {file = "regex-2026.6.28-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cadea12805a1bce0b091c302b814207be26fb60a9c0e7f9ad2f9e21790a429fe"}, + {file = "regex-2026.6.28-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5f2c1682b67ad5d2376498f2a5a2a8f782fa2e4a06d0465b5e357799806e8a20"}, + {file = "regex-2026.6.28-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:64e142eb55e84868087da1375d7c36ff97d55010951849f515322a91d5fef1b4"}, + {file = "regex-2026.6.28-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:abb4daabe7be63273787a62dfd6164dadf8f7a63fbec3d2730e5e5e7126d858c"}, + {file = "regex-2026.6.28-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:ec2b2ad00ab8c16a2798cc8db80c53c4d5b8b3a2441f6cbaef06625f5ca25854"}, + {file = "regex-2026.6.28-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bfc9677982c914d9085b8e1c3b3ae6e88f139fb56531c2416d6c8f338093c22b"}, + {file = "regex-2026.6.28-cp313-cp313-win32.whl", hash = "sha256:bf54bc693fc4e0530e666ba5ec4bcba14dbe8f66b7cfc15c27317d1a6e40b9a5"}, + {file = "regex-2026.6.28-cp313-cp313-win_amd64.whl", hash = "sha256:e128feaf65bf3d9eb91bec92322a8f7e4835e9c798f3e9ea4b69f4def85620e3"}, + {file = "regex-2026.6.28-cp313-cp313-win_arm64.whl", hash = "sha256:695873e0ea8d3815ea9e92e2c68faf039cc450e2c0a62a31afe2049eb11be767"}, + {file = "regex-2026.6.28-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:189dbf9fc4252d9f1352bf4bd1bef885edb6cc4b7341df202a65f821aaa3891c"}, + {file = "regex-2026.6.28-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9277a4c6503390aa39cb4483b87ec0384faee0850a23b5cea33d008b5d8d83f1"}, + {file = "regex-2026.6.28-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:17eddca4e8ea9af0b5739314776cdf0172a49731ab61f2e1ea66e066ddd46c97"}, + {file = "regex-2026.6.28-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4466b8641e00c697aab5a73150150d2b2ea96b131c595691f42031abafd9f4d"}, + {file = "regex-2026.6.28-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9cfcd4b0bdcf768c498415c170d1ed2a25a99bf0b65fa253bbd02f68ceba6475"}, + {file = "regex-2026.6.28-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:80c7adf1ef647f6b1e8aa2ca280e517174cd08bdf7a2e412cdfb68bd6a0917cb"}, + {file = "regex-2026.6.28-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a043f5770e82283a22aed4cefef1a4e0f9dd8fd7184cb6ce0ad2e579e2134a9e"}, + {file = "regex-2026.6.28-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3bd630a8dba06b55254ea5ee862194edab52ec783100d2ef1cd15a9c512fee27"}, + {file = "regex-2026.6.28-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b77207e3cee13086f1906a6a2a12b41244c577e8ad9370d4b35ae1d548d354f3"}, + {file = "regex-2026.6.28-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:6de82c268e5d101ee9e3ffd869924aa9a371e3a21e752cf4fa17b6ce50d219f7"}, + {file = "regex-2026.6.28-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:b15859e3908544fb99cf47341dcf0bfd089147d258c4c4d8a29e5b087f8085cb"}, + {file = "regex-2026.6.28-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:c91487a917edd48a1ea646fdf60d7936d304f0e686fa7ea8326e47efca51d816"}, + {file = "regex-2026.6.28-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4ac65f3e3a99fd8f3a4a74e7a6610acd1ce9dfe9b8a03d346a4922380d68aeb"}, + {file = "regex-2026.6.28-cp313-cp313t-win32.whl", hash = "sha256:3f6316f258bc7e6c9c2acbe9954947bbd397a81be3742a637a555f1855d6618d"}, + {file = "regex-2026.6.28-cp313-cp313t-win_amd64.whl", hash = "sha256:1484bdd6fba28422df9b5ebb04055b2e1b680e8e4f08490bb21ff0f3cc50d0ab"}, + {file = "regex-2026.6.28-cp313-cp313t-win_arm64.whl", hash = "sha256:3f15020f0b69cafe57baa067ff65b29acef68ff6b1670a53bef1ca11d708e02d"}, + {file = "regex-2026.6.28-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:f7c032b0c8a73739ff8ff1aaf30c281fa19c17bf7f1543256c8507390db7807c"}, + {file = "regex-2026.6.28-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:f6710f512c57b84f127a23d0f59560a03b64136eff419ae1be5ab557577fe5e3"}, + {file = "regex-2026.6.28-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c0013958f427bd82509a186b9ff206d66cb8d60a81fc797a4c717afd18c5b0ba"}, + {file = "regex-2026.6.28-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94f06cdcd6421f8e194ad312ea608020381250df9b8a57661c1b57e9e5273878"}, + {file = "regex-2026.6.28-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ec9689392f7494ff4e3f8e7e8522f9158f11023f337eaaf04a64542fc45bbf26"}, + {file = "regex-2026.6.28-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:aa084684e6d2078bf6139e374d1fc2af5ddc1ac7122759a2db716d68169f6fd0"}, + {file = "regex-2026.6.28-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:40455e6840dc4e96a6fe50f4cedc957de2752c954d91e789812be55d49be199a"}, + {file = "regex-2026.6.28-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:530b5c223b9ca5dd8370ac502e080aee0e4ded32be987c6564b425fb5523d581"}, + {file = "regex-2026.6.28-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8e0ed273ecd1a89be84466c1749bfe58609cc2a32b5d5e05006c4625ba96411b"}, + {file = "regex-2026.6.28-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:0ab0d5344311fc8e8667078942056c3b9c9b4a4b1cc99f2eb8a5af54554f4acc"}, + {file = "regex-2026.6.28-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:eacb79625323d9f7e7925366b917f492b8356fad58f5dc4fa12ff8c21d8f4ca9"}, + {file = "regex-2026.6.28-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:20f4d87702702aa1d572721e146f301660c50eef6fd6cb596e48a22b0ace17db"}, + {file = "regex-2026.6.28-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1e693940a3b9e6d6e4dc2a54ecaa74b74934f77af1ef95f518a74261ef7cc1bc"}, + {file = "regex-2026.6.28-cp314-cp314-win32.whl", hash = "sha256:234a51e20ebc18ab83b2c0600cf28f2e884560a0e00f743878f0b7d8e7c4cf03"}, + {file = "regex-2026.6.28-cp314-cp314-win_amd64.whl", hash = "sha256:7b15c437bc4604f03ceb3f8d37eae2f8930e320e1bc556b259848c639d9eec1a"}, + {file = "regex-2026.6.28-cp314-cp314-win_arm64.whl", hash = "sha256:c6e6f790d01380a74ad564f216c533b86504afb61bf66f2b2e11e7f1a3e287a7"}, + {file = "regex-2026.6.28-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:3527a72adcbe9e3600f1553b497d397c1a371d227580d41d96c3c5964109b65c"}, + {file = "regex-2026.6.28-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:a644f6408692812f5ead82519eed680e08d5d546fddbd9f7d9514e3c73899aa5"}, + {file = "regex-2026.6.28-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:8e2fae6bb883648346f84db270dc9aafc29d8e895f62b88a75ccc83b09519820"}, + {file = "regex-2026.6.28-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:debe623e09cee97ef9404575e936c610aac9bb08358c5099aaef14644a6871f2"}, + {file = "regex-2026.6.28-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cc579c91fb4605773483a8d940b136bcc5b854fff44fa14a1572a038f46563f1"}, + {file = "regex-2026.6.28-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e7c42be203d84ecf7d487ff23f8a61ef0eb0534fa0fc317a2fce8c065d20618f"}, + {file = "regex-2026.6.28-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8184b4e2fdaf9cdfe77e38f15a4d9dc149168c9c29eb0ea17c5481d3bb80546"}, + {file = "regex-2026.6.28-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:697f103104f5872d64078d8eeac59979960be8ee76115a2d3f31096312e2a400"}, + {file = "regex-2026.6.28-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:714d2b1aa29beef0ddfcdc72ad0771c05326551a8bb0680b0ddf74bfaad87387"}, + {file = "regex-2026.6.28-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0f09f62e450cc2f113018cc8412aeea3a120a04e1ca7e801a0d441583f9a3b06"}, + {file = "regex-2026.6.28-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:731ea12d5aeb2577eaef2393d6428b995f76eb35f68a89e03e15a97719d1de19"}, + {file = "regex-2026.6.28-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:51e952c8783eabd4706d0f63922f219bcfc1bef9b8cb35941c0d1a0396578858"}, + {file = "regex-2026.6.28-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:43248fe4c0ab8fbb223588a0795b11268940072c97bba30ea8f9b49d8cdfde34"}, + {file = "regex-2026.6.28-cp314-cp314t-win32.whl", hash = "sha256:fc1eddc25ad23c0f1344ab280d961ac595ead48292d7c779497975942373f493"}, + {file = "regex-2026.6.28-cp314-cp314t-win_amd64.whl", hash = "sha256:ede8d8e53b6dde0a50f7eca902f0af76d87ab02a55aba7542da68ae3e5dfe83d"}, + {file = "regex-2026.6.28-cp314-cp314t-win_arm64.whl", hash = "sha256:4da6f6a72f8700b97a1a765e837fb7d5750bfd9f13acea7bae498f573e3a70a8"}, + {file = "regex-2026.6.28.tar.gz", hash = "sha256:3cb4b6c5cb3060cc31efdc1fbb27c25fb9b29044afd87e40601a1c4d9db54342"}, ] [[package]] @@ -940,38 +883,15 @@ files = [ ] [[package]] -name = "sgmllib3k" -version = "1.0.0" -description = "Py3k port of sgmllib." -optional = false -python-versions = "*" -groups = ["main"] -files = [ - {file = "sgmllib3k-1.0.0.tar.gz", hash = "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9"}, -] - -[[package]] -name = "soupsieve" -version = "2.8.4" -description = "A modern CSS selector implementation for Beautiful Soup." +name = "tzdata" +version = "2024.2" +description = "Provider of IANA time zone data" optional = false -python-versions = ">=3.9" +python-versions = ">=2" groups = ["main"] files = [ - {file = "soupsieve-2.8.4-py3-none-any.whl", hash = "sha256:e7e6b0769c8f51ed59acab6e994b00621096cfb1c640a7509295987388fbaf65"}, - {file = "soupsieve-2.8.4.tar.gz", hash = "sha256:e121fd02e975c695e4e9e8774a5ee35d74714b59307868dcc5319ad2d9e3328e"}, -] - -[[package]] -name = "typing-extensions" -version = "4.15.0" -description = "Backported and Experimental Type Hints for Python 3.9+" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, - {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, + {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, + {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, ] [[package]] @@ -1006,21 +926,21 @@ zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] [[package]] name = "virtualenv" -version = "21.4.2" +version = "21.5.1" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "virtualenv-21.4.2-py3-none-any.whl", hash = "sha256:854210ca524a1a4d0d744734f4acbc721c3ffe163b85bbf5d56d14d5ae2f0fae"}, - {file = "virtualenv-21.4.2.tar.gz", hash = "sha256:38e6ee0a555615c0ea9da2ac7e9998fe8dc3b911dd33ad8eaad2020957653b0c"}, + {file = "virtualenv-21.5.1-py3-none-any.whl", hash = "sha256:55aa670b67bbfb991b03fda39bd3276d92c419d702376e98c5df1c9989a26783"}, + {file = "virtualenv-21.5.1.tar.gz", hash = "sha256:dca3bf98275a59c652b69d68e73433e597d977c2da9198882479d1a7188009c8"}, ] [package.dependencies] distlib = ">=0.3.7,<1" filelock = {version = ">=3.24.2,<4", markers = "python_version >= \"3.10\""} platformdirs = ">=3.9.1,<5" -python-discovery = ">=1.4" +python-discovery = ">=1.4.2" [[package]] name = "win32-setctime" @@ -1153,4 +1073,4 @@ cffi = ["cffi (>=1.17,<2.0) ; platform_python_implementation != \"PyPy\" and pyt [metadata] lock-version = "2.1" python-versions = ">=3.11,<3.15" -content-hash = "9fa7378a8df2620a9ee54a7b989622a809fabff10605969a57e54021d73d671c" +content-hash = "98215fe1e749b03338f96fc7994319c71b530765c4d0711672f2e83c25f163db" diff --git a/pyproject.toml b/pyproject.toml index 626c6a7c..4db01ef2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,9 +14,8 @@ mwclient="^0.11.0" keyvalues3="^0.1" python-mermaid="^0.1.3" python-dotenv = "^1.0.1" -feedparser = "^6.0.11" requests = "^2.32.3" -bs4 = "^0.0.2" +tzdata = "^2024.2" loguru = "^0.7.2" zstandard = "^0.25.0" pillow = "^12.2.0" diff --git a/src/changelogs/constants.py b/src/changelogs/constants.py index 57c1a2ae..82fc30b7 100644 --- a/src/changelogs/constants.py +++ b/src/changelogs/constants.py @@ -1 +1,5 @@ -CHANGELOG_RSS_URL = 'https://forums.playdeadlock.com/forums/changelog.10/index.rss' +STEAM_APP_ID = '1422450' +STEAM_NEWS_API_URL = ( + f'https://api.steampowered.com/ISteamNews/GetNewsForApp/v2/?appid={STEAM_APP_ID}&count=50&maxlength=0&feeds=steam_community_announcements' +) +STEAM_MIGRATION_DATE = '2026-06-04' diff --git a/src/changelogs/fetch_changelogs.py b/src/changelogs/fetch_changelogs.py index 0899c1c7..942c847b 100644 --- a/src/changelogs/fetch_changelogs.py +++ b/src/changelogs/fetch_changelogs.py @@ -1,14 +1,10 @@ import os -from os import listdir -from os.path import isfile, join from loguru import logger -import feedparser -from bs4 import BeautifulSoup -from urllib import request -from urllib.parse import urlparse +import requests +import hashlib from utils import file_utils, json_utils -from typing import TypedDict -from .constants import CHANGELOG_RSS_URL +from typing import TypedDict, NotRequired +from .constants import STEAM_APP_ID, STEAM_NEWS_API_URL, STEAM_MIGRATION_DATE from collections import defaultdict from datetime import datetime from zoneinfo import ZoneInfo @@ -19,20 +15,26 @@ class ChangelogConfig(TypedDict): """ Each record in changelog_configs.json - Key is "changelog_id", default to forum_id, differs for herolab changelogs + Key is "changelog_id", default to source_id, differs for herolab changelogs """ - forum_id: str + source_id: str # Now stores the Steam GID date: str link: str + is_hero_lab: bool + title: NotRequired[str] + steam_hash: NotRequired[str] + was_edited: NotRequired[bool] class ForumUpdate(TypedDict): - """Represents a single update entry fetched from the forum""" + """Represents a single update entry fetched from the Steam API""" version: str text: str link: str + title: NotRequired[str] + steam_hash: NotRequired[str] class Hotfix(TypedDict): @@ -50,10 +52,10 @@ class ChangelogString(TypedDict): class ChangelogFetcher: """ - Fetches changelogs from the deadlock forums and game files and parses them into a dictionary + Fetches changelogs from Steam Web API and game files and parses them into a dictionary """ - def __init__(self, update_existing, input_dir, output_dir, herolab_patch_notes_path): + def __init__(self, update_existing, input_dir, output_dir): self.changelogs: dict[str, ChangelogString] = {} self.changelog_configs: dict[str, ChangelogConfig] = {} self.hotfixes: list[Hotfix] = [] @@ -62,13 +64,8 @@ def __init__(self, update_existing, input_dir, output_dir, herolab_patch_notes_p self.INPUT_DIR = input_dir self.OUTPUT_DIR = output_dir - self.RSS_URL = CHANGELOG_RSS_URL - - # Safely derive base url (e.g., https://forums.playdeadlock.com) - parsed_url = urlparse(self.RSS_URL) - self.FORUM_BASE_URL = f'{parsed_url.scheme}://{parsed_url.netloc}' - - self.HEROLABS_PATCH_NOTES_PATH = herolab_patch_notes_path + self.STEAM_NEWS_URL = STEAM_NEWS_API_URL + self.APP_ID = STEAM_APP_ID self.TAGS_TO_REMOVE = ['', '', '', '', ''] @@ -153,23 +150,48 @@ def _get_patch_section(self, header: str, full_text: str) -> str: match = pattern.search(full_text) return match.group(0).strip() if match else '' + def _bbcode_to_text(self, bbcode: str) -> str: + """Converts Steam BBCode to plain text matching existing parser expectations.""" + text = bbcode.replace('\\[', '[').replace('\\]', ']') + text = text.replace('[p]', '').replace('[/p]', '\n') + + # Handle lists explicitly before the catch-all + text = re.sub(r'\[/?list\]', '', text) + text = re.sub(r'\[\*\]', '- ', text) + + # Remove bold/italic/underline tags + text = re.sub(r'\[/?b\]', '', text) + text = re.sub(r'\[/?i\]', '', text) + text = re.sub(r'\[/?u\]', '', text) + + # Handle links: [url=...]text[/url] -> text + text = re.sub(r'\[url=[^\]]*\](.*?)\[/url\]', r'\1', text) + text = re.sub(r'\[/?url\]', '', text) + + # Handle images, steam items, youtube + text = re.sub(r'\[img[^\]]*\].*?\[/img\]', '', text) + text = re.sub(r'\[steamitem[^\]]*\].*?\[/steamitem\]', '', text) + text = re.sub(r'\[previewyoutube[^\]]*\].*?\[/previewyoutube\]', '', text) + + # Catch-all: remove any remaining BBCode tags we missed + text = re.sub(r'\[/?[a-zA-Z0-9]+(?:\s[^\]]*)?\]', '', text) + + # Clean up extra blank lines + text = re.sub(r'\n{3,}', '\n\n', text).strip() + return text + def run(self): self.load_localization() - self.fetch_forum_changelogs() - self.get_gamefile_changelogs() + self.fetch_steam_changelogs() self.changelogs_to_file() def load_localization(self): self.localization_data_en = json_utils.read(os.path.join(self.OUTPUT_DIR, 'localizations', 'english.json')) - def get_txt(self, changelog_path): - self._process_local_changelogs(changelog_path) - return self.changelogs - def changelogs_to_file(self): """ Save combined changelogs to input and output directories. - Saving to input directory is necessary as the RSS feed can only see + Saving to input directory is necessary as the Steam API only provides recent changelogs. Since output data is paved over each deploy, we need this source for historic @@ -197,244 +219,58 @@ def changelogs_to_file(self): # Save decoupled hotfixes for the uploader json_utils.write(f'{self.OUTPUT_DIR}/changelogs/hotfixes.json', self.hotfixes) - def _fetch_update_html(self, link): - """ - Fetches the HTML content of a forum link and extracts posts grouped by date. - Returns: - dict: { 'YYYY-MM-DD': [ {'text': str, 'link': str}, ... ] } - """ - html = request.urlopen(link).read() - soup = BeautifulSoup(html, features='html.parser') - - # Dictionary to group posts by date string 'YYYY-MM-DD' - content_by_date = defaultdict(list) - - # XenForo posts are wrapped in
- articles = soup.find_all('article', class_='message') - - # Target Timezone: Valve HQ (US/Pacific) + def fetch_steam_changelogs(self): + """Fetch patch notes from Steam Web API.""" + logger.trace('Fetching Steam news for changelogs') target_tz = ZoneInfo('US/Pacific') - for i, article in enumerate(articles): - # Extract the Date - time_elem = article.find('time', class_='u-dt') - if not time_elem or not time_elem.has_attr('datetime'): - continue - - try: - dt_str = time_elem['datetime'] - # Parse ISO string (e.g. 2024-11-21T01:00:00+0000) - dt_utc = datetime.fromisoformat(dt_str) - # Convert to Valve HQ time - dt_valve = dt_utc.astimezone(target_tz) - post_date = dt_valve.strftime('%Y-%m-%d') - except (IndexError, KeyError, ValueError) as e: - logger.warning(f'Failed to parse date from post: {e}') - continue - - # Extract the Link - if i == 0: - # The first post found is the Main Thread. - # Use the canonical link passed into the function (e.g. /threads/update.123/) - post_link = link - else: - # For subsequent posts (comments/hotfixes), find the specific permalink - post_link = None - attribution = article.find('ul', class_='message-attribution-main') - if attribution: - a_tag = attribution.find('a', href=True) - if a_tag: - href = a_tag['href'] - if href.startswith('http'): - post_link = href - else: - # Join base and relative path ensuring exactly one slash - post_link = self.FORUM_BASE_URL.rstrip('/') + '/' + href.lstrip('/') - - # Fallback if extraction fails - if not post_link: - post_link = link - - # Extract the Content - content_div = article.find('div', class_='bbWrapper') - if not content_div: - continue - - text = content_div.text.strip() - if text: - content_by_date[post_date].append({'text': text, 'link': post_link}) - - return content_by_date - - def get_gamefile_changelogs(self): - """Read and parse the Hero Labs changelogs in the game files""" - changelogs = json_utils.read(self.HEROLABS_PATCH_NOTES_PATH) - - gamefile_changelogs = dict() - - # Iterate each pair in the patch note localization - for key, string in changelogs.items(): - # Not a real patch note - if key == 'Language': - continue + try: + resp = requests.get(self.STEAM_NEWS_URL, timeout=30) + resp.raise_for_status() + data = resp.json() + except Exception as e: + logger.error(f'Failed to fetch Steam news: {e}') + return - # key i.e. Citadel_PatchNotes_HeroLabs_hero_astro_1 - # string i.e. "10/24/2024\t\t\t - #
  • Hero Added to Hero Labs
  • - # Changed y from x to z
  • " - - # Parse the date from the beginning of the string - date_raw = string.split('\t')[0].replace('', '').replace('', '') - if len(date_raw) > 10: - date_raw = date_raw[:10] - - # Remove date from remaining string - remaining_str = string.replace(f'{date_raw}\t\t\t', '') - - # Reformat mm/dd/yyyy to yyyy-mm-dd - date = format_date(date_raw) - - # Parse hero name to create a header for the changelog entry - # Citadel_PatchNotes_HeroLabs_hero_astro_1 -> - # hero_astro -> - # Holliday -> - # [ HeroLab Holliday ] - hero_key = key.split('Citadel_PatchNotes_HeroLabs_')[1][:-2] - hero_name_en = self._localize(hero_key) - header = f'[ HeroLab {hero_name_en} ]' - - # Initialize the changelog entry if its the first line for this hero's patch (version) - # Create the raw changelog id (used as filename in raw folder) - # i.e. 2024-10-29_HeroLab - raw_changelog_id = f'{date.replace("/", "-")}_HeroLab' - if raw_changelog_id not in gamefile_changelogs: - gamefile_changelogs[raw_changelog_id] = header + '\n' - else: - gamefile_changelogs[raw_changelog_id] += '\n' + header + '\n' - - # Ensure the date was able to be removed and was in the correct format - if len(remaining_str) == len(string): - logger.warning(f'Date format may not have been able to be parsed correctly for {date}') - - # Parse full description by accumulating each description separated by
  • tags - #
  • Text 1
  • Text 2
  • -> Text 1\nText 2\n - while len(remaining_str) > 0: - # Parse the next description - description, remaining_str = self._parse_description(remaining_str) - if description is None: - break - - # Add to the current changelog entry - gamefile_changelogs[raw_changelog_id] += f'- {description}\n' - - # Add the config entry if it doesn't exist - if raw_changelog_id not in self.changelog_configs: - self.changelog_configs[raw_changelog_id] = { - 'forum_id': None, - 'date': date, - 'link': None, - 'is_hero_lab': True, - } - self.changelogs.update(gamefile_changelogs) - - def _parse_description(self, string): - # Find the next
  • tag - li_start, li_end = self._find_li_tags(string) - if li_start == -1: - # No more list elements to be found - return None, string - if li_end == -1: - raise ValueError(f'No closing
  • tag found in description {string}') - - # Extract the description - description = string[li_start + len('
  • ') : li_end] - - # Remove the description from the remaining string - string = string[li_end + len('
  • ') :] - - # Remove any remaining tags that are unneeded - for tag in self.TAGS_TO_REMOVE: - description = description.replace(tag, '') - - return description, string - - def _find_li_tags(self, string): - # Find the next
  • tag - li_start = string.find('
  • ') - - # If no list elements are found, return right away - if li_start == -1: - return li_start, -1 - - # Find the next li tag, which will either be
  • , or
  • - li_end = string.find('
  • ', li_start + len('
  • ')) - # if no more
  • 's, find the last
  • - if li_end == -1: - li_end = string.find('', li_start + len('
  • ')) - - return li_start, li_end - - def _localize(self, key): - value = self.localization_data_en.get(key, None) - if value is None: - raise Exception(f'Localized string not found for key {key}') - return value - - def fetch_forum_changelogs(self): - """download rss feed from changelog forum and save all available entries""" - logger.trace('Parsing Changelog RSS feed') - # fetches 20 most recent entries - feed = feedparser.parse(self.RSS_URL) - - # Bucket to collect all updates grouped by date + news_items = data.get('appnews', {}).get('newsitems', []) updates_by_day: dict[str, list[ForumUpdate]] = defaultdict(list) - for entry in feed.entries: - # Parse version ID from URL - version = entry.link.split('.')[-1].split('/')[0] - try: - int(version) - except ValueError: - try: - version = entry.link.split('/')[-2].split('.')[-1] - int(version) - except ValueError: - continue - - if version is None or version == '': + for item in news_items: + tags = item.get('tags', []) + if 'patchnotes' not in tags: + logger.trace(f"Skipping non-patch-note news: {item.get('title')} (Tags: {tags})") continue - try: - # Scrape this thread for date-grouped posts - thread_updates = self._fetch_update_html(entry.link) - except Exception as e: - logger.error(f'Issue with parsing RSS feed item {entry.link}: {e}') + gid = str(item['gid']) + url = item.get('url') or f'https://store.steampowered.com/news/app/{self.APP_ID}/view/{gid}' + title = item.get('title', '') + date_unix = item['date'] + contents_bbcode = item.get('contents', '') + + dt_utc = datetime.fromtimestamp(date_unix, tz=ZoneInfo('UTC')) + dt_valve = dt_utc.astimezone(target_tz) + post_date = dt_valve.strftime('%Y-%m-%d') + + # Only process patch notes on or after 2026-06-04. + # Before this date, changelogs were sourced from the Deadlock forums and + # already exist in the data directory. Overwriting them with Steam-sourced + # content would replace forum URLs and formatting, which is undesirable. + if post_date < STEAM_MIGRATION_DATE: + logger.trace(f'Skipping old patch note before 2026-06-04: {title}') continue - # Add these updates to our master bucket - for date_key, posts in thread_updates.items(): - # Join text if multiple posts exist within ONE thread for ONE day - text_parts = [] - for i, p in enumerate(posts): - content = p['text'] - if i > 0: - content = f'=== Patch {i + 1} ===\n{content}' - text_parts.append(content) - - full_text = '\n\n'.join(text_parts) - specific_link = posts[0]['link'] + logger.trace(f'Processing Steam patch note: {title} ({post_date})') + text = self._bbcode_to_text(contents_bbcode) + steam_hash = hashlib.md5(contents_bbcode.encode('utf-8')).hexdigest() - updates_by_day[date_key].append({'version': version, 'text': full_text, 'link': specific_link}) + updates_by_day[post_date].append({'version': gid, 'text': text, 'link': url, 'title': title, 'steam_hash': steam_hash}) - # Now process the gathered updates day by day for date_key, entries in updates_by_day.items(): changelog_id = date_key - # Check for local file first (already processed by bot) local_path = os.path.join(self.INPUT_DIR, 'changelogs/raw', f'{changelog_id}.txt') local_content = file_utils.read(local_path) if os.path.exists(local_path) else '' - # Check for wiki page (manual pages created by editors) wiki_content = self._get_wiki_content(changelog_id) if not local_content else '' existing_config = self.changelog_configs.get(changelog_id) @@ -442,12 +278,30 @@ def fetch_forum_changelogs(self): main_entry = None append_entries = [] - # Find the main entry if existing_config: + matched = False for e in entries: - if e['version'] == existing_config['forum_id']: + if e['version'] == existing_config.get('source_id'): main_entry = e - break + matched = True + if existing_config.get('steam_hash') and existing_config['steam_hash'] != e['steam_hash']: + logger.warning(f'Steam post for {date_key} was edited by the devs!') + self.changelog_configs[changelog_id] = { + 'source_id': e['version'], + 'date': date_key, + 'link': e['link'], + 'is_hero_lab': False, + 'title': e.get('title'), + 'steam_hash': e['steam_hash'], + 'was_edited': True, + } + break + if existing_config and self.changelog_configs.get(changelog_id, {}).get('was_edited'): + continue + + if not matched and entries: + main_entry = entries[0] + for e in entries: if e != main_entry: append_entries.append(e) @@ -456,39 +310,29 @@ def fetch_forum_changelogs(self): main_entry = entries[0] append_entries = entries[1:] - # Determine base content and whether to append if local_content: - # Local file exists - use it as base, don't append to file - # (will still check for hotfixes to append to wiki later) current_text = local_content elif wiki_content and main_entry: - # Wiki page exists but no local file - append forum content to wiki - logger.info(f'Found wiki page for {date_key} without local file, appending forum content') + logger.info(f'Found wiki page for {date_key} without local file, appending new content') append_entries.insert(0, main_entry) current_text = wiki_content main_entry = None else: - # No existing content - use forum as base current_text = main_entry['text'] if main_entry else (self.changelogs.get(changelog_id, '')) old_text = local_content or wiki_content or '' - # Helper to get next patch number def get_next_patch_num(txt): matches = re.findall(r'=== Patch (\d+) ===', txt) if matches: return max(map(int, matches)) + 1 - # If there's existing content but no patches yet, this will be Patch 2 return 2 if txt.strip() else 1 - # Merge any secondary entries into current text with proper patch headers final_text = current_text for entry in append_entries: - # Remove any existing patch headers from the entry first entry_text = entry['text'] entry_text = re.sub(r'=== Patch \d+ ===\n*', '', entry_text).strip() - # Skip if this content is already in final_text normalized_entry = re.sub(r'^- ', '* ', entry_text, flags=re.MULTILINE) normalized_final = re.sub(r'^- ', '* ', final_text, flags=re.MULTILINE) if normalized_entry not in normalized_final: @@ -496,7 +340,6 @@ def get_next_patch_num(txt): final_text += f'\n\n=== Patch {patch_num} ===\n\n{entry_text}' logger.debug(f'Adding Patch {patch_num} to {date_key}') - # Detect hotfixes - compare new patches against old content potential_headers = re.findall(r'=== Patch \d+ ===', final_text) for h in potential_headers: if h not in old_text: @@ -505,102 +348,34 @@ def get_next_patch_num(txt): self.hotfixes.append({'date': date_key, 'text': section_text}) logger.debug(f'Detected hotfix: {h} for {date_key}') - # Save to memory and update config self.changelogs[changelog_id] = final_text - # Determine forum_id with priority: main_entry > existing_config > append_entries - if main_entry: - forum_id = main_entry['version'] - elif existing_config: - forum_id = existing_config.get('forum_id') - elif append_entries: - forum_id = append_entries[0]['version'] - else: - forum_id = None - - # Determine link with same priority if main_entry: + source_id = main_entry['version'] link = main_entry['link'] + title = main_entry.get('title') + steam_hash = main_entry.get('steam_hash') elif existing_config: + source_id = existing_config.get('source_id') link = existing_config.get('link') + title = existing_config.get('title') + steam_hash = existing_config.get('steam_hash') elif append_entries: + source_id = append_entries[0]['version'] link = append_entries[0]['link'] + title = append_entries[0].get('title') + steam_hash = append_entries[0].get('steam_hash') else: + source_id = None link = None + title = None + steam_hash = None self.changelog_configs[changelog_id] = { - 'forum_id': forum_id, + 'source_id': source_id, 'date': date_key, 'link': link, 'is_hero_lab': False, + 'title': title, + 'steam_hash': steam_hash, } - - def _process_local_changelogs(self, changelog_path): - logger.trace('Parsing Changelog txt files') - # Make sure path exists - if not os.path.isdir(changelog_path): - logger.warning(f'Issue opening changelog dir `{changelog_path}`') - return - files = [f for f in listdir(changelog_path) if isfile(join(changelog_path, f))] - logger.trace(f'Found {str(len(files))} changelog entries in `{changelog_path}`') - for file in files: - version = file.replace('.txt', '') - try: - with open(changelog_path + f'/{version}.txt', 'r', encoding='utf8') as f: - changelogs = f.read() - self.changelogs[version] = changelogs - except Exception: - logger.warning(f'Issue with {file}, skipping') - - def _create_changelog_id(self, date, forum_id, i=0): - """ - Creating a custom id based on the date by appending _ - if its another patch for the same day, i.e.: - 2024-10-29 - 2024-10-29-1 - 2024-10-29-2 - """ - - # (2024-12-17, 0) -> 2024-12-17 - # (2024-12-17, 1) -> 2024-12-17-1 - id = date if i == 0 else f'{date}-{i}' - - # Existing config for this date - existing_config = self.changelog_configs.get(id, None) - - # If this id doesn't yet exist, use it - if existing_config is None: - return id - # Else same date already exists - - # If the forum id is the same, use the same changelog id - # which will update the existing record - if existing_config['forum_id'] == forum_id: - return id - # Else forum id's are different, so different patches on the same day - - # Recursively check if the next id is available - return self._create_changelog_id(date, forum_id, i + 1) - - -def format_date(date): - """ - Reformat mm/dd/yyyy or mm-dd-yyyy to yyyy-mm-dd - Also convert days and months to 2 digits - """ - # Split date by / or - - if '/' in date: - date = date.split('/') - elif '-' in date: - date = date.split('-') - else: - raise ValueError(f'Invalid date format {date}') - - # If the day or month is a single digit, add a leading 0 - for i in range(2): - if len(date[i]) == 1: - date[i] = '0' + date[i] - - # Reformat to yyyy-mm-dd - date = f'{date[2]}-{date[0]}-{date[1]}' - return date diff --git a/src/changelogs/parse_changelogs.py b/src/changelogs/parse_changelogs.py index 5478a044..8023b9af 100644 --- a/src/changelogs/parse_changelogs.py +++ b/src/changelogs/parse_changelogs.py @@ -93,15 +93,12 @@ def format_and_save_wikitext_changelogs(self, changelogs, changelog_configs): output_path = os.path.join(self.OUTPUT_DIR, 'changelogs', 'wiki') os.makedirs(output_path, exist_ok=True) - # Sort keys to determine chronological order - # We filter for valid dates and exclude 'is_hero_lab' so main updates only link to previous main updates. sorted_update_ids = sorted( [k for k, v in changelog_configs.items() if v.get('date') and not v.get('is_hero_lab')], key=lambda k: changelog_configs[k]['date'] ) for changelog_id, raw_text in changelogs.items(): config = changelog_configs.get(changelog_id) - # Skip if config is missing or if it's a Hero Lab entry. if not config or config.get('is_hero_lab'): continue @@ -129,10 +126,18 @@ def format_and_save_wikitext_changelogs(self, changelogs, changelog_configs): except ValueError: pass - source_link = config.get('link', '') - source_title = '' - if source_link: - # Logic to extract title from URL + source_link = config.get('link') or '' + source_title = config.get('title') + + is_steam_link = ( + 'store.steampowered.com/news/' in source_link + or 'steamstore-a.akamaihd.net/news/' in source_link + or 'steamcommunity.com/app/' in source_link + ) + if source_link and is_steam_link: + if not source_title: + source_title = f"{date_obj.strftime('%m-%d-%Y')} Update" + elif source_link: parts = source_link.split('/') slug = '' for part in parts: @@ -145,11 +150,11 @@ def format_and_save_wikitext_changelogs(self, changelogs, changelog_configs): title_part = slug.split('.')[0] source_title = title_part.replace('-update', ' Update') - # Check for reply indicators in the URL if '/post-' in source_link or '/posts/' in source_link: source_title += ' (Reply)' else: - source_title = f"{date_obj.strftime('%m-%d-%Y')} Update" + if not source_title: + source_title = f"{date_obj.strftime('%m-%d-%Y')} Update" full_page_content = f"""{{{{Update layout | prev_update = {prev_update_link} @@ -228,13 +233,6 @@ def _parse_tags(self, current_heading, line): if heading_tag is not None: tags = self._register_tag(tags, tag=heading_tag) - # If the heading is a "HeroLab ", register as well - if current_heading.startswith('HeroLab '): - hero = current_heading[len('HeroLab ') :] - if self.is_hero(hero): - tags = self._register_tag(tags, hero) - tags = self._register_tag(tags, 'Hero') - # if no tag is found, assign to default tag if len(tags) == 0: tags = self._register_tag(tags, tag=self.default_tag) diff --git a/src/changelogs/tags.py b/src/changelogs/tags.py index 5cabaa89..66be9e8c 100644 --- a/src/changelogs/tags.py +++ b/src/changelogs/tags.py @@ -373,7 +373,6 @@ def _write_tag_tree(self, tag_tree): # Add , , etc. to tag tree # to show where instance tags would appear (such as Abrams, Basic Magazine, Siphon Life) tag_tree['Hero'][''] = {} - tag_tree['Hero'][''] = {'HeroLab ': {}} tag_tree['Hero']['Ability'][''] = {} tag_tree['Item']['Weapon Item'][''] = {} tag_tree['Item']['Vitality Item'][''] = {} diff --git a/src/deadbot.py b/src/deadbot.py index 567c39ca..28bf0c18 100644 --- a/src/deadbot.py +++ b/src/deadbot.py @@ -104,12 +104,10 @@ def act_gamefile_parse(args: Args): def act_changelog_parse(args: Args): - herolab_patch_notes_path = os.path.join(args.workdir, 'localizations', 'patch_notes', 'citadel_patch_notes_english.json') chlog_fetcher = fetch_changelogs.ChangelogFetcher( update_existing=False, input_dir=args.inputdir, output_dir=args.output, - herolab_patch_notes_path=herolab_patch_notes_path, ) chlog_fetcher.run() diff --git a/src/wiki/upload.py b/src/wiki/upload.py index 4963c528..0a1c14a5 100644 --- a/src/wiki/upload.py +++ b/src/wiki/upload.py @@ -107,6 +107,10 @@ def _upload_changelog_pages(self): logger.info('Uploading changelog pages...') + # Load changelog configs to check for edit flags + changelog_configs_path = os.path.join(self.OUTPUT_DIR, 'changelogs', 'changelog_configs.json') + changelog_configs = json_utils.read(changelog_configs_path, ignore_error=True) or {} + # Get and sort files with proper variant ordering via utility files = changelog_utils.sort_changelog_files([f for f in os.listdir(changelog_dir) if f.endswith('.txt')]) if not files: @@ -117,6 +121,11 @@ def _upload_changelog_pages(self): for filename in files: changelog_id = filename.replace('.txt', '') + + # Skip if the post was edited by devs to protect manual wiki edits + if changelog_configs.get(changelog_id, {}).get('was_edited'): + logger.info(f'Skipping wiki upload for {changelog_id} because devs edited the post. Manual review required.') + continue try: date_obj = changelog_utils.parse_changelog_date_from_id(changelog_id) if not date_obj: