vimgolf_gym.dataclasses

Shared Pydantic dataclasses for vimgolf-gym

  1"""
  2Shared Pydantic dataclasses for vimgolf-gym
  3"""
  4
  5import json
  6from datetime import datetime
  7from pathlib import Path
  8
  9from parse import parse
 10from pydantic import BaseModel, Field
 11from typing import Optional
 12
 13class VimGolfCustomChallenge(BaseModel):
 14    """Represents a custom VimGolf challenge
 15
 16    Attributes:
 17        input: The input of the challenge (required)
 18        output: The output of the challenge (required)
 19        name: The name of the challenge (optional)
 20        description: The description of the challenge (optional)
 21        solution: The VimGolf solution (optional)
 22    """
 23    input: str
 24    output: str
 25    name: Optional[str]
 26    description: Optional[str]
 27    solution: Optional[str]
 28
 29
 30class VimGolfEnvResult(BaseModel):
 31    """Represents a single result of VimGolf challenge environment,
 32
 33    Attributes:
 34        correct: The challenge is solved or not
 35        keys: VimGolf solution keys (converted from raw representation)
 36        score: Keystrokes count (the lower the better)
 37    """
 38
 39    correct: bool
 40    keys: str
 41    score: int
 42
 43
 44class VimGolfParsedPublicSolutionHeader(BaseModel):
 45    """Represents the header of a VimGolf public solution entry.
 46
 47    Attributes:
 48        rank: The rank of the solution (provided as a string in the reference).
 49        score: The score of the solution (provided as a string in the reference).
 50        user_name: The name of the user who submitted the solution.
 51        user_id: The ID of the user who submitted the solution.
 52        date: The date the solution was submitted.
 53    """
 54
 55    rank: str
 56    score: str
 57    user_name: str
 58    user_id: str
 59    date: datetime
 60
 61
 62class VimGolfPublicSolution(BaseModel):
 63    """Represents a public solution entry in VimGolf.
 64
 65    Attributes:
 66        rank: The rank of the solution (provided as a string in the reference).
 67        solution: The sequence of Vim keystrokes used in the solution.
 68        header: Descriptive header containing user and challenge details.
 69    """
 70
 71    rank: str
 72    solution: str
 73    header: str
 74
 75
 76class VimGolfChallengeMetadata(BaseModel):
 77    """
 78    Represents metadata for a VimGolf challenge.
 79
 80    Attributes:
 81        href: URL path to the challenge.
 82        title: Name/description of the challenge.
 83        detail: Explanation of the challenge task.
 84        challenge_hash: Unique identifier hash for the challenge.
 85    """
 86
 87    href: str
 88    title: str
 89    detail: str
 90    challenge_hash: str
 91
 92
 93class VimGolfChallengeDefinition(BaseModel):
 94    """
 95    Represents a VimGolf challenge definition including input/output code and client information.
 96
 97    Attributes:
 98        input: Starting code and its type (nested model)
 99        output: Expected solution code and its type (nested model)
100        client_version: Version of the client that created the challenge
101    """
102
103    class InputOutputModel(BaseModel):
104        """
105        Nested model for input/output code definitions.
106
107        Attributes:
108            data: The actual code content
109            type: Programming language identifier (e.g., 'rb' for Ruby)
110        """
111
112        data: str
113        type: str
114
115    input: InputOutputModel = Field(..., alias="in")
116    output: InputOutputModel = Field(..., alias="out")
117    client_version: str = Field(..., alias="client")
118
119    class Config:
120        validate_by_name = True
121
122
123def parse_json_file(file_path: Path, model: type[BaseModel]) -> BaseModel:
124    """Parse a JSON file into a specified Pydantic model
125    
126    Args:
127        file_path (Path): Path to the JSON file.
128        model (type[BaseModel]): Pydantic model to parse the JSON into.
129    
130    Returns:
131        BaseModel: Parsed model instance
132    """
133    with open(file_path, "r", encoding="utf-8") as f:
134        data = json.load(f)
135    return model.parse_obj(data)
136
137
138def parse_public_solution_header(input_str: str) -> VimGolfParsedPublicSolutionHeader:
139    """Parse the public solution header string
140    
141    Args:
142        input_str (str): Public solution header string.
143    
144    Returns:
145        VimGolfParsedPublicSolutionHeader
146    """
147    template = "#{rank} {user_name} / @{user_id} - Score: {score} - {month}/{day}/{year} @ {hour}:{minute}"
148
149    # Parse the input string using the template
150    parsed_data = parse(template, input_str)
151
152    # Convert parsed fields to integers and process the year
153    month = int(parsed_data["month"])
154    day = int(parsed_data["day"])
155    year = int(parsed_data["year"])
156    hour = int(parsed_data["hour"])
157    minute = int(parsed_data["minute"])
158
159    # Adjust two-digit year to four digits
160    full_year = year + 2000 if year < 70 else year + 1900
161
162    # Create a datetime object and format the timestamp
163    dt = datetime(full_year, month, day, hour, minute)
164    timestamp = dt.strftime("%Y-%m-%d %H:%M:%S")
165
166    ret = VimGolfParsedPublicSolutionHeader(
167        rank=parsed_data["rank"],
168        score=parsed_data["score"],
169        user_name=parsed_data["user_name"],
170        user_id=parsed_data["user_id"],
171        date=timestamp,
172    )
173    return ret
class VimGolfCustomChallenge(pydantic.main.BaseModel):
14class VimGolfCustomChallenge(BaseModel):
15    """Represents a custom VimGolf challenge
16
17    Attributes:
18        input: The input of the challenge (required)
19        output: The output of the challenge (required)
20        name: The name of the challenge (optional)
21        description: The description of the challenge (optional)
22        solution: The VimGolf solution (optional)
23    """
24    input: str
25    output: str
26    name: Optional[str]
27    description: Optional[str]
28    solution: Optional[str]

Represents a custom VimGolf challenge

Attributes:
  • input: The input of the challenge (required)
  • output: The output of the challenge (required)
  • name: The name of the challenge (optional)
  • description: The description of the challenge (optional)
  • solution: The VimGolf solution (optional)
input: str
output: str
name: Optional[str]
description: Optional[str]
solution: Optional[str]
model_config: ClassVar[pydantic.config.ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class VimGolfEnvResult(pydantic.main.BaseModel):
31class VimGolfEnvResult(BaseModel):
32    """Represents a single result of VimGolf challenge environment,
33
34    Attributes:
35        correct: The challenge is solved or not
36        keys: VimGolf solution keys (converted from raw representation)
37        score: Keystrokes count (the lower the better)
38    """
39
40    correct: bool
41    keys: str
42    score: int

Represents a single result of VimGolf challenge environment,

Attributes:
  • correct: The challenge is solved or not
  • keys: VimGolf solution keys (converted from raw representation)
  • score: Keystrokes count (the lower the better)
correct: bool
keys: str
score: int
model_config: ClassVar[pydantic.config.ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class VimGolfParsedPublicSolutionHeader(pydantic.main.BaseModel):
45class VimGolfParsedPublicSolutionHeader(BaseModel):
46    """Represents the header of a VimGolf public solution entry.
47
48    Attributes:
49        rank: The rank of the solution (provided as a string in the reference).
50        score: The score of the solution (provided as a string in the reference).
51        user_name: The name of the user who submitted the solution.
52        user_id: The ID of the user who submitted the solution.
53        date: The date the solution was submitted.
54    """
55
56    rank: str
57    score: str
58    user_name: str
59    user_id: str
60    date: datetime

Represents the header of a VimGolf public solution entry.

Attributes:
  • rank: The rank of the solution (provided as a string in the reference).
  • score: The score of the solution (provided as a string in the reference).
  • user_name: The name of the user who submitted the solution.
  • user_id: The ID of the user who submitted the solution.
  • date: The date the solution was submitted.
rank: str
score: str
user_name: str
user_id: str
date: datetime.datetime
model_config: ClassVar[pydantic.config.ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class VimGolfPublicSolution(pydantic.main.BaseModel):
63class VimGolfPublicSolution(BaseModel):
64    """Represents a public solution entry in VimGolf.
65
66    Attributes:
67        rank: The rank of the solution (provided as a string in the reference).
68        solution: The sequence of Vim keystrokes used in the solution.
69        header: Descriptive header containing user and challenge details.
70    """
71
72    rank: str
73    solution: str
74    header: str

Represents a public solution entry in VimGolf.

Attributes:
  • rank: The rank of the solution (provided as a string in the reference).
  • solution: The sequence of Vim keystrokes used in the solution.
  • header: Descriptive header containing user and challenge details.
rank: str
solution: str
header: str
model_config: ClassVar[pydantic.config.ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class VimGolfChallengeMetadata(pydantic.main.BaseModel):
77class VimGolfChallengeMetadata(BaseModel):
78    """
79    Represents metadata for a VimGolf challenge.
80
81    Attributes:
82        href: URL path to the challenge.
83        title: Name/description of the challenge.
84        detail: Explanation of the challenge task.
85        challenge_hash: Unique identifier hash for the challenge.
86    """
87
88    href: str
89    title: str
90    detail: str
91    challenge_hash: str

Represents metadata for a VimGolf challenge.

Attributes:
  • href: URL path to the challenge.
  • title: Name/description of the challenge.
  • detail: Explanation of the challenge task.
  • challenge_hash: Unique identifier hash for the challenge.
href: str
title: str
detail: str
challenge_hash: str
model_config: ClassVar[pydantic.config.ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class VimGolfChallengeDefinition(pydantic.main.BaseModel):
 94class VimGolfChallengeDefinition(BaseModel):
 95    """
 96    Represents a VimGolf challenge definition including input/output code and client information.
 97
 98    Attributes:
 99        input: Starting code and its type (nested model)
100        output: Expected solution code and its type (nested model)
101        client_version: Version of the client that created the challenge
102    """
103
104    class InputOutputModel(BaseModel):
105        """
106        Nested model for input/output code definitions.
107
108        Attributes:
109            data: The actual code content
110            type: Programming language identifier (e.g., 'rb' for Ruby)
111        """
112
113        data: str
114        type: str
115
116    input: InputOutputModel = Field(..., alias="in")
117    output: InputOutputModel = Field(..., alias="out")
118    client_version: str = Field(..., alias="client")
119
120    class Config:
121        validate_by_name = True

Represents a VimGolf challenge definition including input/output code and client information.

Attributes:
  • input: Starting code and its type (nested model)
  • output: Expected solution code and its type (nested model)
  • client_version: Version of the client that created the challenge
client_version: str
model_config: ClassVar[pydantic.config.ConfigDict] = {'validate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class VimGolfChallengeDefinition.InputOutputModel(pydantic.main.BaseModel):
104    class InputOutputModel(BaseModel):
105        """
106        Nested model for input/output code definitions.
107
108        Attributes:
109            data: The actual code content
110            type: Programming language identifier (e.g., 'rb' for Ruby)
111        """
112
113        data: str
114        type: str

Nested model for input/output code definitions.

Attributes:
  • data: The actual code content
  • type: Programming language identifier (e.g., 'rb' for Ruby)
data: str
type: str
model_config: ClassVar[pydantic.config.ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class VimGolfChallengeDefinition.Config:
120    class Config:
121        validate_by_name = True
validate_by_name = True
def parse_json_file( file_path: pathlib.Path, model: type[pydantic.main.BaseModel]) -> pydantic.main.BaseModel:
124def parse_json_file(file_path: Path, model: type[BaseModel]) -> BaseModel:
125    """Parse a JSON file into a specified Pydantic model
126    
127    Args:
128        file_path (Path): Path to the JSON file.
129        model (type[BaseModel]): Pydantic model to parse the JSON into.
130    
131    Returns:
132        BaseModel: Parsed model instance
133    """
134    with open(file_path, "r", encoding="utf-8") as f:
135        data = json.load(f)
136    return model.parse_obj(data)

Parse a JSON file into a specified Pydantic model

Arguments:
  • file_path (Path): Path to the JSON file.
  • model (type[BaseModel]): Pydantic model to parse the JSON into.
Returns:

BaseModel: Parsed model instance

def parse_public_solution_header( input_str: str) -> VimGolfParsedPublicSolutionHeader:
139def parse_public_solution_header(input_str: str) -> VimGolfParsedPublicSolutionHeader:
140    """Parse the public solution header string
141    
142    Args:
143        input_str (str): Public solution header string.
144    
145    Returns:
146        VimGolfParsedPublicSolutionHeader
147    """
148    template = "#{rank} {user_name} / @{user_id} - Score: {score} - {month}/{day}/{year} @ {hour}:{minute}"
149
150    # Parse the input string using the template
151    parsed_data = parse(template, input_str)
152
153    # Convert parsed fields to integers and process the year
154    month = int(parsed_data["month"])
155    day = int(parsed_data["day"])
156    year = int(parsed_data["year"])
157    hour = int(parsed_data["hour"])
158    minute = int(parsed_data["minute"])
159
160    # Adjust two-digit year to four digits
161    full_year = year + 2000 if year < 70 else year + 1900
162
163    # Create a datetime object and format the timestamp
164    dt = datetime(full_year, month, day, hour, minute)
165    timestamp = dt.strftime("%Y-%m-%d %H:%M:%S")
166
167    ret = VimGolfParsedPublicSolutionHeader(
168        rank=parsed_data["rank"],
169        score=parsed_data["score"],
170        user_name=parsed_data["user_name"],
171        user_id=parsed_data["user_id"],
172        date=timestamp,
173    )
174    return ret

Parse the public solution header string

Arguments:
  • input_str (str): Public solution header string.
Returns:

VimGolfParsedPublicSolutionHeader