unitytk 0.0.7__tar.gz → 0.0.9__tar.gz
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.
- {unitytk-0.0.7/unitytk.egg-info → unitytk-0.0.9}/PKG-INFO +4 -4
- {unitytk-0.0.7 → unitytk-0.0.9}/docs/README.md +1 -1
- {unitytk-0.0.7 → unitytk-0.0.9}/pyproject.toml +19 -2
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_audio_events_integration.py +36 -118
- unitytk-0.0.9/test/test_base_test.py +617 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_bool_to_fade_curve.py +0 -1
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_clip_name_contract_integration.py +21 -29
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_controller_runtime_integration.py +12 -19
- unitytk-0.0.9/test/test_deploy_templates.py +412 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_emissive_groups_integration.py +23 -35
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_fade_window_preservation.py +13 -21
- unitytk-0.0.7/test/test_c5m_visibility.py → unitytk-0.0.9/test/test_keyed_visibility.py +52 -23
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_lightmap_metadata_integration.py +32 -97
- unitytk-0.0.7/test/test_c130_fcr_integration.py → unitytk-0.0.9/test/test_multi_section_audio_integration.py +85 -116
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_render_opacity_controller.py +14 -23
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_render_opacity_e2e.py +16 -22
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_render_opacity_integration.py +14 -21
- unitytk-0.0.9/test/test_run_tests.py +271 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_shadow_plane_integration.py +21 -34
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_shared_material_standalone.py +16 -15
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_shot_metadata_integration.py +34 -100
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_shots_audio_sidebyside_integration.py +35 -97
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_standalone_enduser.py +40 -33
- unitytk-0.0.9/test/test_temp_projects.py +121 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/__init__.py +3 -2
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/launcher.py +5 -4
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/scene_builder.py +3 -2
- unitytk-0.0.9/unitytk/template_deployer.py +628 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/templates/AudioEventController.cs +1 -1
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/templates/README.md +14 -4
- {unitytk-0.0.7 → unitytk-0.0.9/unitytk.egg-info}/PKG-INFO +4 -4
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk.egg-info/SOURCES.txt +5 -2
- unitytk-0.0.7/test/test_deploy_templates.py +0 -198
- unitytk-0.0.7/unitytk/template_deployer.py +0 -237
- {unitytk-0.0.7 → unitytk-0.0.9}/LICENSE +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/MANIFEST.in +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/setup.cfg +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_asset_delivery.py +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_launcher.py +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/test/test_scene_builder.py +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/asset_delivery.py +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/templates/EmissiveGroupController.cs +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/templates/EmissiveGroups.hlsl +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/templates/EmissiveGroupsLit.shader +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/templates/LightmapMetadataController.cs +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/templates/M3trik.Unitytk.asmdef +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/templates/RenderOpacityController.cs +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/templates/ShadowPlaneController.cs +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/templates/ShotMetadataController.cs +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/templates/UnitytkSettings.cs +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk/templates/__init__.py +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk.egg-info/dependency_links.txt +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk.egg-info/requires.txt +0 -0
- {unitytk-0.0.7 → unitytk-0.0.9}/unitytk.egg-info/top_level.txt +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: unitytk
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.9
|
|
4
4
|
Summary: A modular Python toolkit for Unity interaction.
|
|
5
5
|
Author-email: Ryan Simpson <m3trik@outlook.com>
|
|
6
6
|
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/
|
|
8
|
-
Project-URL: Repository, https://github.com/
|
|
7
|
+
Project-URL: Homepage, https://github.com/m3trik/unitytk
|
|
8
|
+
Project-URL: Repository, https://github.com/m3trik/unitytk
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
10
|
Classifier: License :: OSI Approved :: MIT License
|
|
11
11
|
Classifier: Operating System :: OS Independent
|
|
@@ -15,7 +15,7 @@ License-File: LICENSE
|
|
|
15
15
|
Requires-Dist: pythontk>=0.7.71
|
|
16
16
|
Dynamic: license-file
|
|
17
17
|
|
|
18
|
-
[](../test/)
|
|
19
19
|
|
|
20
20
|
# unitytk
|
|
21
21
|
|
|
@@ -17,8 +17,8 @@ classifiers = [
|
|
|
17
17
|
dependencies = ["pythontk>=0.7.71"]
|
|
18
18
|
|
|
19
19
|
[project.urls]
|
|
20
|
-
Homepage = "https://github.com/
|
|
21
|
-
Repository = "https://github.com/
|
|
20
|
+
Homepage = "https://github.com/m3trik/unitytk"
|
|
21
|
+
Repository = "https://github.com/m3trik/unitytk"
|
|
22
22
|
|
|
23
23
|
[tool.setuptools.dynamic]
|
|
24
24
|
version = {attr = "unitytk.__version__"}
|
|
@@ -30,3 +30,20 @@ include = ["unitytk*"]
|
|
|
30
30
|
|
|
31
31
|
[tool.setuptools.package-data]
|
|
32
32
|
"*" = ["*.ui", "*.json", "*.txt", "*.md", "*.cs", "*.hlsl", "*.shader", "*.asmdef"]
|
|
33
|
+
|
|
34
|
+
[tool.pytest.ini_options]
|
|
35
|
+
testpaths = ["test"]
|
|
36
|
+
pythonpath = [".", "test"]
|
|
37
|
+
addopts = "--ignore=test/temp_tests"
|
|
38
|
+
|
|
39
|
+
[tool.ruff]
|
|
40
|
+
# House formatter/linter - rule set, exemptions and gate status: m3trik/docs/CODE_STANDARD.md section 1.
|
|
41
|
+
line-length = 88
|
|
42
|
+
target-version = "py39"
|
|
43
|
+
|
|
44
|
+
[tool.ruff.lint]
|
|
45
|
+
select = ["E4", "E7", "E9", "F"]
|
|
46
|
+
ignore = ["E402"] # house pattern: try-guarded DCC imports precede the other imports
|
|
47
|
+
|
|
48
|
+
[tool.ruff.lint.per-file-ignores]
|
|
49
|
+
"**/templates/**" = ["F821"] # exec-templates carry __PLACEHOLDER__ tokens substituted at run time
|
|
@@ -28,24 +28,24 @@ import os
|
|
|
28
28
|
import sys
|
|
29
29
|
import json
|
|
30
30
|
import shutil
|
|
31
|
-
import tempfile
|
|
32
31
|
import unittest
|
|
33
32
|
import subprocess
|
|
34
33
|
import logging
|
|
35
34
|
|
|
36
35
|
logger = logging.getLogger(__name__)
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
sys.path.insert(0, scripts_dir)
|
|
37
|
+
import base_test # noqa: F401 — sys.path bootstrap for the sibling repos
|
|
38
|
+
from base_test import EnvSkip, MayaEnv, TempProjects, UnityEnv, UserPropsProbe
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
MAYAPY = r"C:\Program Files\Autodesk\Maya2025\bin\mayapy.exe"
|
|
40
|
+
scripts_dir = base_test.SCRIPTS_ROOT
|
|
45
41
|
|
|
42
|
+
from unitytk import UnityLauncher, UnityFinder, TemplateDeployer
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
#: Resolved per machine -- UNITYTK_MAYAPY/MAYATK_MAYAPY, then the newest
|
|
45
|
+
#: standard install, then PATH (base_test.MayaEnv, same shape as mayatk's
|
|
46
|
+
#: runner). Pinning one install path made every gate below skip silently on
|
|
47
|
+
#: any other machine while the run still reported green.
|
|
48
|
+
MAYAPY = MayaEnv.mayapy()
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
def _unity_available() -> bool:
|
|
@@ -60,9 +60,7 @@ MAYA_EXPORT_SCRIPT = r'''
|
|
|
60
60
|
"""Executed inside mayapy — keys audio tracks on data_internal and bakes the manifest."""
|
|
61
61
|
import sys, os, json
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
if pkg_dir not in sys.path:
|
|
65
|
-
sys.path.insert(0, pkg_dir)
|
|
63
|
+
# mayatk/pythontk repo roots arrive via PYTHONPATH set by the parent test.
|
|
66
64
|
|
|
67
65
|
import maya.standalone
|
|
68
66
|
maya.standalone.initialize(name="python")
|
|
@@ -144,72 +142,11 @@ maya.standalone.uninitialize()
|
|
|
144
142
|
# Unity-side C# scripts
|
|
145
143
|
# ======================================================================
|
|
146
144
|
|
|
147
|
-
#
|
|
148
|
-
#
|
|
149
|
-
#
|
|
150
|
-
#
|
|
151
|
-
#
|
|
152
|
-
UNITY_POSTPROCESSOR_CS = r"""
|
|
153
|
-
using UnityEngine;
|
|
154
|
-
using UnityEditor;
|
|
155
|
-
using System.IO;
|
|
156
|
-
using System.Collections.Generic;
|
|
157
|
-
|
|
158
|
-
public class AudioEventTestPostprocessor : AssetPostprocessor
|
|
159
|
-
{
|
|
160
|
-
const string RESULTS_DIR = @"__RESULTS_DIR__";
|
|
161
|
-
|
|
162
|
-
// Static so it survives across postprocessor invocations within the
|
|
163
|
-
// same Unity editor session. Each GameObject with user-properties
|
|
164
|
-
// triggers OnPostprocessGameObjectWithUserProperties once, and we
|
|
165
|
-
// accumulate them all here before rewriting the JSON file.
|
|
166
|
-
static readonly Dictionary<string, Dictionary<string, string>> _all =
|
|
167
|
-
new Dictionary<string, Dictionary<string, string>>();
|
|
168
|
-
|
|
169
|
-
void OnPreprocessModel()
|
|
170
|
-
{
|
|
171
|
-
var importer = assetImporter as ModelImporter;
|
|
172
|
-
if (importer != null && !importer.importAnimatedCustomProperties)
|
|
173
|
-
importer.importAnimatedCustomProperties = true;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
void OnPostprocessGameObjectWithUserProperties(
|
|
177
|
-
GameObject go, string[] propNames, object[] values)
|
|
178
|
-
{
|
|
179
|
-
var props = new Dictionary<string, string>();
|
|
180
|
-
for (int i = 0; i < propNames.Length; i++)
|
|
181
|
-
{
|
|
182
|
-
string valStr = values[i] != null ? values[i].ToString() : "null";
|
|
183
|
-
props[propNames[i]] = valStr;
|
|
184
|
-
}
|
|
185
|
-
_all[go.name] = props;
|
|
186
|
-
|
|
187
|
-
string outPath = Path.Combine(RESULTS_DIR, "postprocessor_results.json");
|
|
188
|
-
File.WriteAllText(outPath, DictToJson(_all));
|
|
189
|
-
Debug.Log("[AudioEventTest] Captured " + propNames.Length
|
|
190
|
-
+ " user properties on " + go.name);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
static string DictToJson(Dictionary<string, Dictionary<string, string>> all)
|
|
194
|
-
{
|
|
195
|
-
var outer = new List<string>();
|
|
196
|
-
foreach (var go in all)
|
|
197
|
-
{
|
|
198
|
-
var inner = new List<string>();
|
|
199
|
-
foreach (var kv in go.Value)
|
|
200
|
-
inner.Add(" \"" + Escape(kv.Key) + "\": \"" + Escape(kv.Value) + "\"");
|
|
201
|
-
outer.Add(" \"" + Escape(go.Key) + "\": {\n"
|
|
202
|
-
+ string.Join(",\n", inner) + "\n }");
|
|
203
|
-
}
|
|
204
|
-
return "{\n" + string.Join(",\n", outer) + "\n}";
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
static string Escape(string s)
|
|
208
|
-
{
|
|
209
|
-
return s.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n");
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
"""
|
|
145
|
+
# The user-properties probe is the ONE shared template - see
|
|
146
|
+
# base_test.UserPropsProbe. Five suites each carried a near-identical copy,
|
|
147
|
+
# and the two halves of the carrier lookup had drifted (C# matched
|
|
148
|
+
# data_export by equality, Python by prefix), so one run could answer
|
|
149
|
+
# "is the carrier there?" two ways.
|
|
213
150
|
|
|
214
151
|
UNITY_VERIFIER_CS = r"""
|
|
215
152
|
using UnityEngine;
|
|
@@ -221,6 +158,7 @@ using System.Collections.Generic;
|
|
|
221
158
|
|
|
222
159
|
public class AudioEventTestVerifier
|
|
223
160
|
{
|
|
161
|
+
__CARRIER_MATCH__
|
|
224
162
|
public static void Verify()
|
|
225
163
|
{
|
|
226
164
|
string resultsFile = @"__RESULTS_PATH__";
|
|
@@ -263,7 +201,7 @@ public class AudioEventTestVerifier
|
|
|
263
201
|
foreach (var t in prefab.GetComponentsInChildren<Transform>(true))
|
|
264
202
|
{
|
|
265
203
|
goNames.Add(t.name);
|
|
266
|
-
if (dataExport == null && t.name
|
|
204
|
+
if (dataExport == null && IsCarrier(t.name))
|
|
267
205
|
dataExport = t;
|
|
268
206
|
}
|
|
269
207
|
}
|
|
@@ -462,11 +400,7 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
462
400
|
|
|
463
401
|
@classmethod
|
|
464
402
|
def setUpClass(cls):
|
|
465
|
-
|
|
466
|
-
# these preserve a full Unity project on purpose.
|
|
467
|
-
_temp_base = os.path.join(os.path.dirname(__file__), "temp_tests")
|
|
468
|
-
os.makedirs(_temp_base, exist_ok=True)
|
|
469
|
-
cls.temp_dir = tempfile.mkdtemp(prefix="audio_events_integ_", dir=_temp_base)
|
|
403
|
+
cls.temp_dir = TempProjects.allocate("audio_events_integ")
|
|
470
404
|
cls.fbx_path = None
|
|
471
405
|
cls.maya_results = None
|
|
472
406
|
cls.unity_results = None
|
|
@@ -481,7 +415,7 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
481
415
|
# Step 1: Maya export via AudioClips.prepare_for_export
|
|
482
416
|
# ------------------------------------------------------------------
|
|
483
417
|
|
|
484
|
-
@
|
|
418
|
+
@MayaEnv.skip_unless_available()
|
|
485
419
|
def test_01_maya_export(self):
|
|
486
420
|
"""Author tracks via AudioUtils, bake manifest via AudioClips, export FBX."""
|
|
487
421
|
script_path = os.path.join(self.temp_dir, "maya_export.py")
|
|
@@ -540,8 +474,8 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
540
474
|
# Step 2: Unity import and readback
|
|
541
475
|
# ------------------------------------------------------------------
|
|
542
476
|
|
|
543
|
-
@
|
|
544
|
-
@
|
|
477
|
+
@MayaEnv.skip_unless_available()
|
|
478
|
+
@EnvSkip.unless(_unity_available(), "no Unity editor found")
|
|
545
479
|
def test_02_unity_import(self):
|
|
546
480
|
"""Import FBX with real controllers deployed; verify manifest + auto-attach."""
|
|
547
481
|
fbx_path = self.__class__.fbx_path
|
|
@@ -557,11 +491,7 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
557
491
|
|
|
558
492
|
logger.info(f"Creating Unity project: {project_path}")
|
|
559
493
|
if not launcher.create_project(project_path, batch_mode=True):
|
|
560
|
-
self.skipTest(
|
|
561
|
-
"Unity batch project creation failed — typically no batch-mode "
|
|
562
|
-
"license on this machine (see Unity Editor.log). The Maya export "
|
|
563
|
-
"half (test_01) still validates the FBX contents."
|
|
564
|
-
)
|
|
494
|
+
self.skipTest(UnityEnv.project_creation_reason())
|
|
565
495
|
|
|
566
496
|
assets_path = os.path.join(project_path, "Assets")
|
|
567
497
|
# create_project reports success on directory existence but may not have
|
|
@@ -578,22 +508,13 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
578
508
|
editor_path = os.path.join(assets_path, "Editor")
|
|
579
509
|
os.makedirs(editor_path, exist_ok=True)
|
|
580
510
|
|
|
581
|
-
|
|
582
|
-
postproc_cs = UNITY_POSTPROCESSOR_CS.replace(
|
|
583
|
-
"__RESULTS_DIR__", results_dir_escaped
|
|
584
|
-
)
|
|
585
|
-
with open(
|
|
586
|
-
os.path.join(editor_path, "AudioEventTestPostprocessor.cs"),
|
|
587
|
-
"w",
|
|
588
|
-
encoding="utf-8",
|
|
589
|
-
) as f:
|
|
590
|
-
f.write(postproc_cs)
|
|
511
|
+
UserPropsProbe.deploy(editor_path, self.temp_dir)
|
|
591
512
|
|
|
592
513
|
results_path = os.path.join(self.temp_dir, "unity_results.json")
|
|
593
514
|
results_path_escaped = results_path.replace("\\", "\\\\")
|
|
594
515
|
verifier_cs = UNITY_VERIFIER_CS.replace(
|
|
595
516
|
"__RESULTS_PATH__", results_path_escaped
|
|
596
|
-
)
|
|
517
|
+
).replace("__CARRIER_MATCH__", UserPropsProbe.carrier_match_cs())
|
|
597
518
|
with open(
|
|
598
519
|
os.path.join(editor_path, "AudioEventTestVerifier.cs"),
|
|
599
520
|
"w",
|
|
@@ -644,10 +565,11 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
644
565
|
if not os.path.exists(results_path):
|
|
645
566
|
# A batch-licensing failure is environmental (not a code bug) — skip.
|
|
646
567
|
if UnityLauncher.is_license_failure(returncode, full_log):
|
|
647
|
-
|
|
648
|
-
"Unity
|
|
649
|
-
|
|
568
|
+
logger.info(
|
|
569
|
+
"Unity batch license failure (rc=%s) — see %s",
|
|
570
|
+
returncode, log_path,
|
|
650
571
|
)
|
|
572
|
+
self.skipTest(UnityEnv.license_reason())
|
|
651
573
|
self.fail(
|
|
652
574
|
f"unity_results.json not created (Unity rc={returncode}) — "
|
|
653
575
|
f"check {log_path}"
|
|
@@ -655,7 +577,8 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
655
577
|
with open(results_path) as f:
|
|
656
578
|
self.__class__.unity_results = json.load(f)
|
|
657
579
|
|
|
658
|
-
postproc_path = os.path.join(
|
|
580
|
+
postproc_path = os.path.join(
|
|
581
|
+
self.temp_dir, UserPropsProbe.RESULTS_FILENAME)
|
|
659
582
|
if os.path.exists(postproc_path):
|
|
660
583
|
with open(postproc_path) as f:
|
|
661
584
|
self.__class__.postproc = json.load(f)
|
|
@@ -668,8 +591,8 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
668
591
|
# Step 3: Verify manifest + auto-attach + AnimationEvents
|
|
669
592
|
# ------------------------------------------------------------------
|
|
670
593
|
|
|
671
|
-
@
|
|
672
|
-
@
|
|
594
|
+
@MayaEnv.skip_unless_available()
|
|
595
|
+
@EnvSkip.unless(_unity_available(), "no Unity editor found")
|
|
673
596
|
def test_03_analyze(self):
|
|
674
597
|
"""End-to-end: manifest, prefab shape, controller attach, AnimationEvents."""
|
|
675
598
|
unity = self.__class__.unity_results
|
|
@@ -684,17 +607,12 @@ class TestAudioEventsIntegration(unittest.TestCase):
|
|
|
684
607
|
)
|
|
685
608
|
|
|
686
609
|
postproc = self.__class__.postproc or {}
|
|
687
|
-
|
|
688
|
-
for name, props in postproc.items():
|
|
689
|
-
if name.lower().startswith("data_export"):
|
|
690
|
-
carrier_entry = (name, props)
|
|
691
|
-
break
|
|
610
|
+
name, props = UserPropsProbe.find_carrier(postproc)
|
|
692
611
|
self.assertIsNotNone(
|
|
693
|
-
|
|
694
|
-
f"No GameObject
|
|
695
|
-
f"postprocessor results: {list(postproc)}",
|
|
612
|
+
name,
|
|
613
|
+
f"No GameObject named {UserPropsProbe.CARRIER!r} (prefix match) "
|
|
614
|
+
f"in postprocessor results: {list(postproc)}",
|
|
696
615
|
)
|
|
697
|
-
name, props = carrier_entry
|
|
698
616
|
self.assertIn(
|
|
699
617
|
"audio_manifest", props,
|
|
700
618
|
f"audio_manifest user-property missing on {name}; saw: {list(props)}",
|