Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: convert dataframe tests #17655

Merged
merged 1 commit into from
Dec 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 0 additions & 53 deletions tests/integration_tests/dataframe_test.py

This file was deleted.

12 changes: 10 additions & 2 deletions tests/unit_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,22 @@

import pytest

from superset.app import SupersetApp
from superset.initialization import SupersetAppInitializer


@pytest.fixture
def app_context():
"""
A fixture for running the test inside an app context.
"""
from superset.app import create_app
app = SupersetApp(__name__)

app.config.from_object("superset.config")
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite://"

app_initializer = app.config.get("APP_INITIALIZER", SupersetAppInitializer)(app)
app_initializer.init_app()

app = create_app()
with app.app_context():
yield
55 changes: 55 additions & 0 deletions tests/unit_tests/dataframe_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: disable=unused-argument, import-outside-toplevel
from superset.dataframe import df_to_records
from superset.typing import DbapiDescription


def test_df_to_records(app_context: None) -> None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def test_df_to_records(app_context: None) -> None:
def test_df_to_records(_: None) -> None:

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need app_context here to be named as is, since it's a fixture used by the test.

from superset.db_engine_specs import BaseEngineSpec
from superset.result_set import SupersetResultSet

data = [("a1", "b1", "c1"), ("a2", "b2", "c2")]
cursor_descr: DbapiDescription = [
(column, "string", None, None, None, None, False) for column in ("a", "b", "c")
]
results = SupersetResultSet(data, cursor_descr, BaseEngineSpec)
df = results.to_pandas_df()

assert df_to_records(df) == [
{"a": "a1", "b": "b1", "c": "c1"},
{"a": "a2", "b": "b2", "c": "c2"},
]


def test_js_max_int(app_context: None) -> None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def test_js_max_int(app_context: None) -> None:
def test_js_max_int(_: None) -> None:

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. It's a weird behavior of pytest, but we specify which fixtures we want based on their names.

from superset.db_engine_specs import BaseEngineSpec
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason why these aren't at the top of the file?

Copy link
Member Author

@betodealmeida betodealmeida Dec 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, these imports need to be done inside an app_context, otherwise they fail:

>>> from superset.db_engine_specs import BaseEngineSpec
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/beto/Projects/incubator-superset/superset/db_engine_specs/__init__.py", line 43, in <module>
    from superset.db_engine_specs.base import BaseEngineSpec
  File "/Users/beto/Projects/incubator-superset/superset/db_engine_specs/base.py", line 61, in <module>
    from superset.models.sql_lab import Query
  File "/Users/beto/Projects/incubator-superset/superset/models/__init__.py", line 17, in <module>
    from . import (
  File "/Users/beto/Projects/incubator-superset/superset/models/alerts.py", line 53, in <module>
    class Alert(Model, AuditMixinNullable):
  File "/Users/beto/Projects/incubator-superset/superset/models/alerts.py", line 66, in Alert
    owners = relationship(security_manager.user_model, secondary=alert_owner)
  File "/Users/beto/.pyenv/versions/superset/lib/python3.8/site-packages/werkzeug/local.py", line 347, in __getattr__
    return getattr(self._get_current_object(), name)
AttributeError: 'NoneType' object has no attribute 'user_model'
>>>

The app_context fixture will do the initialization needed for the import. This way, it works when ran inside the test, but fails as a top-level import.

Note that this is a consequence of bad architecture in Superset. You can see that when we import BaseEngineSpec it assumes that a user model is defined in the security manager, and it fails.

from superset.result_set import SupersetResultSet

data = [(1, 1239162456494753670, "c1"), (2, 100, "c2")]
cursor_descr: DbapiDescription = [
("a", "int", None, None, None, None, False),
("b", "int", None, None, None, None, False),
("c", "string", None, None, None, None, False),
]
results = SupersetResultSet(data, cursor_descr, BaseEngineSpec)
df = results.to_pandas_df()

assert df_to_records(df) == [
{"a": 1, "b": "1239162456494753670", "c": "c1"},
{"a": 2, "b": 100, "c": "c2"},
]