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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3810,10 +3810,39 @@ components:
allOf:
- $ref: '#/components/schemas/EvolutionChainLink'
readOnly: true
transformations:
type: array
items:
$ref: '#/components/schemas/EvolutionChainTransformation'
readOnly: true
required:
- baby_trigger_item
- chain
- id
- transformations
EvolutionChainFormTransformation:
type: object
properties:
form:
$ref: '#/components/schemas/PokemonFormSummary'
trigger:
type: string
readOnly: true
item:
$ref: '#/components/schemas/ItemSummary'
ability:
$ref: '#/components/schemas/AbilitySummary'
move:
$ref: '#/components/schemas/MoveSummary'
base_form:
$ref: '#/components/schemas/PokemonFormSummary'
required:
- ability
- base_form
- form
- item
- move
- trigger
EvolutionChainLink:
type: object
properties:
Expand Down Expand Up @@ -3844,6 +3873,18 @@ components:
readOnly: true
required:
- url
EvolutionChainTransformation:
type: object
properties:
species:
$ref: '#/components/schemas/PokemonSpeciesSummary'
forms:
type: array
items:
$ref: '#/components/schemas/EvolutionChainFormTransformation'
required:
- forms
- species
EvolutionTriggerDetail:
type: object
properties:
Expand Down
58 changes: 57 additions & 1 deletion pokemon_v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ class PokemonWithRelations(Protocol):
"EncounterPokemonDetailSerializer",
"EncounterSlotSerializer",
"EvolutionChainDetailSerializer",
"EvolutionChainFormTransformationSerializer",
"EvolutionChainLinkSerializer",
"EvolutionChainSummarySerializer",
"EvolutionChainTransformationSerializer",
"EvolutionTriggerDetailSerializer",
"EvolutionTriggerNameSerializer",
"EvolutionTriggerSummarySerializer",
Expand Down Expand Up @@ -3372,6 +3374,24 @@ class Meta:
)


class EvolutionChainFormTransformationSerializer(serializers.ModelSerializer[PokemonFormCondition]):
form = PokemonFormSummarySerializer(source="pokemon_form")
trigger = serializers.CharField(source="form_trigger.name", read_only=True)
item = ItemSummarySerializer()
ability = AbilitySummarySerializer()
move = MoveSummarySerializer()
base_form = PokemonFormSummarySerializer()

class Meta:
model = PokemonFormCondition
fields = ("form", "trigger", "item", "ability", "move", "base_form")


class EvolutionChainTransformationSerializer(serializers.Serializer[Any]):
species = PokemonSpeciesSummarySerializer()
forms = EvolutionChainFormTransformationSerializer(many=True)


class EvolutionChainLinkSerializer(serializers.Serializer[Any]):
is_baby = serializers.BooleanField()
species = PokemonSpeciesSummarySerializer()
Expand All @@ -3382,6 +3402,7 @@ class EvolutionChainLinkSerializer(serializers.Serializer[Any]):
class EvolutionChainDetailSerializer(serializers.ModelSerializer[EvolutionChain]):
baby_trigger_item = ItemSummarySerializer()
chain = serializers.SerializerMethodField("build_chain")
transformations = serializers.SerializerMethodField("build_transformations")

POKEMON_EVOLUTION_FK_FIELDS: ClassVar[list[str]] = [
field.name
Expand All @@ -3391,7 +3412,7 @@ class EvolutionChainDetailSerializer(serializers.ModelSerializer[EvolutionChain]

class Meta:
model = EvolutionChain
fields = ("id", "baby_trigger_item", "chain")
fields = ("id", "baby_trigger_item", "chain", "transformations")

@extend_schema_field(EvolutionChainLinkSerializer)
def build_chain(self, obj: EvolutionChain) -> dict[str, Any]:
Expand Down Expand Up @@ -3464,6 +3485,41 @@ def build_chain_link_entry(
"evolves_to": [self.build_chain_link_entry(c, summary_data) for c in chain_link["children"]],
}

# collects the reversible form changes of every species in the chain (mega evolution,
# primal reversion, gigantamax, in-battle transformations), grouped by species
@extend_schema_field(EvolutionChainTransformationSerializer(many=True))
def build_transformations(self, obj: EvolutionChain) -> list[dict[str, Any]]:
conditions = (
PokemonFormCondition.objects.filter(pokemon_form__pokemon__pokemon_species__evolution_chain=obj)
.select_related(
"form_trigger",
"item",
"ability",
"move",
"base_form",
"pokemon_form__pokemon__pokemon_species",
)
.order_by(
"pokemon_form__pokemon__pokemon_species__order",
"pokemon_form__pokemon__pokemon_species__pk",
"pokemon_form__order",
"pk",
)
)

return [
{
"species": PokemonSpeciesSummarySerializer(species, context=self.context).data,
"forms": EvolutionChainFormTransformationSerializer(
list(species_conditions), many=True, context=self.context
).data,
}
for species, species_conditions in itertools.groupby(
conditions,
key=lambda condition: condition.pokemon_form.pokemon.pokemon_species,
)
]


############################
# POKEATHLON SERIALIZERS #
Expand Down
68 changes: 68 additions & 0 deletions pokemon_v2/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4837,6 +4837,7 @@ def test_evolution_chain_api(self):

# base params
self.assertEqual(response.data["id"], evolution_chain.pk)
self.assertEqual(response.data["transformations"], [])
# baby trigger params
self.assertEqual(response.data["baby_trigger_item"]["name"], baby_trigger_item.name)
self.assertEqual(
Expand Down Expand Up @@ -4921,6 +4922,73 @@ def test_evolution_chain_api(self):
"{}{}/type/{}/".format(TEST_HOST, API_V2, stage_two_second_party_type.pk),
)

# verifies that the reversible form changes of the chain's species are exposed
def test_evolution_chain_api_transformations(self):
evolution_chain = self.setup_evolution_chain_data()

basic = self.setup_pokemon_species_data(name="bsc for evo chn trnsfrm", evolution_chain=evolution_chain)
evolved = self.setup_pokemon_species_data(
name="evlvd for evo chn trnsfrm",
evolves_from_species=basic,
evolution_chain=evolution_chain,
order=2,
)
self.setup_pokemon_evolution_data(evolved_species=evolved, min_level=16)

evolved_pokemon = self.setup_pokemon_data(pokemon_species=evolved, name="pkmn for evo chn trnsfrm")
default_form = self.setup_pokemon_form_data(
pokemon=evolved_pokemon, name="dflt frm for evo chn trnsfrm", order=1, form_order=1
)
mega_form = self.setup_pokemon_form_data(
pokemon=evolved_pokemon,
name="mg frm for evo chn trnsfrm",
order=2,
form_order=2,
is_mega=True,
)
mega_stone = self.setup_item_data(name="itm for evo chn trnsfrm")
form_trigger = self.setup_pokemon_form_trigger_data(name="frm trgr for evo chn trnsfrm")
self.setup_pokemon_form_condition_data(
pokemon_form=mega_form,
form_trigger=form_trigger,
item=mega_stone,
base_form=default_form,
)

response = self.client.get("{}/evolution-chain/{}/".format(API_V2, evolution_chain.pk))

self.assertEqual(response.status_code, status.HTTP_200_OK)

# the chain itself is untouched by the transformations
self.assertEqual(response.data["chain"]["species"]["name"], basic.name)
self.assertEqual(response.data["chain"]["evolves_to"][0]["species"]["name"], evolved.name)
self.assertEqual(response.data["chain"]["evolves_to"][0]["evolves_to"], [])

transformations = response.data["transformations"]
self.assertEqual(len(transformations), 1)
self.assertEqual(transformations[0]["species"]["name"], evolved.name)
self.assertEqual(
transformations[0]["species"]["url"],
"{}{}/pokemon-species/{}/".format(TEST_HOST, API_V2, evolved.pk),
)

forms = transformations[0]["forms"]
self.assertEqual(len(forms), 1)
self.assertEqual(forms[0]["form"]["name"], mega_form.name)
self.assertEqual(
forms[0]["form"]["url"],
"{}{}/pokemon-form/{}/".format(TEST_HOST, API_V2, mega_form.pk),
)
self.assertEqual(forms[0]["trigger"], form_trigger.name)
self.assertEqual(forms[0]["item"]["name"], mega_stone.name)
self.assertEqual(
forms[0]["item"]["url"],
"{}{}/item/{}/".format(TEST_HOST, API_V2, mega_stone.pk),
)
self.assertEqual(forms[0]["base_form"]["name"], default_form.name)
self.assertIsNone(forms[0]["ability"])
self.assertIsNone(forms[0]["move"])

# verifies that the wurmple evolution chain is serialized correctly
def test_evolution_chain_api_wurmple_bugfix(self):
# set up wurmple-like evolution chain
Expand Down
Loading