Skip to content

Commit cd4b607

Browse files
vberliermisodeSpecialBuilder32
authored
Upgrade to Pydantic v2 (#1214)
* Upgrade to Pydantic v2 * Make babelbox csv dialect explicit everywhere * Update beet beta version * Fix before validators in resource pack plugin * Update setup-uv action in test job * Comment downcast * Type hint comment * Update beet to release versions * Update .python-version to 3.14 --------- Co-authored-by: Misode <misoloo64@gmail.com> Co-authored-by: SpecialBuilder <specialbuilder32@gmail.com>
1 parent d41cb45 commit cd4b607

File tree

22 files changed

+584
-801
lines changed

22 files changed

+584
-801
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,7 @@ jobs:
3030
run: git fetch origin ${{ github.base_ref }}
3131

3232
- name: Set up uv
33-
uses: astral-sh/setup-uv@v3
34-
with:
35-
version: '0.5.4'
36-
enable-cache: true
33+
uses: astral-sh/setup-uv@v7
3734

3835
- name: Build and publish all modules
3936
if: github.event_name != 'pull_request'
@@ -111,10 +108,7 @@ jobs:
111108
- uses: actions/checkout@v4
112109

113110
- name: Set up uv
114-
uses: astral-sh/setup-uv@v3
115-
with:
116-
version: '0.5.4'
117-
enable-cache: true
111+
uses: astral-sh/setup-uv@v7
118112

119113
- name: Build all modules for tests
120114
run: uv run beet -p beet-test.yaml -l ${{ env.LOG_LEVEL }} build

.python-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.11
1+
3.14

base/beet.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ version: 1.8.0
22
id: gm4
33

44
data_pack:
5-
load:
5+
load:
66
data: data
77

8-
resource_pack:
8+
resource_pack:
99
load:
1010
assets: assets
1111
backport_72: backport_72
@@ -31,3 +31,4 @@ meta:
3131
babelbox:
3232
load: assets/translations.csv
3333
namespace: gm4_translations
34+
dialect: excel

gm4/commands.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
from beet import Project
1616
from beet.toolchain.cli import beet
1717

18-
# NOTE pydantic.v1 does not allow reloading models with custom validators, which beet watch will do normally.
19-
# Importing them here prevents their reload on each watch cycle. This may change in pydantic.v2 - revisit then
18+
# NOTE pydantic does not allow reloading models with custom validators, which beet watch will do normally.
19+
# Importing them here prevents their reload on each watch cycle.
2020
from gm4.utils import MapOption # type: ignore
2121
from gm4.plugins.resource_pack import ModelData # type: ignore
2222

@@ -104,16 +104,16 @@ def clean():
104104
@click.option("-c", "--clean", is_flag=True, help="Clean the output folder.")
105105
def readme_gen(ctx: click.Context, project: Project, modules: tuple[str, ...], watch: bool, clean: bool):
106106
"""Generates all README files for manual uplaoad"""
107-
107+
108108
modules = tuple(m if m.startswith("gm4_") else f"gm4_{m}" for m in modules)
109109
if len(modules) == 0:
110110
click.echo("[GM4] You need at least one module")
111111
return
112-
112+
113113
if clean:
114114
click.echo(f"[GM4] Cleaning output folder...")
115115
shutil.rmtree("out", ignore_errors=True)
116-
116+
117117
click.echo(f"[GM4] Generating READMEs for: {', '.join(modules)}")
118118

119119
# we want to only read in the metadata from each project fo make a readme, not run the whole build pipeline

gm4/plugins/annotations.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313

1414
def beet_default(ctx: Context):
15-
"""Sets up a logging handlers to emit build log entries with the github action annotation format,
15+
"""Sets up a logging handlers to emit build log entries with the github action annotation format,
1616
and create a summary with useful build information."""
1717
root_logger = logging.getLogger(None) # get root logger
1818

@@ -28,7 +28,7 @@ def filter(record: logging.LogRecord):
2828

2929
root_logger.handlers.clear() # clear the handler set by beet CLI toolchain
3030
root_logger.addHandler(ann_handler)
31-
31+
3232
# summary handler holds onto certain records until the exit phase when it emits to a markdown summary
3333
sum_handler = SummaryHandler(1000, ctx.cache)
3434
logging.getLogger("gm4.output").addHandler(sum_handler)
@@ -47,12 +47,12 @@ def filter(record: logging.LogRecord):
4747
}
4848

4949
class AnnotationFormatter(logging.Formatter):
50-
50+
5151
def format(self, record: logging.LogRecord) -> str:
5252

5353
expl = record.getMessage().replace("\n", "%0A")
5454
# use urlencoded newline
55-
55+
5656
level = LEVEL_CONVERSION.get(record.levelno, LEVEL_CONVERSION[logging.INFO])
5757

5858
filename = None
@@ -61,14 +61,14 @@ def format(self, record: logging.LogRecord) -> str:
6161

6262
if getattr(record, "gh_annotate_skip", False): # disable annotations for any gm4 log events flagged manually
6363
return f"{level.capitalize()}: {record.name} {expl}" # formatted to resemble annotated entry
64-
64+
6565
match = re.match(r"(.+):(\d+):(\d+)", getattr(record, "annotate", "")) # extract filename and location from mecha annotation
6666
if match:
6767
filename, line, col = match.groups()
6868
return f"::{level} file={filename},line={line},col={col},title={record.name}::{record.name} {expl}"
6969

7070
return f"::{level} title={record.name}::{record.name} {expl}"
71-
71+
7272
class SummaryHandler(logging.handlers.BufferingHandler):
7373
def __init__(self, capacity: int, beet_cache: ProjectCache):
7474
super().__init__(capacity)
@@ -78,8 +78,8 @@ def __init__(self, capacity: int, beet_cache: ProjectCache):
7878
def flush(self):
7979
summary_entries: dict[str, Any] = {}
8080

81-
this_manifest = ManifestCacheModel.parse_obj(self.beet_cache["gm4_manifest"].json)
82-
last_manifest = ManifestFileModel.parse_obj(self.beet_cache["previous_manifest"].json)
81+
this_manifest = ManifestCacheModel.model_validate(self.beet_cache["gm4_manifest"].json)
82+
last_manifest = ManifestFileModel.model_validate(self.beet_cache["previous_manifest"].json)
8383

8484
this_versions = {id: entry.version for id, entry in (this_manifest.modules | this_manifest.libraries).items()}
8585
last_versions = {id: entry.version for id, entry in ({e.id: e for e in last_manifest.modules} | last_manifest.libraries).items()}
@@ -107,7 +107,7 @@ def flush(self):
107107
"ver_update": f"{last_version_num}{this_version_num}",
108108
"logs": [] # list of tuples ("smithed", log_message)
109109
}
110-
110+
111111
# append to logs
112112
summary_entries[module_id]["logs"].append((service, record.getMessage()))
113113

@@ -120,7 +120,7 @@ def flush(self):
120120
nested_table += "</table></details>"
121121

122122
table += f"\n {entry['name']} | {entry['ver_update']} | {nested_table}"
123-
123+
124124
summary = "# :rocket: Build Deployment Summary :rocket:\n"+table
125125

126126
if not self.summary_created:
@@ -131,7 +131,7 @@ def flush(self):
131131
self.summary_created = True
132132
self.buffer.clear()
133133

134-
134+
135135

136136
def add_module_dir_to_diagnostics(ctx: Context):
137137
"""Sets up a logging record filter that prepends the proper module folder to mecha diagnostics"""
@@ -141,7 +141,7 @@ def add_module_dir_to_diagnostics(ctx: Context):
141141

142142
yield
143143
mc_logger.removeFilter(local_filter) # clear the filter once done (after mecha)
144-
144+
145145

146146
def add_mecha_subproject_dir(record: logging.LogRecord, subproject_dir: str|Path = ""):
147147
if d:=getattr(record, "annotate"):

gm4/plugins/manifest.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from beet import Context, InvalidProjectConfig, PluginOptions, TextFile, load_config, Function
1414
from beet.library.base import _dump_files # type: ignore ; private method used to deterministicify pack dumping
1515
from nbtlib.contrib.minecraft import StructureFileData, StructureFile # type: ignore ; no stub
16-
from pydantic.v1 import BaseModel, Extra
16+
from pydantic import BaseModel
1717
from repro_zipfile import ReproducibleZipFile # type: ignore ; no stub
1818

1919
from gm4.plugins.versioning import VersioningConfig
@@ -41,17 +41,17 @@ class SmithedConfig(PluginOptions):
4141
class PMCConfig(PluginOptions):
4242
uid: int
4343

44-
class ManifestConfig(PluginOptions, extra=Extra.ignore):
44+
class ManifestConfig(PluginOptions, extra="ignore"):
4545
minecraft: list[str] = SUPPORTED_GAME_VERSIONS
46-
versioning: Optional[VersioningConfig]
46+
versioning: Optional[VersioningConfig] = None
4747
# distribution
48-
website: Optional[WebsiteConfig]
49-
modrinth: Optional[ModrinthConfig]
50-
smithed: Optional[SmithedConfig]
51-
pmc: Optional[PMCConfig]
48+
website: Optional[WebsiteConfig] = None
49+
modrinth: Optional[ModrinthConfig] = None
50+
smithed: Optional[SmithedConfig] = None
51+
pmc: Optional[PMCConfig] = None
5252
# promo
53-
video: str|None
54-
wiki: str|None
53+
video: str|None = None
54+
wiki: str|None = None
5555
credits: CreditsModel
5656

5757
# models for meta.json and cached manifest
@@ -102,7 +102,7 @@ def create(ctx: Context):
102102
for pack_id in [p.name for p in sorted(ctx.directory.glob(glob))]:
103103
try:
104104
config = load_config(Path(pack_id) / "beet.yaml")
105-
gm4_meta = ctx.validate("gm4", validator=ManifestConfig, options=config.meta["gm4"]) # manually parse config into models
105+
gm4_meta = ctx.validate("gm4", validator=ManifestConfig, options=config.meta["gm4"]) # manually parse config into models
106106

107107
manifest_section[pack_id] = ManifestModuleModel(
108108
id = config.id,
@@ -142,7 +142,7 @@ def create(ctx: Context):
142142
manifest.base = {"version": base_config["version"]}
143143

144144
# Cache the new manifest, so sub-pipelines can access it
145-
ctx.cache["gm4_manifest"].json = manifest.dict()
145+
ctx.cache["gm4_manifest"].json = manifest.model_dump()
146146

147147
# Read in the previous manifest, if found
148148
version = os.getenv("VERSION", "1.21.5")
@@ -158,21 +158,21 @@ def create(ctx: Context):
158158
sys.exit(1) # quit the build and mark the github action as failed
159159
else:
160160
logger.warning("No existing meta.json manifest file was located")
161-
ctx.cache["previous_manifest"].json = ManifestFileModel(last_commit="",modules=[],libraries={},contributors=[]).dict()
161+
ctx.cache["previous_manifest"].json = ManifestFileModel(last_commit="",modules=[],libraries={},contributors=[]).model_dump()
162+
162163

163-
164164

165165
def update_patch(ctx: Context):
166166
"""Checks the datapack files for changes from last build, and increments patch number"""
167167
yield
168168
logger = parent_logger.getChild("update_patch")
169169

170170
# load current manifest from cache
171-
this_manifest = ManifestCacheModel.parse_obj(ctx.cache["gm4_manifest"].json)
171+
this_manifest = ManifestCacheModel.model_validate(ctx.cache["gm4_manifest"].json)
172172
pack = ({e.id:e for e in (this_manifest.libraries|this_manifest.modules).values()})[ctx.project_id]
173173

174174
# attempt to load prior meta.json manifest
175-
last_manifest = ManifestFileModel.parse_obj(ctx.cache["previous_manifest"].json)
175+
last_manifest = ManifestFileModel.model_validate(ctx.cache["previous_manifest"].json)
176176
released_modules: dict[str, ManifestModuleModel] = {m.id:m for m in last_manifest.modules if m.version}|{l.id:l for l in last_manifest.libraries.values()}
177177

178178
# determine this modules status
@@ -214,7 +214,7 @@ def update_patch(ctx: Context):
214214
else: # no changes, keep the patch
215215
pack.version = released.version
216216

217-
ctx.cache["gm4_manifest"].json = this_manifest.dict()
217+
ctx.cache["gm4_manifest"].json = this_manifest.model_dump()
218218

219219

220220
def write_meta(ctx: Context):
@@ -232,7 +232,7 @@ def write_meta(ctx: Context):
232232

233233
def write_credits(ctx: Context):
234234
"""Writes the credits metadata to CREDITS.md. and collects for README.md"""
235-
manifest = ManifestCacheModel.parse_obj(ctx.cache["gm4_manifest"].json)
235+
manifest = ManifestCacheModel.model_validate(ctx.cache["gm4_manifest"].json)
236236
contributors = manifest.contributors
237237
module = manifest.modules.get(ctx.project_id)
238238
credits = module.credits if module else {}
@@ -254,7 +254,7 @@ def write_credits(ctx: Context):
254254
linked_credits[title].append(f"[{name}]({links[0]})")
255255
else:
256256
linked_credits[title].append(f"{name}")
257-
257+
258258
# format credits for CREDITS.md
259259
text = "# Credits\n"
260260
for title in linked_credits:
@@ -277,7 +277,7 @@ def write_update_function(init: Optional[Function], ctx: Context):
277277
if not init:
278278
return
279279

280-
manifest = ManifestCacheModel.parse_obj(ctx.cache["gm4_manifest"].json)
280+
manifest = ManifestCacheModel.model_validate(ctx.cache["gm4_manifest"].json)
281281
modules = manifest.modules
282282

283283
score = f"{ctx.project_id.removeprefix('gm4_')} gm4_modules"
@@ -309,7 +309,7 @@ def write_update_function(init: Optional[Function], ctx: Context):
309309

310310
def repro_structure_to_bytes(content: StructureFileData) -> bytes:
311311
"""a modified Structure.to_bytes from beet, which ensures the GZip does not add
312-
the current time.time to the nbt file header.
312+
the current time.time to the nbt file header.
313313
Used for deterministic pack builds and auto-patch detection"""
314314
dst = BytesIO()
315315
with GzipFile(fileobj=dst, mode="wb", mtime=0) as fileobj:

gm4/plugins/output.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def beet_default(ctx: Context):
2525
out_dir = Path("out")
2626

2727
yield # wait for exit phase, after other plugins cleanup
28-
28+
2929
ctx.data.save(
3030
path=out_dir / f"{ctx.project_id}_{version.replace('.', '_')}",
3131
overwrite=True,
@@ -73,7 +73,7 @@ def release(ctx: Context):
7373
"""
7474
Saves the zipped datapack and metadata to the ./release/{version} folder.
7575
Should be first in pipeline to properly wrap all other plugins cleanup phases
76-
76+
7777
If the module has the `version` and `meta.modrinth.project_id` fields, and
7878
`BEET_MODRINTH_TOKEN` environment variable is set, will try to publish a
7979
new version to Modrinth if it doesn't already exist.
@@ -90,7 +90,7 @@ def release(ctx: Context):
9090
file_name = f"{corrected_project_id}_{version_dir.replace('.', '_')}.zip"
9191

9292
yield # wait for exit phase, after other plugins cleanup
93-
93+
9494
ctx.data.save(
9595
path=release_dir / file_name,
9696
overwrite=True,
@@ -103,7 +103,7 @@ def release(ctx: Context):
103103
os.makedirs(pack_icon_dir, exist_ok=True)
104104
if "pack.png" in ctx.data.extra:
105105
ctx.data.extra["pack.png"].dump(pack_icon_dir, f"{corrected_project_id}.png")
106-
106+
107107
smithed_readme_dir = generated_dir / "smithed_readmes"
108108
os.makedirs(smithed_readme_dir, exist_ok=True)
109109
if "smithed_readme" in ctx.meta:
@@ -200,7 +200,7 @@ def publish_smithed(ctx: Context, config: ManifestConfig, file_name: str):
200200
auth_token = os.getenv(SMITHED_AUTH_KEY, None)
201201
logger = parent_logger.getChild(f"smithed.{ctx.project_id}")
202202
mc_version_dir = os.getenv("VERSION", "1.21.5")
203-
manifest = ManifestCacheModel.parse_obj(ctx.cache["gm4_manifest"].json)
203+
manifest = ManifestCacheModel.model_validate(ctx.cache["gm4_manifest"].json)
204204
project_id = stem if (stem:=ctx.directory.stem).startswith("lib") else ctx.project_id
205205

206206
if config.smithed and auth_token:
@@ -214,7 +214,7 @@ def publish_smithed(ctx: Context, config: ManifestConfig, file_name: str):
214214
else:
215215
logger.warning(f"Failed to get project: {res.status_code} {res.text}")
216216
return
217-
217+
218218
project_data = res.json()
219219

220220
# update description and pack image
@@ -307,10 +307,10 @@ def clear_release(ctx: Context):
307307

308308
def readmes(ctx: Context):
309309
"""Saves all READMEs intended for download sites to the ./out/readmes folder."""
310-
310+
311311
readme_dir = Path("out/readmes")
312312
base_path = readme_dir / ctx.project_id
313-
313+
314314
if "README.md" in ctx.data.extra:
315315
os.makedirs(base_path, exist_ok=True)
316316
ctx.data.extra["README.md"].dump(base_path, "GM4_README.md")

gm4/plugins/prefabs.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
from beet import Context, PluginOptions, configurable
22
from beet.contrib.find_replace import find_replace
33
from beet.contrib.rename_files import rename_files
4-
from pydantic.v1 import Extra
54
import nbtlib # type: ignore ; no stub file
65
import re
76
from gm4.plugins.manifest import repro_structure_to_bytes
87

98

10-
class PrefabConfig(PluginOptions, extra=Extra.ignore):
9+
class PrefabConfig(PluginOptions, extra="ignore"):
1110
prefabs: list[str]
1211

1312
def beet_default(ctx: Context):
1413
"""Handles renaming of prefab assets as they merge into a for modules use"""
1514
prefab_namespace = ctx.project_id
1615
module_namsepace = ctx.cache["currently_building"].json["id"]
17-
16+
1817
structure_deep_rename(ctx, prefab_namespace, module_namsepace)
1918

2019
@configurable("gm4", validator=PrefabConfig)

0 commit comments

Comments
 (0)