使用混音器的自定义类型的AttributeError

时间:2014-10-17 00:59:24

标签: python postgresql sqlalchemy

我在Python的klen调音台库中偶然发现了一个非常有趣的错误。

https://github.com/klen/mixer

每当您尝试使用sqlalchemy.dialect.postgresql.INET设置包含列的模型时,就会出现此错误。尝试将模型与此混合将带来以下痕迹...

mixer: ERROR: Traceback (most recent call last):
File "/home/cllamach/PythonProjects/mixer/mixer/main.py", line 612, in blend
return type_mixer.blend(**values)
File "/home/cllamach/PythonProjects/mixer/mixer/main.py", line 130, in blend
for name, value in defaults.items()
File "/home/cllamach/PythonProjects/mixer/mixer/main.py", line 130, in <genexpr>
for name, value in defaults.items()
File "/home/cllamach/PythonProjects/mixer/mixer/mix_types.py", line 220, in gen_value
return type_mixer.gen_field(field)
File "/home/cllamach/PythonProjects/mixer/mixer/main.py", line 209, in gen_field
return self.gen_value(field.name, field, unique=unique)
File "/home/cllamach/PythonProjects/mixer/mixer/main.py", line 254, in gen_value
gen = self.get_generator(field, field_name, fake=fake)
File "/home/cllamach/PythonProjects/mixer/mixer/main.py", line 304, in get_generator
field.scheme, field_name, fake, kwargs=field.params)
File "/home/cllamach/PythonProjects/mixer/mixer/backend/sqlalchemy.py", line 178, in make_generator
stype, field_name=field_name, fake=fake, args=args, kwargs=kwargs)
File "/home/cllamach/PythonProjects/mixer/mixer/main.py", line 324, in make_generator
fabric = self.__factory.gen_maker(scheme, field_name, fake)
File "/home/cllamach/PythonProjects/mixer/mixer/factory.py", line 157, in gen_maker
if not func and fcls.__bases__:
AttributeError: Mixer (<class 'tests.test_flask.IpAddressUser'>): 'NoneType' object has no attribute '__bases__'

我将这个错误一直调试到代码中的几个方法,第一个方法get_generator尝试以下方法......

if key not in self.__generators:
        self.__generators[key] = self.make_generator(
            field.scheme, field_name, fake, kwargs=field.params)

而且这是奇怪的部分。在这个语句中,field.scheme有一个值,特别是sqlalchemy中的Column对象,但是当传递给make_generetor方法时,它作为None传递。到目前为止,我已经看到这两种方法之间没有其他代码,已经使用ipdb和其他方法进行了调试。尝试使用ipdb手动调用该方法,但仍然将该方案传递给无。

我知道这可以被认为是一个特别的问题,但我想知道以前是否有人遇到过这类问题,因为这对我来说是第一次。

2 个答案:

答案 0 :(得分:2)

混音器在未知列类型上窒息。它将GenFactory.types中知道的所有内容存储为dict并调用types.get(column_type),这当然会返回None以获取无法识别的类型。我碰到了这个,因为我用sqlalchemy.types.TypeDecorator定义了几个自定义的SQLAlchemy类型。

要解决此问题,您必须将您的类型修补为Mixer的类型系统。我是这样做的:

def _setup_mixer_with_custom_types():
    from mixer._faker import faker
    from mixer.backend.sqlalchemy import (
        GenFactory,
        mixer,
    )
    from myproject.customcolumntypes import (
        IntegerTimestamp,
        UTCDateTimeTimestamp,
    )

    def arrow_generator():
        return arrow.get(faker.date_time())

    GenFactory.generators[IntegerTimestamp] = arrow_generator
    GenFactory.generators[UTCDateTimeTimestamp] = arrow_generator

    return mixer

mixer = _setup_mixer_with_custom_types()

请注意,您实际上不必触摸GenFactory.types,因为如果它可以直接在GenFactory.generators上找到您的类型,那么它只是Mixer跳过的中间步骤。

在我的情况下,我还必须定义一个自定义生成器(以容纳Arrow),但您可能不需要。调音台使用fake-factory库生成虚假数据,您可以通过查看GenFactory.generators字典来查看他们正在使用的内容。

答案 1 :(得分:1)

您必须将列类型放入GenFactory.generators,默认情况下只包含一些标准类型。您可以继承GenFactory,然后在生成Mixer时指定自己的类,而不是猴子修补。

在这种情况下,我们会自定义GenFactory已经存在子类的Mixerbackend.sqlalchemy变体:

from mixer.backend.sqlalchemy import Mixer, GenFactory
from customtypes import CustomType    # The column type

def get_mixer():
    class CustomFactory(GenFactory):
        # No need to preserve entries, the parent class attribute is
        # automatically extended through GenFactory's metaclass
        generators = {
            CustomType: lambda: 42    # Or any other function
        }

    return Mixer(factory=CustomFactory)

您可以使用您喜欢的任何函数作为生成器,它只需返回所需的值。有时,直接使用faker中的内容可能就足够了。

同样,您还可以自定义GenFactory的其他属性,即fakerstypes