Serialization
Overview
Elote provides a standardized serialization format for all competitor types, allowing for consistent saving and loading of competitor states. This is particularly useful for:
Persisting ratings between application runs
Sharing ratings between different systems
Creating backups of rating data
Analyzing rating changes over time
Standardized Format
As of version 1.0.0, all competitors use a standardized serialization format that includes the following fields:
{
"type": "EloCompetitor",
"version": 1,
"created_at": 1625097600,
"id": "550e8400-e29b-41d4-a716-446655440000",
"parameters": {
"initial_rating": 1500
},
"state": {
"rating": 1550
},
"class_vars": {
"k_factor": 32
}
}
Field Descriptions
type: The class name of the competitor (e.g., “EloCompetitor”, “GlickoCompetitor”)
version: The version of the serialization format (currently 1)
created_at: Unix timestamp when the state was exported
id: A unique identifier for this state export (UUID)
parameters: The parameters used to initialize the competitor - initial_rating: The initial rating value - Other parameters specific to the competitor type
state: The current state variables of the competitor - rating: The current rating value - Other state variables specific to the competitor type
class_vars: Class variables for backward compatibility - Class variables specific to the competitor type
Backward Compatibility
For backward compatibility, the serialized format also includes flattened parameters and state variables at the top level of the dictionary. This allows older code that expects these fields to continue working.
For example, in addition to the structured format above, the serialized JSON also includes:
{
"type": "EloCompetitor",
"version": 1,
"created_at": 1625097600,
"id": "550e8400-e29b-41d4-a716-446655440000",
"parameters": { ... },
"state": { ... },
"class_vars": { ... },
"initial_rating": 1500,
"current_rating": 1550
}
Serialization Methods
To JSON
To serialize a competitor to JSON:
from elote import EloCompetitor
# Create a competitor
competitor = EloCompetitor(initial_rating=1500)
# Serialize to JSON
json_str = competitor.to_json()
From JSON
To deserialize a competitor from JSON:
from elote import EloCompetitor
# Deserialize from JSON
competitor = EloCompetitor.from_json(json_str)
Cross-Competitor Compatibility
Competitors can only be deserialized to the same type they were serialized from. Attempting to deserialize a competitor to a different type will raise an InvalidStateException
.
For example, this will fail:
from elote import EloCompetitor, GlickoCompetitor
# Create and serialize an Elo competitor
elo_competitor = EloCompetitor(initial_rating=1500)
json_str = elo_competitor.to_json()
# Attempt to deserialize as a Glicko competitor (will raise an exception)
try:
glicko_competitor = GlickoCompetitor.from_json(json_str)
except Exception as e:
print(f"Error: {e}")
Complete Example
Here’s a complete example of serializing and deserializing a competitor:
from elote import EloCompetitor
import json
# Create a competitor
competitor = EloCompetitor(initial_rating=1500)
# Simulate some matches
competitor.beat(EloCompetitor(initial_rating=1400))
competitor.beat(EloCompetitor(initial_rating=1450))
competitor.lost_to(EloCompetitor(initial_rating=1600))
# Serialize to JSON
json_str = competitor.to_json()
# Print the serialized JSON (formatted for readability)
print("Serialized competitor:")
print(json.dumps(json.loads(json_str), indent=4))
# Deserialize from JSON
new_competitor = EloCompetitor.from_json(json_str)
# Verify the ratings match
print(f"Original rating: {competitor.rating}")
print(f"Deserialized rating: {new_competitor.rating}")
# Continue using the deserialized competitor
new_competitor.beat(EloCompetitor(initial_rating=1450))
print(f"Updated rating after another match: {new_competitor.rating}")
Implementing Serialization in Custom Competitors
If you’re implementing a custom competitor, you need to implement the following methods to support the standardized serialization format:
def _export_parameters(self) -> Dict[str, Any]:
"""Export the parameters used to initialize this competitor."""
return {
"initial_rating": self._initial_rating,
# Include any other parameters used during initialization
}
def _export_current_state(self) -> Dict[str, Any]:
"""Export the current state variables of this competitor."""
return {
"rating": self._rating,
# Include any other state variables that change during usage
}
def _import_parameters(self, parameters: Dict[str, Any]) -> None:
"""Import parameters from a state dictionary."""
if "initial_rating" in parameters:
initial_rating = parameters["initial_rating"]
if initial_rating < self._minimum_rating:
raise InvalidParameterException(f"Initial rating cannot be below the minimum rating of {self._minimum_rating}")
self._initial_rating = initial_rating
# Import any other parameters
def _import_current_state(self, state: Dict[str, Any]) -> None:
"""Import current state variables from a state dictionary."""
if "rating" in state:
rating = state["rating"]
if rating < self._minimum_rating:
raise InvalidStateException(f"Rating cannot be below the minimum rating of {self._minimum_rating}")
self._rating = rating
# Import any other state variables
@classmethod
def _create_from_parameters(cls: Type[T], parameters: Dict[str, Any]) -> T:
"""Create a new competitor instance from parameters."""
initial_rating = parameters.get("initial_rating", 1500)
# Create a new instance with the parameters
return cls(initial_rating=initial_rating)
For more details on implementing custom competitors, see the implementing_competitors guide.