wip
This commit is contained in:
@@ -20,7 +20,7 @@ ENABLED_FEATURES = ["basic", "preview"] if VERSION_TYPE == "free" else [
|
|||||||
"basic", "preview", "presets", "normal_maps", "batch_processing",
|
"basic", "preview", "presets", "normal_maps", "batch_processing",
|
||||||
"image_overlays", "basic_utilities", "advanced_utilities", "advanced_styling",
|
"image_overlays", "basic_utilities", "advanced_utilities", "advanced_styling",
|
||||||
"stroke_effects", "blur_effects", "shadow_glow_effects", "shader_generation",
|
"stroke_effects", "blur_effects", "shadow_glow_effects", "shader_generation",
|
||||||
"text_fitting", "multiline_text"
|
"text_fitting"
|
||||||
]
|
]
|
||||||
|
|
||||||
# Version-specific limits (applied at build time through file exclusions)
|
# Version-specific limits (applied at build time through file exclusions)
|
||||||
@@ -114,9 +114,7 @@ def has_text_fitting():
|
|||||||
"""Check if text fitting is available"""
|
"""Check if text fitting is available"""
|
||||||
return has_feature("text_fitting")
|
return has_feature("text_fitting")
|
||||||
|
|
||||||
def has_multiline_text():
|
|
||||||
"""Check if multiline text feature is available."""
|
|
||||||
return has_feature("multiline_text")
|
|
||||||
|
|
||||||
def get_max_resolution():
|
def get_max_resolution():
|
||||||
"""Get maximum texture resolution based on version"""
|
"""Get maximum texture resolution based on version"""
|
||||||
@@ -138,8 +136,7 @@ def should_show_feature_lock(feature_name):
|
|||||||
'blur_effects': has_blur_effects,
|
'blur_effects': has_blur_effects,
|
||||||
'shadow_glow_effects': has_shadow_glow_effects,
|
'shadow_glow_effects': has_shadow_glow_effects,
|
||||||
'shader_generation': has_shader_generation,
|
'shader_generation': has_shader_generation,
|
||||||
'text_fitting': has_text_fitting,
|
'text_fitting': has_text_fitting
|
||||||
'multiline_text': has_multiline_text
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_full_version():
|
if is_full_version():
|
||||||
|
|||||||
BIN
dist/text_texture_generator_v1.0.0.zip
vendored
BIN
dist/text_texture_generator_v1.0.0.zip
vendored
Binary file not shown.
BIN
dist/text_texture_generator_v1.0.0_free.zip
vendored
BIN
dist/text_texture_generator_v1.0.0_free.zip
vendored
Binary file not shown.
@@ -136,20 +136,8 @@ else:
|
|||||||
TEXT_TEXTURE_OT_export_presets = MockOperator
|
TEXT_TEXTURE_OT_export_presets = MockOperator
|
||||||
TEXT_TEXTURE_OT_import_presets = MockOperator
|
TEXT_TEXTURE_OT_import_presets = MockOperator
|
||||||
|
|
||||||
# Conditionally import text editor operators (PRO feature)
|
# Text editor operators removed - feature deprecated
|
||||||
try:
|
TEXT_EDITOR_OPERATORS_AVAILABLE = False
|
||||||
from .operators import (
|
|
||||||
TEXT_TEXTURE_OT_edit_text,
|
|
||||||
)
|
|
||||||
TEXT_EDITOR_OPERATORS_AVAILABLE = True
|
|
||||||
except ImportError as e:
|
|
||||||
import sys
|
|
||||||
import traceback
|
|
||||||
print(f"WARNING: text_editor_ops import failed: {e}", file=sys.stderr)
|
|
||||||
traceback.print_exc()
|
|
||||||
# Free version - use mock operator
|
|
||||||
TEXT_TEXTURE_OT_edit_text = MockOperator
|
|
||||||
TEXT_EDITOR_OPERATORS_AVAILABLE = False
|
|
||||||
|
|
||||||
# Import UI panels and functions
|
# Import UI panels and functions
|
||||||
from .ui import (
|
from .ui import (
|
||||||
@@ -182,7 +170,6 @@ classes = (
|
|||||||
TEXT_TEXTURE_OT_duplicate_overlay,
|
TEXT_TEXTURE_OT_duplicate_overlay,
|
||||||
TEXT_TEXTURE_OT_delete_overlay,
|
TEXT_TEXTURE_OT_delete_overlay,
|
||||||
TEXT_TEXTURE_OT_move_overlay,
|
TEXT_TEXTURE_OT_move_overlay,
|
||||||
TEXT_TEXTURE_OT_edit_text,
|
|
||||||
TEXT_TEXTURE_OT_open_panel,
|
TEXT_TEXTURE_OT_open_panel,
|
||||||
TEXT_TEXTURE_OT_save_preset,
|
TEXT_TEXTURE_OT_save_preset,
|
||||||
TEXT_TEXTURE_OT_save_preset_enter,
|
TEXT_TEXTURE_OT_save_preset_enter,
|
||||||
|
|||||||
Binary file not shown.
@@ -1,7 +1,7 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from bpy.types import Operator
|
from bpy.types import Operator
|
||||||
from bpy.props import StringProperty
|
from bpy.props import StringProperty
|
||||||
from ..utils.constants import has_text_editor
|
from ..utils.constants import is_full_version
|
||||||
|
|
||||||
|
|
||||||
class TEXT_TEXTURE_OT_edit_text(Operator):
|
class TEXT_TEXTURE_OT_edit_text(Operator):
|
||||||
@@ -21,7 +21,7 @@ class TEXT_TEXTURE_OT_edit_text(Operator):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def poll(cls, context):
|
def poll(cls, context):
|
||||||
"""Only available in PRO version"""
|
"""Only available in PRO version"""
|
||||||
return has_text_editor()
|
return is_full_version()
|
||||||
|
|
||||||
def invoke(self, context, event):
|
def invoke(self, context, event):
|
||||||
"""Copy current text to temp storage and open dialog"""
|
"""Copy current text to temp storage and open dialog"""
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -12,7 +12,7 @@ from ..utils.constants import (
|
|||||||
get_feature_availability_text, get_version_info_details,
|
get_feature_availability_text, get_version_info_details,
|
||||||
has_image_overlays, has_basic_utilities, has_presets,
|
has_image_overlays, has_basic_utilities, has_presets,
|
||||||
has_normal_maps, has_batch_processing, has_advanced_utilities,
|
has_normal_maps, has_batch_processing, has_advanced_utilities,
|
||||||
has_advanced_styling, has_text_fitting, has_text_editor
|
has_advanced_styling, has_text_fitting
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -201,13 +201,8 @@ def draw_text_input_section(layout, props):
|
|||||||
"""Draw the main text input field"""
|
"""Draw the main text input field"""
|
||||||
layout.prop(props, "text", text="")
|
layout.prop(props, "text", text="")
|
||||||
|
|
||||||
# Add multiline text editor button
|
# Note: Multiline text editor feature is not currently available
|
||||||
row = layout.row()
|
# The operator "text_texture.edit_text" does not exist in the codebase
|
||||||
if has_text_editor():
|
|
||||||
row.operator("text_texture.edit_multiline_text", text="Edit Multiline Text", icon='TEXT')
|
|
||||||
else:
|
|
||||||
row.enabled = False
|
|
||||||
row.operator("text_texture.edit_multiline_text", text="Edit Multiline Text (PRO)", icon='LOCKED')
|
|
||||||
|
|
||||||
def draw_font_dropdown_section(layout, props):
|
def draw_font_dropdown_section(layout, props):
|
||||||
pass
|
pass
|
||||||
|
|||||||
Binary file not shown.
@@ -20,7 +20,7 @@ ENABLED_FEATURES = ["basic", "preview"] if VERSION_TYPE == "free" else [
|
|||||||
"basic", "preview", "presets", "normal_maps", "batch_processing",
|
"basic", "preview", "presets", "normal_maps", "batch_processing",
|
||||||
"image_overlays", "basic_utilities", "advanced_utilities", "advanced_styling",
|
"image_overlays", "basic_utilities", "advanced_utilities", "advanced_styling",
|
||||||
"stroke_effects", "blur_effects", "shadow_glow_effects", "shader_generation",
|
"stroke_effects", "blur_effects", "shadow_glow_effects", "shader_generation",
|
||||||
"text_fitting", "text_editor"
|
"text_fitting"
|
||||||
]
|
]
|
||||||
|
|
||||||
# Version-specific limits (applied at build time through file exclusions)
|
# Version-specific limits (applied at build time through file exclusions)
|
||||||
@@ -114,9 +114,7 @@ def has_text_fitting():
|
|||||||
"""Check if text fitting is available"""
|
"""Check if text fitting is available"""
|
||||||
return has_feature("text_fitting")
|
return has_feature("text_fitting")
|
||||||
|
|
||||||
def has_text_editor():
|
|
||||||
"""Check if text editor feature is available."""
|
|
||||||
return has_feature("text_editor")
|
|
||||||
|
|
||||||
def get_max_resolution():
|
def get_max_resolution():
|
||||||
"""Get maximum texture resolution based on version"""
|
"""Get maximum texture resolution based on version"""
|
||||||
@@ -138,8 +136,7 @@ def should_show_feature_lock(feature_name):
|
|||||||
'blur_effects': has_blur_effects,
|
'blur_effects': has_blur_effects,
|
||||||
'shadow_glow_effects': has_shadow_glow_effects,
|
'shadow_glow_effects': has_shadow_glow_effects,
|
||||||
'shader_generation': has_shader_generation,
|
'shader_generation': has_shader_generation,
|
||||||
'text_fitting': has_text_fitting,
|
'text_fitting': has_text_fitting
|
||||||
'text_editor': has_text_editor
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_full_version():
|
if is_full_version():
|
||||||
|
|||||||
103
tests/e2e/test_no_stale_imports.py
Normal file
103
tests/e2e/test_no_stale_imports.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
"""E2E regression test to ensure multiline text editor feature is completely removed.
|
||||||
|
|
||||||
|
This test scans actual source files for stale imports and references that should
|
||||||
|
not exist after the multiline text editor feature was removed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def read_file_lines(filepath: Path) -> list[str]:
|
||||||
|
"""Read file and return lines with line numbers."""
|
||||||
|
with open(filepath, 'r', encoding='utf-8') as f:
|
||||||
|
return f.readlines()
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_has_text_editor_import_in_text_editor_ops():
|
||||||
|
"""Verify has_text_editor is not imported in text_editor_ops.py"""
|
||||||
|
file_path = Path('src/operators/text_editor_ops.py')
|
||||||
|
lines = read_file_lines(file_path)
|
||||||
|
|
||||||
|
stale_imports = []
|
||||||
|
for i, line in enumerate(lines, start=1):
|
||||||
|
if 'has_text_editor' in line and 'import' in line.lower():
|
||||||
|
stale_imports.append((i, line.strip()))
|
||||||
|
|
||||||
|
assert not stale_imports, (
|
||||||
|
f"Found stale 'has_text_editor' imports in {file_path}:\n"
|
||||||
|
+ "\n".join(f" Line {num}: {content}" for num, content in stale_imports)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_has_text_editor_import_in_panels():
|
||||||
|
"""Verify has_text_editor is not imported in panels.py"""
|
||||||
|
file_path = Path('src/ui/panels.py')
|
||||||
|
lines = read_file_lines(file_path)
|
||||||
|
|
||||||
|
stale_imports = []
|
||||||
|
for i, line in enumerate(lines, start=1):
|
||||||
|
if 'has_text_editor' in line and ('import' in line.lower() or 'from' in line.lower()):
|
||||||
|
stale_imports.append((i, line.strip()))
|
||||||
|
|
||||||
|
assert not stale_imports, (
|
||||||
|
f"Found stale 'has_text_editor' imports in {file_path}:\n"
|
||||||
|
+ "\n".join(f" Line {num}: {content}" for num, content in stale_imports)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_multiline_text_operator_references_in_init():
|
||||||
|
"""Verify TEXT_TEXTURE_OT_edit_multiline_text is not referenced in __init__.py"""
|
||||||
|
file_path = Path('src/__init__.py')
|
||||||
|
lines = read_file_lines(file_path)
|
||||||
|
|
||||||
|
stale_references = []
|
||||||
|
for i, line in enumerate(lines, start=1):
|
||||||
|
if 'TEXT_TEXTURE_OT_edit_multiline_text' in line:
|
||||||
|
stale_references.append((i, line.strip()))
|
||||||
|
|
||||||
|
assert not stale_references, (
|
||||||
|
f"Found stale 'TEXT_TEXTURE_OT_edit_multiline_text' references in {file_path}:\n"
|
||||||
|
+ "\n".join(f" Line {num}: {content}" for num, content in stale_references)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_multiline_text_in_constants():
|
||||||
|
"""Verify multiline_text feature is completely removed from constants.py"""
|
||||||
|
file_path = Path('src/utils/constants.py')
|
||||||
|
lines = read_file_lines(file_path)
|
||||||
|
|
||||||
|
stale_code = []
|
||||||
|
|
||||||
|
# Check for has_multiline_text function
|
||||||
|
for i, line in enumerate(lines, start=1):
|
||||||
|
if 'def has_multiline_text' in line or 'has_multiline_text' in line:
|
||||||
|
stale_code.append((i, line.strip()))
|
||||||
|
|
||||||
|
# Check for "multiline_text" in ENABLED_FEATURES
|
||||||
|
content = ''.join(lines)
|
||||||
|
if '"multiline_text"' in content or "'multiline_text'" in content:
|
||||||
|
for i, line in enumerate(lines, start=1):
|
||||||
|
if 'multiline_text' in line and 'ENABLED_FEATURES' in content[max(0, content.find(line)-500):content.find(line)+500]:
|
||||||
|
stale_code.append((i, line.strip()))
|
||||||
|
|
||||||
|
assert not stale_code, (
|
||||||
|
f"Found stale 'multiline_text' code in {file_path}:\n"
|
||||||
|
+ "\n".join(f" Line {num}: {content}" for num, content in stale_code)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_has_text_editor_function_in_constants():
|
||||||
|
"""Verify has_text_editor function doesn't exist in constants.py"""
|
||||||
|
file_path = Path('src/utils/constants.py')
|
||||||
|
lines = read_file_lines(file_path)
|
||||||
|
|
||||||
|
stale_functions = []
|
||||||
|
for i, line in enumerate(lines, start=1):
|
||||||
|
if 'def has_text_editor' in line:
|
||||||
|
stale_functions.append((i, line.strip()))
|
||||||
|
|
||||||
|
assert not stale_functions, (
|
||||||
|
f"Found stale 'has_text_editor' function definition in {file_path}:\n"
|
||||||
|
+ "\n".join(f" Line {num}: {content}" for num, content in stale_functions)
|
||||||
|
)
|
||||||
48
tests/unit/test_imports.py
Normal file
48
tests/unit/test_imports.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
"""Unit tests for import integrity of renamed/removed symbols."""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Add src to path for imports
|
||||||
|
src_path = Path(__file__).parent.parent.parent / "src"
|
||||||
|
sys.path.insert(0, str(src_path))
|
||||||
|
|
||||||
|
|
||||||
|
def test_has_multiline_text_function_complete():
|
||||||
|
"""Test that has_multiline_text() is a complete function with body."""
|
||||||
|
from utils.constants import has_multiline_text
|
||||||
|
|
||||||
|
# Should be callable
|
||||||
|
assert callable(has_multiline_text)
|
||||||
|
|
||||||
|
# Should return a boolean (not crash with incomplete body)
|
||||||
|
result = has_multiline_text()
|
||||||
|
assert isinstance(result, bool)
|
||||||
|
|
||||||
|
|
||||||
|
def test_has_text_editor_imports_from_constants():
|
||||||
|
"""Test that has_text_editor can be imported from utils.constants."""
|
||||||
|
from utils.constants import has_text_editor
|
||||||
|
|
||||||
|
# Verify it's callable (should be a function)
|
||||||
|
assert callable(has_text_editor)
|
||||||
|
|
||||||
|
# Should return a boolean without crashing
|
||||||
|
result = has_text_editor()
|
||||||
|
assert isinstance(result, bool)
|
||||||
|
|
||||||
|
|
||||||
|
def test_new_operator_name_imports_from_operators():
|
||||||
|
"""Test that TEXT_TEXTURE_OT_edit_text (NEW name) can be imported from operators."""
|
||||||
|
from src.operators import TEXT_TEXTURE_OT_edit_text
|
||||||
|
|
||||||
|
# Verify it's a Blender operator class
|
||||||
|
assert hasattr(TEXT_TEXTURE_OT_edit_text, 'bl_idname')
|
||||||
|
assert TEXT_TEXTURE_OT_edit_text.bl_idname == 'text_texture.edit_text'
|
||||||
|
|
||||||
|
|
||||||
|
def test_old_operator_name_not_importable():
|
||||||
|
"""Test that TEXT_TEXTURE_OT_edit_multiline_text (OLD name) is NOT importable."""
|
||||||
|
with pytest.raises(ImportError, match="cannot import name 'TEXT_TEXTURE_OT_edit_multiline_text'"):
|
||||||
|
from src.operators import TEXT_TEXTURE_OT_edit_multiline_text
|
||||||
Reference in New Issue
Block a user