From d66772d9ec38cbe77c6cf384ea2814bc3f19f1c5 Mon Sep 17 00:00:00 2001 From: Doug Hoskisson Date: Wed, 28 Feb 2024 17:22:42 -0800 Subject: [PATCH] Core: typing: return type of `fill_slot_data` to `Mapping` (#2876) * Core: typing: return type of `fill_slot_data` to `Mapping` type checker be like: "Wait a minute! If you give this mutable dict to those sussy sketchbags, they might mutate it and invalidate your more specific typing!" Note that this doesn't mean the return value needs to be immutable. It just means the caller won't mutate it (which matches current `Main.py` implementation). I've seen some talk of introducing ownership to the type system. https://discuss.python.org/t/we-may-need-better-specification-for-existing-and-future-refinement-types-in-the-type-system/43955/5 Then maybe I could say: "Do whatever you want with it, because I'm giving up ownership." But that doesn't exist in the type system currently. * in docs too * docs talk less about type and more about json * keep `dict` to be safe with .net client and json --- docs/world api.md | 5 +++-- worlds/AutoWorld.py | 14 ++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/world api.md b/docs/world api.md index fd8e0988e567..f82ef40a98f8 100644 --- a/docs/world api.md +++ b/docs/world api.md @@ -738,8 +738,9 @@ def generate_output(self, output_directory: str) -> None: If the game client needs to know information about the generated seed, a preferred method of transferring the data is through the slot data. This is filled with the `fill_slot_data` method of your world by returning -a `Dict[str, Any]`, but, to not waste resources, should be limited to data that is absolutely necessary. Slot data is -sent to your client once it has successfully [connected](network%20protocol.md#connected). +a `dict` with `str` keys that can be serialized with json. +But, to not waste resources, it should be limited to data that is absolutely necessary. Slot data is sent to your client +once it has successfully [connected](network%20protocol.md#connected). If you need to know information about locations in your world, instead of propagating the slot data, it is preferable to use [LocationScouts](network%20protocol.md#locationscouts), since that data already exists on the server. The most common usage of slot data is sending option results that the client needs to be aware of. diff --git a/worlds/AutoWorld.py b/worlds/AutoWorld.py index b282c7deb8bd..dd0f46f6a6d1 100644 --- a/worlds/AutoWorld.py +++ b/worlds/AutoWorld.py @@ -7,8 +7,8 @@ import sys import time from dataclasses import make_dataclass -from typing import Any, Callable, ClassVar, Dict, Set, Tuple, FrozenSet, List, Optional, TYPE_CHECKING, TextIO, Type, \ - Union +from typing import (Any, Callable, ClassVar, Dict, FrozenSet, List, Mapping, + Optional, Set, TextIO, Tuple, TYPE_CHECKING, Type, Union) from Options import PerGameCommonOptions from BaseClasses import CollectionState @@ -365,13 +365,19 @@ def generate_output(self, output_directory: str) -> None: If you need any last-second randomization, use self.random instead.""" pass - def fill_slot_data(self) -> Dict[str, Any]: # json of WebHostLib.models.Slot - """Fill in the `slot_data` field in the `Connected` network package. + def fill_slot_data(self) -> Mapping[str, Any]: # json of WebHostLib.models.Slot + """What is returned from this function will be in the `slot_data` field + in the `Connected` network package. + It should be a `dict` with `str` keys, and should be serializable with json. + This is a way the generator can give custom data to the client. The client will receive this as JSON in the `Connected` response. The generation does not wait for `generate_output` to complete before calling this. `threading.Event` can be used if you need to wait for something from `generate_output`.""" + # The reason for the `Mapping` type annotation, rather than `dict` + # is so that type checkers won't worry about the mutability of `dict`, + # so you can have more specific typing in your world implementation. return {} def extend_hint_information(self, hint_data: Dict[int, Dict[int, str]]):