Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Getting the next structure hook

オープン
#794 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
25/100
issue の種類
機能追加
明瞭さ
説明が足りない
活発さ
活発
技術スタック
python
領域
data

調査の方向性

The issue asks how to chain a pre-normalization step in front of structure hooks, and it mentions get_structure_hook, make_dict_structure_fn, register_structure_hook_factory and use_class_methods. Read how those hooks are resolved and why a generic like list[Foo] raises StructureHandlerNotFoundError, and check the linked attrs issue for the attrib.type string behaviour. Done would be a maintainer-agreed design for field converters running before structuring, with tests for the ensure_list case.

索引モデルが issue の本文から書いたものです。

説明

I am trying to wrap and combine attrs.Converter and the structure hook to have a pre-normalization step before the structure logic kicks in. There are 2 issues I hit

Pre-normalizing the class

Here the issue is that I cannot get the original (or next preferred) structure, roughly can simulate it with

use_class_methods(raw_converter, "from_raw", "to_raw")

@define
class Foo:
    a: str
    b: int = 1

    @classmethod
    def from_raw(cls, data, converter):
        if isinstance(data, str):
            data = {"a": data}
        if not isinstance(data, dict):
            raise TypeEroor("Unsupported")
        original_structure = structure.get_structure_hook(cls)
        return original_structure(data, cls)

The recursion here is rather obvious, but there is no way to get n layers further down in the preference to get the next structure hook. Even if it was to be hard-coded or only go one layer further would probably work for most cases.

Pre-normalizing the fields

This is most likely a PEBKAC, but I get StructureHandlerNotFoundError when trying to get the structure hook of a generic. Basically the end goal is to have

@define
class Foo:
    a: str

def ensure_list(data):
    if not isinstance(data, list):
        data = [data]
    return data

@define
class Bar:
    foo: list[Foo] = field(converter=ensure_list)

@raw_converter.register_structure_hook_factory(has)
def structure_attrs_with_converter(cls, converter):
    cls_structure = cattrs.gen.make_dict_structure_fn(
        cls,
        converter,
        **{
            attrib.name: override(struct_hook=attr_structure)
            for attrib in attrs.fields(cls)
            if (
                attr_structure := structure_field_with_converter(
                    attrib=attrib,
                    converter=converter,
                )
            )
        },
    )
    return cls_structure

def structure_field_with_converter(attrib, converter):
    if not attrib.converter:
        return None
    original_structure = converter.get_structure_hook(attrib.type)

    def structure(raw_value, _type):
        value = attrib.converter(raw_value, None, attrib)
        return original_structure(value, _type)

    return structure

core of the issue here is that attrib.type given here is a str, not even a ForwardRef that I could later evaluate 🤔
Edit: Aha, it's an attrs bug https://github.com/python-attrs/attrs/issues/1596

Also I have tried to get attrs.Converter and cattrs to work nicely together, but so far this is the only way I found feasible. The issue is that the attrs.Converter must run before the main structure of the class, otherwise it will try to structure each element in the foo key before making sure it is a list in this example. If there are other ways to design this, that would be welcome, since this can get a bit messy.


This might be related to https://github.com/python-attrs/cattrs/issues/659?

主要言語
Python
スター
1.1k
フォーク
171
平均マージ
14時間 46分
マージ済み PR(30日)
5

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

python-attrs/cattrs のほかの issue

python-attrs/cattrs の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。