我在Python的klen调音台库中偶然发现了一个非常有趣的错误。
每当您尝试使用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手动调用该方法,但仍然将该方案传递给无。
我知道这可以被认为是一个特别的问题,但我想知道以前是否有人遇到过这类问题,因为这对我来说是第一次。
答案 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
已经存在子类的Mixer
和backend.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
的其他属性,即fakers
和types
。