Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle Enum columns backed by Python Enums #164

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

Vidminas
Copy link

In bfc25f8, support for Enums backing ChoiceType was added. But this doesn't cover native Enums directly backing the SQLAlchemy Enum column type (supported since SQLAlchemy v1.1).

For example, with an enum and an SQLAlchemy class that contains it like this:

class MaterialType(Enum):
    POWDER = "Powder"
    SAND = "Sand"
    GRAVEL = "Gravel"
    BOULDER = "Boulder"

class Material(Base):
    __tablename__ = "material"
    material_type: Mapped[MaterialType]

My app crashes with a ValueError: 'POWDER' is not a valid MaterialType when attempting to render the form, as the default selected option contains an invalid value.

I found several similar (but not the same) issues reported elsewhere:

I've added an additional case to handle this in WTForms-Alchemy > generator.py > select_field_kwargs.

Before the change:

================================================= test session starts =================================================
platform win32 -- Python 3.11.4, pytest-7.4.0, pluggy-1.2.0
cachedir: .tox\sqlalchemy14\.pytest_cache
rootdir: C:\Users\Vidminas\GitHub\wtforms-alchemy
plugins: anyio-3.7.1, cov-4.1.0
collected 249 items

tests\test_class_map.py .................                                                                        [  6%]
tests\test_column_aliases.py .....                                                                               [  8%]
tests\test_configuration.py ...........F......                                                                   [ 16%]
tests\test_country_field.py ..                                                                                   [ 16%]
tests\test_custom_fields.py .                                                                                    [ 17%]
tests\test_deep_form_relations.py ..                                                                             [ 18%]
tests\test_descriptions.py ..                                                                                    [ 18%]
tests\test_field_exclusion.py ....                                                                               [ 20%]
tests\test_field_order.py .                                                                                      [ 20%]
tests\test_field_parameters.py .............                                                                     [ 26%]
tests\test_field_trimming.py ..                                                                                  [ 26%]
tests\test_form_meta.py ........                                                                                 [ 30%]
tests\test_hybrid_properties.py ..                                                                               [ 30%]
tests\test_i18n_extension.py ...                                                                                 [ 32%]
tests\test_inheritance.py .....                                                                                  [ 34%]
tests\test_labels.py ..                                                                                          [ 34%]
tests\test_model_field_list.py ........                                                                          [ 38%]
tests\test_model_form_factory.py ............                                                                    [ 42%]
tests\test_model_form_field.py ...                                                                               [ 44%]
tests\test_phone_number.py ....                                                                                  [ 45%]
tests\test_phone_number_field.py ............                                                                    [ 50%]
tests\test_query_select_field.py .............                                                                   [ 55%]
tests\test_select_field.py ..........                                                                            [ 59%]
tests\test_synonym.py ..                                                                                         [ 60%]
tests\test_types.py ................F..............................                                              [ 79%]
tests\test_unique_validator.py .......................                                                           [ 88%]
tests\test_utils.py .                                                                                            [ 89%]
tests\test_validators.py ...................                                                                     [ 96%]
tests\test_weekdays_field.py ..                                                                                  [ 97%]
tests\test_widgets.py ......                                                                                     [100%]

====================================================== FAILURES =======================================================
___________________________ TestModelFormConfiguration.test_supports_custom_datetime_format ___________________________

self = <tests.test_configuration.TestModelFormConfiguration object at 0x00000186FC071350>

    def test_supports_custom_datetime_format(self):
        self.init(sa.DateTime, nullable=False)

        class ModelTestForm(ModelForm):
            class Meta:
                model = self.ModelTest
                datetime_format = '%Y-%m-%dT%H:%M:%S'

        form = ModelTestForm()
>       assert form.test_column.format == '%Y-%m-%dT%H:%M:%S'
E       AssertionError: assert ['%Y-%m-%dT%H:%M:%S'] == '%Y-%m-%dT%H:%M:%S'
E        +  where ['%Y-%m-%dT%H:%M:%S'] = <wtforms_components.fields.html5.DateTimeField object at 0x00000186FC4C0210>.format
E        +    where <wtforms_components.fields.html5.DateTimeField object at 0x00000186FC4C0210> = <tests.test_configuration.TestModelFormConfiguration.test_supports_custom_datetime_format.<locals>.ModelTestForm object at 0x00000186FC4C2350>.test_column

tests\test_configuration.py:154: AssertionError
______________ TestModelColumnToFormFieldTypeConversion.test_builtin_enum_field_converts_to_select_field ______________

self = <tests.test_types.TestModelColumnToFormFieldTypeConversion object at 0x00000186FC479F50>

    def test_builtin_enum_field_converts_to_select_field(self):
        class TestEnum(Enum):
            A = 'a'
            B = 'b'
        self.init(type_=sa.Enum(TestEnum))
        self.assert_type('test_column', SelectField)
        form = self.form_class()
>       assert form.test_column.choices == [('a', 'A'), ('b', 'B')]
E       AssertionError: assert [('A', 'A'), ('B', 'B')] == [('a', 'A'), ('b', 'B')]
E         At index 0 diff: ('A', 'A') != ('a', 'A')
E         Use -v to get more diff

tests\test_types.py:150: AssertionError
================================================== warnings summary ===================================================
tests\test_unique_validator.py:12
  C:\Users\Vidminas\GitHub\wtforms-alchemy\tests\test_unique_validator.py:12: MovedIn20Warning: Deprecated API features detected! These feature(s) are not compatible with SQLAlchemy 2.0. To prevent incompatible upgrades prior to updating applications, ensure requirements files are pinned to "sqlalchemy<2.0". Set environment variable SQLALCHEMY_WARN_20=1 to show all deprecation warnings.  Set environment variable SQLALCHEMY_SILENCE_UBER_WARNING=1 to silence this message. (Background on SQLAlchemy 2.0 at: https://sqlalche.me/e/b8d9)
    base = declarative_base()

tests/test_model_form_factory.py::TestModelFormFactory::test_class_meta_wtforms2
tests/test_model_form_factory.py::TestModelFormFactory::test_class_meta_wtforms2
  C:\Users\Vidminas\GitHub\wtforms-alchemy\tests\test_model_form_factory.py:94: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.
    if LooseVersion(wtforms.__version__) < LooseVersion('2'):

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=============================================== short test summary info ===============================================
FAILED tests/test_configuration.py::TestModelFormConfiguration::test_supports_custom_datetime_format - AssertionError...
FAILED tests/test_types.py::TestModelColumnToFormFieldTypeConversion::test_builtin_enum_field_converts_to_select_field
====================================== 2 failed, 247 passed, 3 warnings in 4.60s ======================================
sqlalchemy14: exit 1 (9.26 seconds) C:\Users\Vidminas\GitHub\wtforms-alchemy> py.test pid=21592
.pkg: _exit> python C:\Users\Vidminas\.conda\envs\wtforms-alchemy\Lib\site-packages\pyproject_api\_backend.py True setuptools.build_meta __legacy__
  sqlalchemy14: FAIL code 1 (218.98=setup[124.92]+cmd[84.80,9.26] seconds)
  evaluation failed :( (219.48 seconds)

After the change:

================================================= test session starts =================================================
platform win32 -- Python 3.11.4, pytest-7.4.0, pluggy-1.2.0
cachedir: .tox\sqlalchemy14\.pytest_cache
rootdir: C:\Users\Vidminas\GitHub\wtforms-alchemy
plugins: anyio-3.7.1, cov-4.1.0
collected 249 items

tests\test_class_map.py .................                                                                        [  6%]
tests\test_column_aliases.py .....                                                                               [  8%]
tests\test_configuration.py ...........F......                                                                   [ 16%]
tests\test_country_field.py ..                                                                                   [ 16%]
tests\test_custom_fields.py .                                                                                    [ 17%]
tests\test_deep_form_relations.py ..                                                                             [ 18%]
tests\test_descriptions.py ..                                                                                    [ 18%]
tests\test_field_exclusion.py ....                                                                               [ 20%]
tests\test_field_order.py .                                                                                      [ 20%]
tests\test_field_parameters.py .............                                                                     [ 26%]
tests\test_field_trimming.py ..                                                                                  [ 26%]
tests\test_form_meta.py ........                                                                                 [ 30%]
tests\test_hybrid_properties.py ..                                                                               [ 30%]
tests\test_i18n_extension.py ...                                                                                 [ 32%]
tests\test_inheritance.py .....                                                                                  [ 34%]
tests\test_labels.py ..                                                                                          [ 34%]
tests\test_model_field_list.py ........                                                                          [ 38%]
tests\test_model_form_factory.py ............                                                                    [ 42%]
tests\test_model_form_field.py ...                                                                               [ 44%]
tests\test_phone_number.py ....                                                                                  [ 45%]
tests\test_phone_number_field.py ............                                                                    [ 50%]
tests\test_query_select_field.py .............                                                                   [ 55%]
tests\test_select_field.py ..........                                                                            [ 59%]
tests\test_synonym.py ..                                                                                         [ 60%]
tests\test_types.py ...............................................                                              [ 79%]
tests\test_unique_validator.py .......................                                                           [ 88%]
tests\test_utils.py .                                                                                            [ 89%]
tests\test_validators.py ...................                                                                     [ 96%]
tests\test_weekdays_field.py ..                                                                                  [ 97%]
tests\test_widgets.py ......                                                                                     [100%]

====================================================== FAILURES =======================================================
___________________________ TestModelFormConfiguration.test_supports_custom_datetime_format ___________________________

self = <tests.test_configuration.TestModelFormConfiguration object at 0x000002698E6B1790>

    def test_supports_custom_datetime_format(self):
        self.init(sa.DateTime, nullable=False)

        class ModelTestForm(ModelForm):
            class Meta:
                model = self.ModelTest
                datetime_format = '%Y-%m-%dT%H:%M:%S'

        form = ModelTestForm()
>       assert form.test_column.format == '%Y-%m-%dT%H:%M:%S'
E       AssertionError: assert ['%Y-%m-%dT%H:%M:%S'] == '%Y-%m-%dT%H:%M:%S'
E        +  where ['%Y-%m-%dT%H:%M:%S'] = <wtforms_components.fields.html5.DateTimeField object at 0x000002698EAFB550>.format
E        +    where <wtforms_components.fields.html5.DateTimeField object at 0x000002698EAFB550> = <tests.test_configuration.TestModelFormConfiguration.test_supports_custom_datetime_format.<locals>.ModelTestForm object at 0x000002698EAFB310>.test_column

tests\test_configuration.py:154: AssertionError
================================================== warnings summary ===================================================
tests\test_unique_validator.py:12
  C:\Users\Vidminas\GitHub\wtforms-alchemy\tests\test_unique_validator.py:12: MovedIn20Warning: Deprecated API features detected! These feature(s) are not compatible with SQLAlchemy 2.0. To prevent incompatible upgrades prior to updating applications, ensure requirements files are pinned to "sqlalchemy<2.0". Set environment variable SQLALCHEMY_WARN_20=1 to show all deprecation warnings.  Set environment variable SQLALCHEMY_SILENCE_UBER_WARNING=1 to silence this message. (Background on SQLAlchemy 2.0 at: https://sqlalche.me/e/b8d9)
    base = declarative_base()

tests/test_model_form_factory.py::TestModelFormFactory::test_class_meta_wtforms2
tests/test_model_form_factory.py::TestModelFormFactory::test_class_meta_wtforms2
  C:\Users\Vidminas\GitHub\wtforms-alchemy\tests\test_model_form_factory.py:94: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.
    if LooseVersion(wtforms.__version__) < LooseVersion('2'):

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=============================================== short test summary info ===============================================
FAILED tests/test_configuration.py::TestModelFormConfiguration::test_supports_custom_datetime_format - AssertionError...
====================================== 1 failed, 248 passed, 3 warnings in 6.06s ======================================
sqlalchemy14: exit 1 (11.44 seconds) C:\Users\Vidminas\GitHub\wtforms-alchemy> py.test pid=12208
.pkg: _exit> python C:\Users\Vidminas\.conda\envs\wtforms-alchemy\Lib\site-packages\pyproject_api\_backend.py True setuptools.build_meta __legacy__
  sqlalchemy14: FAIL code 1 (238.39=setup[127.99]+cmd[98.97,11.44] seconds)
  evaluation failed :( (238.91 seconds)

(There is also an irrelevant unit test failing in both cases, which I've reported in #163)

@Vidminas
Copy link
Author

Vidminas commented Aug 3, 2023

With more thorough testing, I realised that since sa.Enum inherits from sa.String, the Length validator gets assigned to enum fields too, which leads to a crash when validating a form that contains enums, because they have no length.

Now patched and added a unit test too. tox -e sqlalchemy14 before the change:

================================================= test session starts =================================================
platform win32 -- Python 3.11.4, pytest-7.4.0, pluggy-1.2.0
cachedir: .tox\sqlalchemy14\.pytest_cache
rootdir: C:\Users\Vidminas\GitHub\wtforms-alchemy
plugins: cov-4.1.0
collected 250 items

tests\test_class_map.py .................                                                                        [  6%]
tests\test_column_aliases.py .....                                                                               [  8%]
tests\test_configuration.py ...........F......                                                                   [ 16%]
tests\test_country_field.py ..                                                                                   [ 16%]
tests\test_custom_fields.py .                                                                                    [ 17%]
tests\test_deep_form_relations.py ..                                                                             [ 18%]
tests\test_descriptions.py ..                                                                                    [ 18%] 
tests\test_field_exclusion.py ....                                                                               [ 20%]
tests\test_field_order.py .                                                                                      [ 20%]
tests\test_field_parameters.py .............                                                                     [ 26%]
tests\test_field_trimming.py ..                                                                                  [ 26%]
tests\test_form_meta.py ........                                                                                 [ 30%]
tests\test_hybrid_properties.py ..                                                                               [ 30%]
tests\test_i18n_extension.py ...                                                                                 [ 32%]
tests\test_inheritance.py .....                                                                                  [ 34%] 
tests\test_labels.py ..                                                                                          [ 34%]
tests\test_model_field_list.py ........                                                                          [ 38%]
tests\test_model_form_factory.py ............                                                                    [ 42%]
tests\test_model_form_field.py ...                                                                               [ 44%]
tests\test_phone_number.py ....                                                                                  [ 45%]
tests\test_phone_number_field.py ............                                                                    [ 50%]
tests\test_query_select_field.py .............                                                                   [ 55%]
tests\test_select_field.py ..........                                                                            [ 59%]
tests\test_synonym.py ..                                                                                         [ 60%]
tests\test_types.py ...............................................                                              [ 79%]
tests\test_unique_validator.py .......................                                                           [ 88%]
tests\test_utils.py .                                                                                            [ 88%]
tests\test_validators.py ...................F                                                                    [ 96%]
tests\test_weekdays_field.py ..                                                                                  [ 97%] 
tests\test_widgets.py ......                                                                                     [100%]

====================================================== FAILURES ======================================================= 
___________________________ TestModelFormConfiguration.test_supports_custom_datetime_format ___________________________ 

self = <tests.test_configuration.TestModelFormConfiguration object at 0x00000296FAA57990>

    def test_supports_custom_datetime_format(self):
        self.init(sa.DateTime, nullable=False)

        class ModelTestForm(ModelForm):
            class Meta:
                model = self.ModelTest
                datetime_format = '%Y-%m-%dT%H:%M:%S'

        form = ModelTestForm()
>       assert form.test_column.format == '%Y-%m-%dT%H:%M:%S'
E       AssertionError: assert ['%Y-%m-%dT%H:%M:%S'] == '%Y-%m-%dT%H:%M:%S'
E        +  where ['%Y-%m-%dT%H:%M:%S'] = <wtforms_components.fields.html5.DateTimeField object at 0x00000296FAEE6250>.format
E        +    where <wtforms_components.fields.html5.DateTimeField object at 0x00000296FAEE6250> = <tests.test_configuration.TestModelFormConfiguration.test_supports_custom_datetime_format.<locals>.ModelTestForm object at 0x00000296FADF7250>.test_column

tests\test_configuration.py:154: AssertionError
___________________________________ TestAutoAssignedValidators.test_enum_validators ___________________________________ 

self = <tests.test_validators.TestAutoAssignedValidators object at 0x00000296FAED3790>

    def test_enum_validators(self):
        class TestEnum(enum.Enum):
            A = 'a'
            B = 'b'

        self.init(type_=sa.Enum(TestEnum), nullable=True)
        form = self.form_class()

>       assert len(form.test_column.validators) == 1
E       assert 2 == 1
E        +  where 2 = len([<wtforms.validators.Optional object at 0x00000296FBA101D0>, <wtforms.validators.Length object at 0x00000296FBB40C10>])
E        +    where [<wtforms.validators.Optional object at 0x00000296FBA101D0>, <wtforms.validators.Length object at 0x00000296FBB40C10>] = <wtforms_components.fields.select.SelectField object at 0x00000296FBB40ED0>.validators
E        +      where <wtforms_components.fields.select.SelectField object at 0x00000296FBB40ED0> = <tests.ModelFormTestCase.init_form.<locals>.ModelTestForm object at 0x00000296FBB39610>.test_column

tests\test_validators.py:278: AssertionError
================================================== warnings summary =================================================== 
tests\test_unique_validator.py:12
  C:\Users\Vidminas\GitHub\wtforms-alchemy\tests\test_unique_validator.py:12: MovedIn20Warning: Deprecated API features 
detected! These feature(s) are not compatible with SQLAlchemy 2.0. To prevent incompatible upgrades prior to updating applications, ensure requirements files are pinned to "sqlalchemy<2.0". Set environment variable SQLALCHEMY_WARN_20=1 to show all deprecation warnings.  Set environment variable SQLALCHEMY_SILENCE_UBER_WARNING=1 to silence this message. (Background on SQLAlchemy 2.0 at: https://sqlalche.me/e/b8d9)
    base = declarative_base()

tests/test_model_form_factory.py::TestModelFormFactory::test_class_meta_wtforms2
tests/test_model_form_factory.py::TestModelFormFactory::test_class_meta_wtforms2
  C:\Users\Vidminas\GitHub\wtforms-alchemy\tests\test_model_form_factory.py:94: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.
    if LooseVersion(wtforms.__version__) < LooseVersion('2'):

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=============================================== short test summary info =============================================== 
FAILED tests/test_configuration.py::TestModelFormConfiguration::test_supports_custom_datetime_format - AssertionError...FAILED tests/test_validators.py::TestAutoAssignedValidators::test_enum_validators - assert 2 == 1
====================================== 2 failed, 248 passed, 3 warnings in 2.35s ====================================== 
sqlalchemy14: exit 1 (4.38 seconds) C:\Users\Vidminas\GitHub\wtforms-alchemy> py.test pid=21920
.pkg: _exit> python C:\Users\Vidminas\.conda\envs\wtforms-alchemy\Lib\site-packages\pyproject_api\_backend.py True setuptools.build_meta __legacy__
  sqlalchemy14: FAIL code 1 (102.83=setup[58.31]+cmd[40.14,4.38] seconds)
  evaluation failed :( (103.08 seconds)

And after the change:

================================================= test session starts =================================================
platform win32 -- Python 3.11.4, pytest-7.4.0, pluggy-1.2.0
cachedir: .tox\sqlalchemy14\.pytest_cache
rootdir: C:\Users\Vidminas\GitHub\wtforms-alchemy
plugins: cov-4.1.0
collected 250 items

tests\test_class_map.py .................                                                                        [  6%]
tests\test_column_aliases.py .....                                                                               [  8%]
tests\test_configuration.py ...........F......                                                                   [ 16%]
tests\test_country_field.py ..                                                                                   [ 16%]
tests\test_custom_fields.py .                                                                                    [ 17%] 
tests\test_deep_form_relations.py ..                                                                             [ 18%]
tests\test_descriptions.py ..                                                                                    [ 18%]
tests\test_field_exclusion.py ....                                                                               [ 20%]
tests\test_field_order.py .                                                                                      [ 20%]
tests\test_field_parameters.py .............                                                                     [ 26%]
tests\test_field_trimming.py ..                                                                                  [ 26%]
tests\test_form_meta.py ........                                                                                 [ 30%]
tests\test_hybrid_properties.py ..                                                                               [ 30%]
tests\test_i18n_extension.py ...                                                                                 [ 32%]
tests\test_inheritance.py .....                                                                                  [ 34%]
tests\test_labels.py ..                                                                                          [ 34%]
tests\test_model_field_list.py ........                                                                          [ 38%]
tests\test_model_form_factory.py ............                                                                    [ 42%]
tests\test_model_form_field.py ...                                                                               [ 44%]
tests\test_phone_number.py ....                                                                                  [ 45%]
tests\test_phone_number_field.py ............                                                                    [ 50%]
tests\test_query_select_field.py .............                                                                   [ 55%]
tests\test_select_field.py ..........                                                                            [ 59%]
tests\test_synonym.py ..                                                                                         [ 60%]
tests\test_types.py ...............................................                                              [ 79%]
tests\test_unique_validator.py .......................                                                           [ 88%]
tests\test_utils.py .                                                                                            [ 88%]
tests\test_validators.py ....................                                                                    [ 96%]
tests\test_weekdays_field.py ..                                                                                  [ 97%] 
tests\test_widgets.py ......                                                                                     [100%]

====================================================== FAILURES ======================================================= 
___________________________ TestModelFormConfiguration.test_supports_custom_datetime_format ___________________________ 

self = <tests.test_configuration.TestModelFormConfiguration object at 0x0000024B3F9B3C50>

    def test_supports_custom_datetime_format(self):
        self.init(sa.DateTime, nullable=False)

        class ModelTestForm(ModelForm):
            class Meta:
                model = self.ModelTest
                datetime_format = '%Y-%m-%dT%H:%M:%S'

        form = ModelTestForm()
>       assert form.test_column.format == '%Y-%m-%dT%H:%M:%S'
E       AssertionError: assert ['%Y-%m-%dT%H:%M:%S'] == '%Y-%m-%dT%H:%M:%S'
E        +  where ['%Y-%m-%dT%H:%M:%S'] = <wtforms_components.fields.html5.DateTimeField object at 0x0000024B3FE21490>.format
E        +    where <wtforms_components.fields.html5.DateTimeField object at 0x0000024B3FE21490> = <tests.test_configuration.TestModelFormConfiguration.test_supports_custom_datetime_format.<locals>.ModelTestForm object at 0x0000024B3F94F390>.test_column

tests\test_configuration.py:154: AssertionError
================================================== warnings summary =================================================== 
tests\test_unique_validator.py:12
  C:\Users\Vidminas\GitHub\wtforms-alchemy\tests\test_unique_validator.py:12: MovedIn20Warning: Deprecated API features 
detected! These feature(s) are not compatible with SQLAlchemy 2.0. To prevent incompatible upgrades prior to updating applications, ensure requirements files are pinned to "sqlalchemy<2.0". Set environment variable SQLALCHEMY_WARN_20=1 to show all deprecation warnings.  Set environment variable SQLALCHEMY_SILENCE_UBER_WARNING=1 to silence this message. (Background on SQLAlchemy 2.0 at: https://sqlalche.me/e/b8d9)
    base = declarative_base()

tests/test_model_form_factory.py::TestModelFormFactory::test_class_meta_wtforms2
tests/test_model_form_factory.py::TestModelFormFactory::test_class_meta_wtforms2
  C:\Users\Vidminas\GitHub\wtforms-alchemy\tests\test_model_form_factory.py:94: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.
    if LooseVersion(wtforms.__version__) < LooseVersion('2'):

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=============================================== short test summary info =============================================== 
FAILED tests/test_configuration.py::TestModelFormConfiguration::test_supports_custom_datetime_format - AssertionError...====================================== 1 failed, 249 passed, 3 warnings in 2.73s ====================================== 
sqlalchemy14: exit 1 (4.81 seconds) C:\Users\Vidminas\GitHub\wtforms-alchemy> py.test pid=8636
.pkg: _exit> python C:\Users\Vidminas\.conda\envs\wtforms-alchemy\Lib\site-packages\pyproject_api\_backend.py True setuptools.build_meta __legacy__
  sqlalchemy14: FAIL code 1 (96.98=setup[49.86]+cmd[42.31,4.81] seconds)
  evaluation failed :( (97.23 seconds)

@Vidminas
Copy link
Author

Vidminas commented Aug 4, 2023

With my above workarounds, rendering and validation no longer crash, but validation still fails for enum fields with "Not a valid choice" because the built-in wtforms_components SelectField does not like the trick of reversing values and labels:

From wtforms_components/fields/select.py, line 54:

@property
def choice_values(self):
    values = []
    for value, label in self.concrete_choices:
        if isinstance(label, (list, tuple)):
            for subvalue, sublabel in label:
                values.append(subvalue)
        else:
            values.append(value)
    return values
        
def pre_validate(self, form):
    """
    Don't forget to validate also values from embedded lists.
    """
    values = self.choice_values
    if (self.data is None and u'' in values) or self.data in values:
        return True

    raise ValidationError(self.gettext(u'Not a valid choice'))

The exception gets raised, because (with my above example enum column) choices are [('Powder', <MaterialType.POWDER: 'Powder'>), ('Sand', <MaterialType.SAND: 'Sand'>), ('Gravel', <MaterialType.GRAVEL: 'Gravel'>), ('Boulder', <MaterialType.BOULDER: 'Boulder'>)] but choice_values are ['Powder', 'Sand', 'Gravel', 'Boulder'], whereas data is an instance of the enum like <MaterialType.POWDER: 'Powder'>

I added a SelectField extension that overrides the choice_values creation to use enum instances instead of string values.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant