Ошибка NoneType при попытке создать пользовательский тип BeautifulSoup Dagster - PullRequest
2 голосов
/ 25 января 2020

Я возился с @dagster_type и пытался создать пользовательский тип HtmlSoup. В основном это необычная @dagster_type оболочка вокруг объекта BeautifulSoup.

import requests
from bs4 import BeautifulSoup
from dagster import (
    dagster_type,
    input_hydration_config,
    Selector,
    Field,
    String,
    TypeCheck,
    EventMetadataEntry
)

def max_depth(soup):
    if hasattr(soup, "contents") and soup.contents:
        return max([max_depth(child) for child in soup.contents]) + 1
    else:
        return 0

def html_soup_type_check(value):
    if not isinstance(value, BeautifulSoup):
        return TypeCheck(
            success=False,
            description=(
                'HtmlSoup should be a BeautifulSoup Object, got '
                '{type_}'
            ).format(type_=type(value))
        )

    if not hasattr(soup, "contents"):
        return TypeCheck(
            success=False,
            description=(
                'HtmlSoup has no contents, check that the URL has content'
            )
        )

    return TypeCheck(
        success=True,
        description='HtmlSoup Summary Stats',
        metadata_entries=[
            EventMetadataEntry.text(
                str(max_depth(value)),
                'max_depth',
                'Max Nested Depth of the Page Soup'
            ),
            EventMetadataEntry.text(
                str(set(tag.name for tag in value.find_all())),
                'tag_names',
                'All available tags in the Page Soup'
            )
        ]
    )


@input_hydration_config(
    Selector(
        {
            'url': Field(
                String,
                is_optional=False,
                description=(
                    'URL to be ingested and converted to a Soup Object'
                )
            )
        }
    )
)
def html_soup_input_hydration_config(context, selector):
    url = selector['url']
    res = requests.get(url, params={
        'Content-type': 'text/html'
    })

    if (not res.status_code == 200):
        return TypeCheck(
            success=False,
            description=(
                '{status_code} ERROR, Check that URL: {url} is correct'
            ).format(status_code=res.status_code, url=url)
        )
    soup = BeautifulSoup(res.content, 'html.parser')
    return HtmlSoup(soup)

@dagster_type(
    name='HtmlSoup',
    description=(
        'The HTML extracted from a URL stored in '
        'a BeautifulSoup object.'
    ),
    type_check=html_soup_type_check,
    input_hydration_config=html_soup_input_hydration_config
)
class HtmlSoup(BeautifulSoup):
    pass

Это то, что я пробовал, но всякий раз, когда я пытаюсь вызвать solid, который использует, принимает в качестве ввода HtmlSoup, например,

@solid
def get_url(context, soup: HtmlSoup):
    return soup.contents

Я получаю эту ошибку

TypeError: объект 'NoneType' не вызывается

  File "/Users/John/Documents/.../venv/lib/python3.7/site-packages/dagster/core/engine/engine_inprocess.py", line 241, in dagster_event_sequence_for_step
    for step_event in check.generator(_core_dagster_event_sequence_for_step(step_context)):
  File "/Users/John/Documents/.../venv/lib/python3.7/site-packages/dagster/core/engine/engine_inprocess.py", line 492, in _core_dagster_event_sequence_for_step
    for input_name, input_value in _input_values_from_intermediates_manager(step_context).items():
  File "/Users/John/Documents/.../venv/lib/python3.7/site-packages/dagster/core/engine/engine_inprocess.py", line 188, in _input_values_from_intermediates_manager
    step_context, step_input.config_data
  File "/Users/John/Documents/.../venv/lib/python3.7/site-packages/dagster/core/types/config_schema.py", line 73, in construct_from_config_value
    return func(context, config_value)
  File "/Users/John/Documents/.../custom_types/html_soup.py", line 82, in html_soup_input_hydration_config
    return HtmlSoup(soup)
  File "/Users/John/Documents/.../venv/lib/python3.7/site-packages/bs4/__init__.py", line 286, in __init__
    markup = markup.read()

Я получил дополнительную информацию, которая говорит:

An exception was thrown during execution that is likely a framework error, rather than an error in user code.
Original error message: TypeError: 'NoneType' object is not callable

Я был сейчас немного покопаться во внутренностях декоратора @dagster_type и о том, как работает декоратор @input_hydration_config, но пока что он немного растерялся.

Цените любую помощь!

1 Ответ

1 голос
/ 28 января 2020

Я действительно смог понять это с помощью метода as_dagster_type, описанного в документации

HtmlSoup = as_dagster_type(
    BeautifulSoup,
    name='BeautifulSoupHTML',
    description='''
        Beautiful Soup HTML Object
    ''',
    input_hydration_config=html_soup_input_hydration_config,
    type_check=html_soup_type_check
)
...