2017-07-12 15 views
1

データベースにオブジェクトを格納し、可能であれば戻すことができるように、ORM以外のクラスのORMバージョンを開発しようとしています。私は今、達成したい何非ormクラスからのSQLAlchemy継承

from ruamel.yaml import YAMLObject 

class User(YAMLObject): 
    yaml_tag = u'user' 

    def __init__(self, name, age): 
     self.name = name 
     self.age = age 

    # Other useful methods 

は、Pythonの世界でUserのような役割を果たし同様のオブジェクト、ですが、それは、したがって、それをデータベースに格納することができること、ORMオブジェクトとしても使用することができます。私が試した何を、ingenuously、次のとおりです。

Base = declarative_base() 

class SQLUser(Base, User): 

    id = Column(Integer, primary_key=True) 
    name = Column(String) 
    age = Column(Integer) 

    def __init__(self, name, age): 
     self.name = name 
     self.age = age 

このクラス階層は、Python 2、次のエラーで、生産して例を実行:

TypeError: Error when calling the metaclass bases metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

私はこれがYAMLObjectメタクラスに関連していると信じて...しかし、YAMLとしてそれらのオブジェクトを保存できるようにしたいので、私はそれが必要です。私は、多分、私がしたいクラスを作成するためにそれを使用して、YAMLObjectメタクラスからとBaseの両方を継承する第三メタクラスを使用する必要があります。このエラーについて読んだもののために...

class MetaMixinUser(type(User), type(Base)): 
    pass 

class SQLUser(six.with_metaclass(MetaMixinUser)): 
    #[...] 

は、残念ながら、これは別のエラーを与えます:

AttributeError: type object 'SQLUser' has no attribute '_decl_class_registry'

私の推理に欠陥がある場所を教えてください。お急ぎの場合は

+0

あなたは 'ダンプできるようにYAMLObject''を継承する必要はありませんthisアルバムのタイトル曲で表現しましたユーザー '。サブクラス化は、IMOがダンピングとロードを可能にする最も邪魔な方法です。また、 'User'クラスは' yaml_tag'を持たないのでおそらく動作しません。 'YAMLObject'への依存を取り除いていますか? – Anthon

+0

@Anthon申し訳ありませんが、私は 'yaml_tag'を省略しましたが、そこにあります。私は私の質問を編集しました。 'User'クラスはそれ自身で正しく動作します(クラスをYAMLファイルに正しくダンプできるように' to_yaml'メソッドを実装しました)。私はすべてにオープンですが、このようにして、エンドユーザに透明な方法でオブジェクトをダンプすることができます。 'yaml.dump'だけが期待どおりに動作します... – SolidSnake

+0

[ruamel.yaml'への登録と装飾](http://yaml.readthedocs.io/ja/latest/dumpcls.html)を追加しました。あなたが実際に使用した答えの中のどの解決策がわかりませんが、登録はあなたのために機能するはずです。飾り付けは、それがするラッピングのために依然として干渉する可能性があります。 – Anthon

答えて

1

ruamel.yaml 0.15.19のあなたYAMLObjectのサブクラス化せずに1文を使用してregister classes、次のことができます。

yaml = ruamel.yaml.YAML() 
yaml.register_class(User) 

YAMLObjectはPyYAMLととの後方互換性のためにそこにある、とそれは便利かもしれませんが、私は本当に三つの理由のためにそれを使用することをお勧めすることはできません。

  1. それはあなたのクラス階層を依存させます、あなたが気づいたように、他の依存関係
  2. それはデフォルト
  3. として便利であまり邪魔になり、Pythonのデコレータに基づくソリューションにより、危険なLoader使用を妨害する可能性がYAMLObject、上。 YAMLObjectをサブクラス化することはありません

唯一の本物はそのyaml_tagためconstructorおよびサブクラスのrepresenterを登録しています。

すべての例では、Python 2を実行するとfrom __future__ import print_functionと仮定しています。

あなたがサブクラス化YAMLObjectに基づいて、以下、持っている場合:

import sys 
import ruamel.yaml 
from ruamel.std.pathlib import Path 

yaml = ruamel.yaml.YAML(typ='unsafe') 

class User(ruamel.yaml.YAMLObject): 
    yaml_tag = u'user' 

    def __init__(self, name, age): 
     self.name = name 
     self.age = age 

    @classmethod 
    def to_yaml(cls, representer, node): 
     return representer.represent_scalar(cls.yaml_tag, 
              u'{.name}-{.age}'.format(node, node)) 

    @classmethod 
    def from_yaml(cls, constructor, node): 
     # type: (Any, Any) -> Any 
     return User(*node.value.split('-')) 


data = {'users': [User('Anthon', 18)]} 
yaml.dump(data, sys.stdout) 
print() 
tmp_file = Path('tmp.yaml') 
yaml.dump(data, tmp_file) 
rd = yaml.load(tmp_file) 
print(rd['users'][0].name, rd['users'][0].age) 

あなたを取得します:

users: [!<user> Anthon-18] 

Anthon 18 

をあなたが行うことによって、サブクラス化せずに正確に同じ結果を得ることができます

import sys 
import ruamel.yaml 
from ruamel.std.pathlib import Path 

yaml = ruamel.yaml.YAML(typ='safe') 

class User(object): 
    yaml_tag = u'user' 

    def __init__(self, name, age): 
     self.name = name 
     self.age = age 

    @classmethod 
    def to_yaml(cls, representer, node): 
     return representer.represent_scalar(cls.yaml_tag, 
              u'{.name}-{.age}'.format(node, node)) 

    @classmethod 
    def from_yaml(cls, constructor, node): 
     # type: (Any, Any) -> Any 
     return User(*node.value.split('-')) 


yaml.representer.add_representer(User, User.to_yaml) 
yaml.constructor.add_constructor(User.yaml_tag, User.from_yaml) 

data = {'users': [User('Anthon', 18)]} 

yaml.dump(data, sys.stdout) 
print() 
tmp_file = Path('tmp.yaml') 
yaml.dump(data, tmp_file) 
rd = yaml.load(tmp_file) 
print(rd['users'][0].name, rd['users'][0].age) 

上記では、SafeLoader(およびSafeDumper)、これは正しい方向の一歩です。しかし、上記のXXXX.add_YYY行を追加することは、クラスがたくさんある場合は迷惑です。そのようなエントリはほぼ同じですが、全く同じではないためです。そして、to_yamlfrom_yamlのいずれかまたは両方が欠けているクラスは処理されません。

import sys 
from ruamel.std.pathlib import Path 
from myyaml import yaml, yaml_object 

@yaml_object 
class User(object): 
    yaml_tag = u'user' 

    def __init__(self, name, age): 
     self.name = name 
     self.age = age 

    @classmethod 
    def to_yaml(cls, representer, node): 
     return representer.represent_scalar(cls.yaml_tag, 
              u'{.name}-{.age}'.format(node, node)) 

    @classmethod 
    def from_yaml(cls, constructor, node): 
     # type: (Any, Any) -> Any 
     return User(*node.value.split('-')) 


data = {'users': [User('Anthon', 18)]} 

yaml.dump(data, sys.stdout) 
print() 
tmp_file = Path('tmp.yaml') 
yaml.dump(data, tmp_file) 
rd = yaml.load(tmp_file) 
print(rd['users'][0].name, rd['users'][0].age) 

を再び同じ結果と:あなたが行うことができます持つ

import ruamel.yaml 

yaml = ruamel.yaml.YAML(typ='safe') 

class SafeYAMLObject(object): 
    def __init__(self, cls): 
     self._cls = cls 

    def to_yaml(self, representer, data): 
     return representer.represent_yaml_object(
      self._cls.yaml_tag, data, self._cls, 
      flow_style=representer.default_flow_style) 

    def from_yaml(self, constructor, node): 
     return constructor.construct_yaml_object(node, self._cls) 

def yaml_object(cls): 
    yaml.representer.add_representer(
     cls, getattr(cls, 'to_yaml', SafeYAMLObject(cls).to_yaml)) 
    yaml.constructor.add_constructor(
     cls.yaml_tag, getattr(cls, 'from_yaml', SafeYAMLObject(cls).from_yaml)) 
    return cls 

:私はあなたがファイルmyyaml.pyにデコレータyaml_objectとヘルパークラスを作る提案する上で解決するために

。あなたはto_yamlfrom_yaml方法を削除する場合は、同じ最終値が、わずかに異なるYAMLはなります

users: 
- !<user> {age: 18, name: Anthon} 

Anthon 18 

私はこれをテストすることができていないが、代わりにサブクラスYAMLObjectのこのデコレータを使用することを取り除く必要がありますTypeErrorやって:

class SQLUser(Base, User): 

免責事項を¹:私はこのANSで使用ruamel.yamlパッケージの作者ですワー。
   免責事項2:私は本当に18ではないが、私はブライアン・アダムスのadagiumに従ってくださいは

関連する問題