Skip to content

Commit 6d1151d

Browse files
committed
tools: deprecation checks, format string items, set min version, better logs
1 parent 9693f33 commit 6d1151d

File tree

2 files changed

+65
-28
lines changed

2 files changed

+65
-28
lines changed

tools/node_settings_generator/parse_nodes.py

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,40 @@ class NodeInfo(NamedTuple):
3737
types_dict : dict[str, set[str]] = {}
3838
log_file = None
3939

40-
NTP_MIN_VERSION = (3, 0)
40+
BLENDER_3_MAX_VERSION = 6
41+
BLENDER_4_MAX_VERSION = 5
42+
BLENDER_5_MAX_VERSION = 0
43+
44+
NTP_MIN_VERSION = Version(3, 0)
45+
46+
BLENDER_VERSIONS = [Version(3, i) for i in range(0, BLENDER_3_MAX_VERSION + 1)]
47+
BLENDER_VERSIONS += [Version(4, i) for i in range(0, BLENDER_4_MAX_VERSION + 1)]
48+
BLENDER_VERSIONS += [Version(5, i) for i in range(0, BLENDER_5_MAX_VERSION + 1)]
49+
50+
def log(message: str):
51+
if log_file is None:
52+
raise RuntimeError("Log file was null!")
53+
with log_mutex:
54+
log_file.write(message)
4155

4256
def process_attr(attr, section, node: str, version: Version) -> None:
57+
# Get name
4358
name_section = attr.find(["code", "span"], class_="sig-name descname")
44-
4559
if not name_section:
4660
raise ValueError(f"{version.tuple_str()} {node}: Couldn't find name section in\n\t{section}")
4761
name = name_section.text
62+
63+
# Check for deprecation
64+
if "Deprecated" in str(attr):
65+
log(f"WARNING: {version.tuple_str()} Attribute {node}.{name} "
66+
f"was marked deprecated, returning\n")
67+
return
4868

69+
# Get type
4970
type_section = attr.find("dd", class_="field-odd")
5071
if not type_section:
51-
raise ValueError(f"{version.tuple_str()} {node}.{name}: Couldn't find type section in\n\t{section}")
72+
raise ValueError(f"{version.tuple_str()} {node}.{name}: "
73+
f"Couldn't find type section in\n\t{section}")
5274
type_text = type_section.text
5375

5476
with mutex:
@@ -61,8 +83,8 @@ def process_attr(attr, section, node: str, version: Version) -> None:
6183
ntp_type = types_utils.get_NTP_type(type_text)
6284
if ntp_type is None:
6385
# Read-only attribute, don't add to attribute list
64-
with log_mutex:
65-
log_file.write(f"WARNING: {version.tuple_str()} {node}.{name}'s type is being ignored:\n\t{type_text.strip()}\n")
86+
log(f"WARNING: {version.tuple_str()} {node}.{name}'s "
87+
f"type is being ignored:\n\t{type_text.strip()}\n")
6688
return
6789

6890
ntp_setting = NTPNodeSetting(name, ntp_type)
@@ -114,7 +136,7 @@ def download_file(filepath: str, version: Version, local_path: str) -> bool:
114136

115137

116138
def get_subclasses(current: str, parent: str, root_path: str,
117-
version: Version) -> list[str]:
139+
version: Version) -> None:
118140
relative_path = f"bpy.types.{current}.html"
119141
current_path = os.path.join(root_path, relative_path)
120142

@@ -132,12 +154,14 @@ def get_subclasses(current: str, parent: str, root_path: str,
132154
main_id = f"{current.lower()}-{parent.lower()}"
133155
sections = soup.find_all(id=main_id)
134156
if not sections:
135-
raise ValueError(f"{version.tuple_str()} {current}: Couldn't find main section with id {main_id}")
157+
raise ValueError(f"{version.tuple_str()} {current}: "
158+
f"Couldn't find main section with id {main_id}")
136159

137160
section = sections[0]
138161
paragraphs = section.find_all("p")
139162
if len(paragraphs) < 2:
140-
raise ValueError(f"{version.tuple_str()} {current}: Couldn't find subclass section")
163+
raise ValueError(f"{version.tuple_str()} {current}: "
164+
f"Couldn't find subclass section")
141165

142166
subclasses_paragraph = paragraphs[1]
143167
if not subclasses_paragraph.text.strip().startswith("subclasses —"):
@@ -147,7 +171,8 @@ def get_subclasses(current: str, parent: str, root_path: str,
147171

148172
subclass_anchors = subclasses_paragraph.find_all("a")
149173
if not subclass_anchors:
150-
raise ValueError(f"{version.tuple_str()} {current} No anchors in subclasses paragraph")
174+
raise ValueError(f"{version.tuple_str()} {current} "
175+
f"No anchors in subclasses paragraph")
151176

152177
subclass_types = [anchor.get("title") for anchor in subclass_anchors]
153178
threads: list[Thread] = []
@@ -156,13 +181,15 @@ def get_subclasses(current: str, parent: str, root_path: str,
156181
raise ValueError(f"{version.tuple_str()} {current} Type was invalid")
157182
is_matching = re.match(r"bpy\.types\.(.*)", type)
158183
if not is_matching:
159-
raise ValueError(f"{version.tuple_str()} {current}: Type {type} was not of the form \"bpy.types.x\"")
184+
raise ValueError(f"{version.tuple_str()} {current}: "
185+
f"Type {type} was not of the form \"bpy.types.x\"")
160186
pure_type = is_matching.group(1)
161187
if (pure_type == "TextureNode"):
162188
# unsupported
163189
continue
164190

165-
thread = Thread(target=get_subclasses, args=(pure_type, current, root_path, version))
191+
thread = Thread(target=get_subclasses,
192+
args=(pure_type, current, root_path, version))
166193
threads.append(thread)
167194
thread.start()
168195

@@ -180,24 +207,21 @@ def process_bpy_version(version: Version) -> None:
180207
get_subclasses(current, parent, root_path, version)
181208

182209
def generate_versions(max_version_inc: Version) -> list[Version]:
183-
BLENDER_3_MAX_VERSION = 6
184-
BLENDER_4_MAX_VERSION = 5
210+
versions = BLENDER_VERSIONS.copy()
185211

186-
versions = [Version(3, i) for i in range(0, BLENDER_3_MAX_VERSION + 1)]
187-
versions += [Version(4, i) for i in range(0, BLENDER_4_MAX_VERSION + 1)]
188-
versions += [Version(5, i) for i in range(0, max_version_inc.minor_ + 1)]
189-
190-
#lazy max version check
212+
# lazy version bounds check
191213
for version in versions[::-1]:
192214
if version > max_version_inc:
193215
versions.remove(version)
216+
if version < NTP_MIN_VERSION:
217+
versions.remove(version)
194218

195219
return versions
196220

197221
def subminor(version: Version) -> tuple:
198222
return (version[0], version[1], 0)
199223

200-
def get_min_version(versions: list[Version]) -> Version:
224+
def get_min_version(versions: list[Version]) -> Version | None:
201225
min_version = min(versions)
202226

203227
if min_version != NTP_MIN_VERSION:
@@ -206,7 +230,7 @@ def get_min_version(versions: list[Version]) -> Version:
206230
return None
207231

208232
def get_max_version(versions: list[Version], blender_versions: list[Version]
209-
) -> Version:
233+
) -> Version | None:
210234
max_v_inclusive = max(versions)
211235
max_v_inclusive_index = blender_versions.index(max_v_inclusive)
212236
max_v_exclusive = blender_versions[max_v_inclusive_index + 1]
@@ -246,7 +270,8 @@ def write_node_info_class(file: TextIOWrapper):
246270
file.write("\n")
247271

248272
def write_ntp_node_settings(node_info: NodeInfo, file: TextIOWrapper,
249-
node_min_v: Version, node_max_v: Version):
273+
node_min_v: Version | None,
274+
node_max_v: Version | None) -> None:
250275
attr_dict = node_info.attributes_
251276
file.write("\n\t\t[")
252277
attrs_exist = len(attr_dict.items()) > 0
@@ -286,6 +311,14 @@ def write_node(name: str, node_info: NodeInfo, file: TextIOWrapper):
286311

287312
file.write("\n\t),\n\n")
288313

314+
def get_max_version_exc(max_version_inc : Version) -> Version:
315+
idx = BLENDER_VERSIONS.index(max_version_inc)
316+
exc_idx = idx + 1
317+
if exc_idx < len(BLENDER_VERSIONS):
318+
return BLENDER_VERSIONS[exc_idx]
319+
else:
320+
return Version(max_version_inc.major_, max_version_inc.minor_ + 1)
321+
289322
if __name__ == "__main__":
290323
parser = argparse.ArgumentParser()
291324
parser.add_argument('max_major_version', type=int,
@@ -312,7 +345,8 @@ def write_node(name: str, node_info: NodeInfo, file: TextIOWrapper):
312345
for version in versions:
313346
process_bpy_version(version)
314347

315-
NTP_MAX_VERSION_EXC = (NTP_MAX_VERSION_INC[0], NTP_MAX_VERSION_INC[1] + 1)
348+
NTP_MAX_VERSION_EXC = get_max_version_exc(NTP_MAX_VERSION_INC)
349+
316350
versions.append(NTP_MAX_VERSION_EXC)
317351

318352
sorted_nodes = dict(sorted(nodes_dict.items()))
@@ -340,8 +374,8 @@ def write_node(name: str, node_info: NodeInfo, file: TextIOWrapper):
340374
print("Successfully finished")
341375

342376
sorted_types = dict(sorted(types_dict.items()))
343-
log_file.write("\nTypes encountered:\n")
377+
log("\nTypes encountered:\n")
344378
for key, value in types_dict.items():
345-
log_file.write(f"{key}\n")
379+
log(f"{key}\n")
346380
for string in value:
347-
log_file.write(f"\t{string}\n")
381+
log(f"\t{string}\n")

tools/node_settings_generator/types_utils.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class ST(Enum):
2828
FOREACH_GEO_ELEMENT_GENERATION_ITEMS = auto()
2929
FOREACH_GEO_ELEMENT_INPUT_ITEMS = auto()
3030
FOREACH_GEO_ELEMENT_MAIN_ITEMS = auto()
31+
FORMAT_STRING_ITEMS = auto()
3132
INDEX_SWITCH_ITEMS = auto()
3233
MENU_SWITCH_ITEMS = auto()
3334
NODE_TREE = auto()
@@ -66,6 +67,7 @@ class ST(Enum):
6667
ST.FOREACH_GEO_ELEMENT_GENERATION_ITEMS,
6768
ST.FOREACH_GEO_ELEMENT_INPUT_ITEMS,
6869
ST.FOREACH_GEO_ELEMENT_MAIN_ITEMS,
70+
ST.FORMAT_STRING_ITEMS,
6971
ST.IMAGE_FORMAT_SETTINGS,
7072
ST.IMAGE_USER,
7173
ST.INDEX_SWITCH_ITEMS,
@@ -75,8 +77,8 @@ class ST(Enum):
7577
ST.SIM_OUTPUT_ITEMS,
7678
}
7779

78-
doc_to_NTP_type_dict : dict[str, ST] = {
79-
"" : "",
80+
doc_to_NTP_type_dict : dict[str, ST | None] = {
81+
"" : None,
8082
"bpy_prop_collection of CryptomatteEntry": ST.CRYPTOMATTE_ENTRIES,
8183
"boolean" : ST.BOOL,
8284
"Collection" : ST.COLLECTION,
@@ -106,6 +108,7 @@ class ST(Enum):
106108
# output nodes exist. Handled separately from NTP attr system
107109
"NodeEnumDefinition" : ST.ENUM_DEFINITION,
108110
"NodeEnumItem" : ST.ENUM_ITEM,
111+
"NodeFunctionFormatStringItems" : ST.FORMAT_STRING_ITEMS,
109112
"NodeGeometryBakeItems" : ST.BAKE_ITEMS,
110113
"NodeGeometryCaptureAttributeItems" : ST.CAPTURE_ATTRIBUTE_ITEMS,
111114
"NodeGeometryForeachGeometryElementGenerationItems": ST.FOREACH_GEO_ELEMENT_GENERATION_ITEMS,
@@ -129,7 +132,7 @@ class ST(Enum):
129132
"VectorFont" : ST.FONT
130133
}
131134

132-
def get_NTP_type(type_str: str) -> str:
135+
def get_NTP_type(type_str: str) -> ST | None:
133136
"""
134137
Time complexity isn't great, might be able to optimize with
135138
a trie or similar data structure

0 commit comments

Comments
 (0)