diff --git a/build/templates/constants.py.template b/build/templates/constants.py.template index 9f91c28..b0e8c33 100644 --- a/build/templates/constants.py.template +++ b/build/templates/constants.py.template @@ -20,7 +20,7 @@ ENABLED_FEATURES = ["basic", "preview"] if VERSION_TYPE == "free" else [ "basic", "preview", "presets", "normal_maps", "batch_processing", "image_overlays", "basic_utilities", "advanced_utilities", "advanced_styling", "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) @@ -114,9 +114,7 @@ def has_text_fitting(): """Check if text fitting is available""" 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(): """Get maximum texture resolution based on version""" @@ -138,8 +136,7 @@ def should_show_feature_lock(feature_name): 'blur_effects': has_blur_effects, 'shadow_glow_effects': has_shadow_glow_effects, 'shader_generation': has_shader_generation, - 'text_fitting': has_text_fitting, - 'multiline_text': has_multiline_text + 'text_fitting': has_text_fitting } if is_full_version(): diff --git a/dist/text_texture_generator_v1.0.0.zip b/dist/text_texture_generator_v1.0.0.zip index de35f37..21539af 100644 Binary files a/dist/text_texture_generator_v1.0.0.zip and b/dist/text_texture_generator_v1.0.0.zip differ diff --git a/dist/text_texture_generator_v1.0.0_free.zip b/dist/text_texture_generator_v1.0.0_free.zip index e18e10d..1b1e752 100644 Binary files a/dist/text_texture_generator_v1.0.0_free.zip and b/dist/text_texture_generator_v1.0.0_free.zip differ diff --git a/src/__init__.py b/src/__init__.py index fcab370..5874119 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -136,20 +136,8 @@ else: TEXT_TEXTURE_OT_export_presets = MockOperator TEXT_TEXTURE_OT_import_presets = MockOperator -# Conditionally import text editor operators (PRO feature) -try: - 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 +# Text editor operators removed - feature deprecated +TEXT_EDITOR_OPERATORS_AVAILABLE = False # Import UI panels and functions from .ui import ( @@ -182,7 +170,6 @@ classes = ( TEXT_TEXTURE_OT_duplicate_overlay, TEXT_TEXTURE_OT_delete_overlay, TEXT_TEXTURE_OT_move_overlay, - TEXT_TEXTURE_OT_edit_text, TEXT_TEXTURE_OT_open_panel, TEXT_TEXTURE_OT_save_preset, TEXT_TEXTURE_OT_save_preset_enter, diff --git a/src/__pycache__/__init__.cpython-311.pyc b/src/__pycache__/__init__.cpython-311.pyc index 6e78b2c..2c7c7ab 100644 Binary files a/src/__pycache__/__init__.cpython-311.pyc and b/src/__pycache__/__init__.cpython-311.pyc differ diff --git a/src/operators/text_editor_ops.py b/src/operators/text_editor_ops.py index 39f7c84..55afef5 100644 --- a/src/operators/text_editor_ops.py +++ b/src/operators/text_editor_ops.py @@ -1,7 +1,7 @@ import bpy from bpy.types import Operator 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): @@ -21,7 +21,7 @@ class TEXT_TEXTURE_OT_edit_text(Operator): @classmethod def poll(cls, context): """Only available in PRO version""" - return has_text_editor() + return is_full_version() def invoke(self, context, event): """Copy current text to temp storage and open dialog""" diff --git a/src/ui/__pycache__/__init__.cpython-311.pyc b/src/ui/__pycache__/__init__.cpython-311.pyc index c087d2a..bcdf74e 100644 Binary files a/src/ui/__pycache__/__init__.cpython-311.pyc and b/src/ui/__pycache__/__init__.cpython-311.pyc differ diff --git a/src/ui/__pycache__/panels.cpython-311.pyc b/src/ui/__pycache__/panels.cpython-311.pyc index acf6d02..3dee696 100644 Binary files a/src/ui/__pycache__/panels.cpython-311.pyc and b/src/ui/__pycache__/panels.cpython-311.pyc differ diff --git a/src/ui/panels.py b/src/ui/panels.py index ab25057..a59cfae 100644 --- a/src/ui/panels.py +++ b/src/ui/panels.py @@ -12,7 +12,7 @@ from ..utils.constants import ( get_feature_availability_text, get_version_info_details, has_image_overlays, has_basic_utilities, has_presets, 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""" layout.prop(props, "text", text="") - # Add multiline text editor button - row = layout.row() - 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') + # Note: Multiline text editor feature is not currently available + # The operator "text_texture.edit_text" does not exist in the codebase def draw_font_dropdown_section(layout, props): pass diff --git a/src/utils/__pycache__/constants.cpython-311.pyc b/src/utils/__pycache__/constants.cpython-311.pyc index 45361a9..7fb46e3 100644 Binary files a/src/utils/__pycache__/constants.cpython-311.pyc and b/src/utils/__pycache__/constants.cpython-311.pyc differ diff --git a/src/utils/constants.py b/src/utils/constants.py index 37c49db..b1f7aca 100644 --- a/src/utils/constants.py +++ b/src/utils/constants.py @@ -20,7 +20,7 @@ ENABLED_FEATURES = ["basic", "preview"] if VERSION_TYPE == "free" else [ "basic", "preview", "presets", "normal_maps", "batch_processing", "image_overlays", "basic_utilities", "advanced_utilities", "advanced_styling", "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) @@ -114,9 +114,7 @@ def has_text_fitting(): """Check if text fitting is available""" 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(): """Get maximum texture resolution based on version""" @@ -138,8 +136,7 @@ def should_show_feature_lock(feature_name): 'blur_effects': has_blur_effects, 'shadow_glow_effects': has_shadow_glow_effects, 'shader_generation': has_shader_generation, - 'text_fitting': has_text_fitting, - 'text_editor': has_text_editor + 'text_fitting': has_text_fitting } if is_full_version(): diff --git a/tests/e2e/test_no_stale_imports.py b/tests/e2e/test_no_stale_imports.py new file mode 100644 index 0000000..e580edb --- /dev/null +++ b/tests/e2e/test_no_stale_imports.py @@ -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) + ) \ No newline at end of file diff --git a/tests/unit/test_imports.py b/tests/unit/test_imports.py new file mode 100644 index 0000000..0426149 --- /dev/null +++ b/tests/unit/test_imports.py @@ -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 \ No newline at end of file