fbxkit 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
fbxkit/__about__.py ADDED
@@ -0,0 +1,7 @@
1
+ """The single definition of the package version.
2
+
3
+ ``pyproject.toml`` reads it via ``dynamic = ["version"]``; nothing else in the
4
+ tree is allowed to hard-code it (``tests/test_packaging.py`` enforces that).
5
+ """
6
+
7
+ __version__ = "0.1.0"
fbxkit/__init__.py ADDED
@@ -0,0 +1,210 @@
1
+ """fbxkit -- lightweight, general-purpose CRUD for FBX files.
2
+
3
+ import fbxkit
4
+
5
+ with fbxkit.open("hero.fbx") as doc:
6
+ for node in doc.select("**[type=mesh]"): # 查
7
+ print(node.path)
8
+ doc.create("locator", parent="|root") # 增
9
+ doc.rename("**[type=mesh]", pattern="^SM_", replacement="") # 改
10
+ doc.delete("**|*_ref", required=False) # 删
11
+ doc.save() # same format, same version
12
+
13
+ The package is layered so that only one module in it imports the Autodesk SDK::
14
+
15
+ schema / selectors / params / serialize pure data and pure logic
16
+ ops / builtin_ops / patch operations, and patches as data
17
+ session/protocol.py the interface an operation may use
18
+ session/fbx.py <- the only import fbx | session/fake.py <- the stand-in
19
+ document.py / io.py / cli.py lifetime, disk facts, the CLI
20
+
21
+ Which means everything except actually opening a file runs, and is tested, on an
22
+ interpreter with no SDK installed at all.
23
+
24
+ **Logging.** The package attaches a ``NullHandler`` and stays silent; every call
25
+ is at DEBUG level, because a library that writes to its host's log at INFO ends
26
+ up in an artist's script editor. To look::
27
+
28
+ import logging
29
+ logging.basicConfig()
30
+ logging.getLogger("fbxkit").setLevel(logging.DEBUG)
31
+ """
32
+
33
+ import logging as _logging
34
+
35
+ # Importing this module is what puts the builtin operations in the registry.
36
+ from . import builtin_ops as _builtin_ops # noqa: F401 (imported for its side effect)
37
+ from .__about__ import __version__
38
+ from .document import FbxDocument, open_document
39
+ from .errors import (
40
+ AmbiguousMatch,
41
+ DocumentClosed,
42
+ FbxkitError,
43
+ FileOpenError,
44
+ FileSaveError,
45
+ NoMatch,
46
+ OperationError,
47
+ ParamError,
48
+ SchemaVersionError,
49
+ SdkUnavailable,
50
+ SelectorError,
51
+ UnknownOperation,
52
+ )
53
+ from .io import EXPORT_VERSIONS, file_info, sniff_format
54
+ from .ops import Operation, OperationRegistry, register, registry
55
+ from .patch import Patch, apply_operations, load_patch, loads_patch
56
+ from .schema import (
57
+ SCHEMA_VERSION,
58
+ Change,
59
+ Counters,
60
+ Diagnostic,
61
+ FileInfo,
62
+ MaterialInfo,
63
+ MeshInfo,
64
+ NodeInfo,
65
+ OperationReport,
66
+ PatchResult,
67
+ PropertyInfo,
68
+ SceneDocument,
69
+ SceneSettings,
70
+ TakeInfo,
71
+ TextureInfo,
72
+ )
73
+ from .selectors import Selector
74
+ from .serialize import dump, dumps, load, loads
75
+ from .session import FakeSession, NodeRef, SessionProtocol, demo_session, have_sdk
76
+
77
+ _logging.getLogger(__name__).addHandler(_logging.NullHandler())
78
+
79
+ __all__ = [
80
+ "__version__",
81
+ "SCHEMA_VERSION",
82
+ # entry points
83
+ "open",
84
+ "open_document",
85
+ "new",
86
+ "read",
87
+ "patch_file",
88
+ "FbxDocument",
89
+ # patches and operations
90
+ "Patch",
91
+ "apply_operations",
92
+ "load_patch",
93
+ "loads_patch",
94
+ "Operation",
95
+ "OperationRegistry",
96
+ "register",
97
+ "registry",
98
+ "available",
99
+ # selection
100
+ "Selector",
101
+ "NodeRef",
102
+ # schema
103
+ "SceneDocument",
104
+ "PatchResult",
105
+ "OperationReport",
106
+ "Change",
107
+ "NodeInfo",
108
+ "MeshInfo",
109
+ "MaterialInfo",
110
+ "TextureInfo",
111
+ "TakeInfo",
112
+ "SceneSettings",
113
+ "Counters",
114
+ "Diagnostic",
115
+ "FileInfo",
116
+ "PropertyInfo",
117
+ # serialization
118
+ "dumps",
119
+ "dump",
120
+ "loads",
121
+ "load",
122
+ # sessions
123
+ "SessionProtocol",
124
+ "FakeSession",
125
+ "demo_session",
126
+ "have_sdk",
127
+ # files
128
+ "file_info",
129
+ "sniff_format",
130
+ "EXPORT_VERSIONS",
131
+ # errors
132
+ "FbxkitError",
133
+ "SdkUnavailable",
134
+ "FileOpenError",
135
+ "FileSaveError",
136
+ "SelectorError",
137
+ "NoMatch",
138
+ "AmbiguousMatch",
139
+ "ParamError",
140
+ "UnknownOperation",
141
+ "OperationError",
142
+ "SchemaVersionError",
143
+ "DocumentClosed",
144
+ ]
145
+
146
+ def open(path, compute_hash=True): # noqa: A001 -- fbxkit.open reads best at the call site
147
+ """Open an FBX file for reading and editing.
148
+
149
+ Use it as a context manager. The scene holds an ``FbxManager`` that must be
150
+ destroyed exactly once, and ``with`` is what guarantees that::
151
+
152
+ with fbxkit.open("hero.fbx") as doc:
153
+ ...
154
+
155
+ Raises :class:`FileOpenError` with a reason that names the actual cause --
156
+ the SDK reports a missing file, an empty file, a truncated file and a file
157
+ of unrelated bytes with one identical message, so fbxkit checks the disk
158
+ first.
159
+ """
160
+ return open_document(path, compute_hash=compute_hash)
161
+
162
+
163
+ def new():
164
+ """An empty scene, for building a file from nothing."""
165
+ from .session.fbx import FbxSession
166
+
167
+ return FbxDocument(FbxSession.empty())
168
+
169
+
170
+ def read(path, include_properties=False, compute_hash=True):
171
+ """Open, snapshot and close in one call -- the read-only path.
172
+
173
+ Returns a :class:`SceneDocument`: everything about the scene as plain data,
174
+ with the file already closed. This is the shape a backend stores and the one
175
+ a diff compares.
176
+ """
177
+ with open(path, compute_hash=compute_hash) as document:
178
+ return document.document(include_properties=include_properties)
179
+
180
+
181
+ def patch_file(path, ops, output=None, dry_run=False, atomic=True, **save_args):
182
+ """Apply a patch to a file and write the result. The batch entry point.
183
+
184
+ Nothing is written when the patch does not fully succeed, so the file on
185
+ disk is either fully patched or untouched::
186
+
187
+ result = fbxkit.patch_file("hero.fbx", [
188
+ {"op": "rename", "target": "**[type=mesh]",
189
+ "pattern": "^SM_", "replacement": ""},
190
+ {"op": "retarget_textures", "prefix": "//server/proj/tex"},
191
+ ], output="hero_clean.fbx")
192
+
193
+ result.status # "ok" | "partial" | "error"
194
+ result.changed # how many individual changes were made
195
+ result.saved # whether the file was actually written
196
+ """
197
+ with open(path) as document:
198
+ return document.apply_and_save(
199
+ ops, path=output, dry_run=dry_run, atomic=atomic, **save_args
200
+ )
201
+
202
+
203
+ def available():
204
+ """Every registered operation and its parameters, as data.
205
+
206
+ Serve this straight to a frontend to generate a form or validate a request,
207
+ instead of transcribing the parameter list on both sides and having the
208
+ copies go stale.
209
+ """
210
+ return registry.available()
fbxkit/__main__.py ADDED
@@ -0,0 +1,8 @@
1
+ """``python -m fbxkit`` -- the same entry point as the ``fbxkit`` console script."""
2
+
3
+ import sys
4
+
5
+ from .cli import main
6
+
7
+ if __name__ == "__main__":
8
+ sys.exit(main())