Skip to content

STYLE use absolute imports #39561

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

Merged
merged 2 commits into from
Feb 3, 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
5 changes: 5 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,8 @@ repos:
rev: v0.1.6
hooks:
- id: no-string-hints
- repo: https://github.com/MarcoGorelli/abs-imports
rev: v0.1.2
hooks:
- id: abs-imports
files: ^pandas/
2 changes: 1 addition & 1 deletion pandas/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@
import pandas.arrays

# use the closest tagged version if possible
from ._version import get_versions
from pandas._version import get_versions
Copy link
Member

Choose a reason for hiding this comment

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

is this added automatically by versioneer?

Copy link
Member Author

Choose a reason for hiding this comment

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

yes, thanks for spotting this - I've updated versioneer.py to use an absolute import


v = get_versions()
__version__ = v.get("closest-tag", v["version"])
Expand Down
34 changes: 22 additions & 12 deletions pandas/_libs/tslibs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,28 @@
"tz_compare",
]

from . import dtypes
from .conversion import OutOfBoundsTimedelta, localize_pydatetime
from .dtypes import Resolution
from .nattype import NaT, NaTType, iNaT, is_null_datetimelike, nat_strings
from .np_datetime import OutOfBoundsDatetime
from .offsets import BaseOffset, Tick, to_offset
from .period import IncompatibleFrequency, Period
from .timedeltas import Timedelta, delta_to_nanoseconds, ints_to_pytimedelta
from .timestamps import Timestamp
from .timezones import tz_compare
from .tzconversion import tz_convert_from_utc_single
from .vectorized import (
from pandas._libs.tslibs import dtypes
from pandas._libs.tslibs.conversion import OutOfBoundsTimedelta, localize_pydatetime
from pandas._libs.tslibs.dtypes import Resolution
from pandas._libs.tslibs.nattype import (
NaT,
NaTType,
iNaT,
is_null_datetimelike,
nat_strings,
)
from pandas._libs.tslibs.np_datetime import OutOfBoundsDatetime
from pandas._libs.tslibs.offsets import BaseOffset, Tick, to_offset
from pandas._libs.tslibs.period import IncompatibleFrequency, Period
from pandas._libs.tslibs.timedeltas import (
Timedelta,
delta_to_nanoseconds,
ints_to_pytimedelta,
)
from pandas._libs.tslibs.timestamps import Timestamp
from pandas._libs.tslibs.timezones import tz_compare
from pandas._libs.tslibs.tzconversion import tz_convert_from_utc_single
from pandas._libs.tslibs.vectorized import (
dt64arr_to_periodarr,
get_resolution,
ints_to_pydatetime,
Expand Down
3 changes: 1 addition & 2 deletions pandas/core/arrays/boolean.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@
from pandas.core.dtypes.missing import isna

from pandas.core import ops

from .masked import BaseMaskedArray, BaseMaskedDtype
from pandas.core.arrays.masked import BaseMaskedArray, BaseMaskedDtype

if TYPE_CHECKING:
import pyarrow
Expand Down
3 changes: 1 addition & 2 deletions pandas/core/arrays/floating.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@
from pandas.core.dtypes.dtypes import ExtensionDtype, register_extension_dtype
from pandas.core.dtypes.missing import isna

from pandas.core.arrays.numeric import NumericArray, NumericDtype
from pandas.core.ops import invalid_comparison
from pandas.core.tools.numeric import to_numeric

from .numeric import NumericArray, NumericDtype


class FloatingDtype(NumericDtype):
"""
Expand Down
5 changes: 2 additions & 3 deletions pandas/core/arrays/integer.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,11 @@
)
from pandas.core.dtypes.missing import isna

from pandas.core.arrays.masked import BaseMaskedArray, BaseMaskedDtype
from pandas.core.arrays.numeric import NumericArray, NumericDtype
from pandas.core.ops import invalid_comparison
from pandas.core.tools.numeric import to_numeric

from .masked import BaseMaskedArray, BaseMaskedDtype
from .numeric import NumericArray, NumericDtype


class _IntegerDtype(NumericDtype):
"""
Expand Down
3 changes: 1 addition & 2 deletions pandas/core/arrays/numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
)

from pandas.core import ops

from .masked import BaseMaskedArray, BaseMaskedDtype
from pandas.core.arrays.masked import BaseMaskedArray, BaseMaskedDtype

if TYPE_CHECKING:
import pyarrow
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/arrays/timedeltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ def _add_period(self, other: Period):
Add a Period object.
"""
# We will wrap in a PeriodArray and defer to the reversed operation
from .period import PeriodArray
from pandas.core.arrays.period import PeriodArray

i8vals = np.broadcast_to(other.ordinal, self.shape)
oth = PeriodArray(i8vals, freq=other.freq)
Expand Down
4 changes: 2 additions & 2 deletions pandas/core/strings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# - PandasArray
# - Categorical

from .accessor import StringMethods
from .base import BaseStringArrayMethods
from pandas.core.strings.accessor import StringMethods
from pandas.core.strings.base import BaseStringArrayMethods

__all__ = ["StringMethods", "BaseStringArrayMethods"]
3 changes: 1 addition & 2 deletions pandas/tests/api/test_types.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import pandas._testing as tm
from pandas.api import types

from .test_api import Base
from pandas.tests.api.test_api import Base


class TestTypes(Base):
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/arithmetic/test_period.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@
import pandas._testing as tm
from pandas.core import ops
from pandas.core.arrays import TimedeltaArray

from .common import assert_invalid_comparison
from pandas.tests.arithmetic.common import assert_invalid_comparison

# ------------------------------------------------------------------
# Comparisons
Expand Down
5 changes: 4 additions & 1 deletion pandas/tests/extension/arrow/test_bool.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@

pytest.importorskip("pyarrow", minversion="0.13.0")

from .arrays import ArrowBoolArray, ArrowBoolDtype # isort:skip
from pandas.tests.extension.arrow.arrays import ( # isort:skip
ArrowBoolArray,
ArrowBoolDtype,
)


@pytest.fixture
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/extension/arrow/test_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

pytest.importorskip("pyarrow", minversion="0.13.0")

from .arrays import ArrowStringDtype # isort:skip
from pandas.tests.extension.arrow.arrays import ArrowStringDtype # isort:skip


def test_constructor_from_list():
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/extension/arrow/test_timestamp.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

import pyarrow as pa # isort:skip

from .arrays import ArrowExtensionArray # isort:skip
from pandas.tests.extension.arrow.arrays import ArrowExtensionArray # isort:skip


@register_extension_dtype
Expand Down
28 changes: 14 additions & 14 deletions pandas/tests/extension/base/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,26 @@ class TestMyDtype(BaseDtypeTests):
``assert_series_equal`` on your base test class.

"""
from .casting import BaseCastingTests # noqa
from .constructors import BaseConstructorsTests # noqa
from .dtype import BaseDtypeTests # noqa
from .getitem import BaseGetitemTests # noqa
from .groupby import BaseGroupbyTests # noqa
from .interface import BaseInterfaceTests # noqa
from .io import BaseParsingTests # noqa
from .methods import BaseMethodsTests # noqa
from .missing import BaseMissingTests # noqa
from .ops import ( # noqa
from pandas.tests.extension.base.casting import BaseCastingTests # noqa
from pandas.tests.extension.base.constructors import BaseConstructorsTests # noqa
Copy link
Member

Choose a reason for hiding this comment

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

Personally, I am -1 on general linting check for this. For example, this specific example where I am commenting on, I find the relative imports actually more readable.

Copy link
Member

Choose a reason for hiding this comment

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

I agree with Joris on this (more generally, i like relative imports for same-directory as it clarified dependency structure)

Copy link
Member Author

@MarcoGorelli MarcoGorelli Feb 8, 2021

Choose a reason for hiding this comment

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

I have no strong opinion here, I was just following the (existing) pandas style guide - should the style guide be changed so an exception is made for same-level imports?

Or this can be reverted if you wish, it was a really good learning exercise anyway.

My personal preference would be to have some kind of rule agreed on, but again, not a strong opinion

Copy link
Contributor

Choose a reason for hiding this comment

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

if we had easily automatic check able for relative imports that would be ok for a limited purpose

we cannot expreess 'more readable' in this way and have it enforced

this is why i am currently -1 on relative imports and why we cannot use them in the code base

Copy link
Member

Choose a reason for hiding this comment

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

I was just following the (existing) pandas style guide - should the style guide be changed so an exception is made for same-level imports?

The part of the style guide about general relative imports, of course fully agreed that we never want implicit relative imports. But personally I think we should reconsider explicit ones, yes.

more generally, i like relative imports for same-directory as it clarified dependency structure

+1, I also find this helpful. I think it should certainly be doable to have a check that relative imports are never outside the local directory

Copy link
Member

Choose a reason for hiding this comment

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

I just don't (yet) see why you'd make an exception for same-directory imports. Doesn't from ..foo import bar also clarify the dependency structure?

there are a bunch of places where we have dependency structure rules (imperfectly enforced, so maybe better thought of as aspirations) of the form "this file doesnt depend on anything else in pandas except other files in this directory or things explicitly higher up in the dependency structure":

pandas._config
pandas._libs.tslibs (depends only on _config)
pandas._libs (depends almost-only on tslibs)
pandas.tseries (depends only on tslibs)
pandas.core.dtypes (depends almost-only on _libs)
pandas.core.arrays (depends almost^2-only on dtypes)
pandas.core.indexes (doesnt depend in groupby or internals)

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for explaining, I hadn't appreciated that - I'll look into this and see how to adapt imports

Copy link
Member Author

@MarcoGorelli MarcoGorelli Feb 17, 2021

Choose a reason for hiding this comment

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

pandas.core.arrays (depends almost^2-only on dtypes)

@jbrockmendel just to make sure I've understood, are you suggesting that every file inside pandas/core/arrays should import from pandas/core/arrays in a relative manner? For example, in pandas/core/arrays/sparse/array.py there is

from pandas.core.arrays import ExtensionArray

, would you want that to be from .. import ExtensionArray instead?

Copy link
Member

Choose a reason for hiding this comment

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

would you want that to be from .. import ExtensionArray instead?

No, I would essentially never use from .. import, only from . import

Note that isort has a LOCALFOLDER section, so from . imports get put below everything else, which is consistent with the pattern of laying out imports in rough order of dependency structure

Copy link
Member Author

Choose a reason for hiding this comment

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

OK, so you'd always use a relative import when importing from the same directory (even outside of the folders you listed above), and use absolute elsewhere? If so, this seems easily enforceable, I can make a PR later this week

from pandas.tests.extension.base.dtype import BaseDtypeTests # noqa
from pandas.tests.extension.base.getitem import BaseGetitemTests # noqa
from pandas.tests.extension.base.groupby import BaseGroupbyTests # noqa
from pandas.tests.extension.base.interface import BaseInterfaceTests # noqa
from pandas.tests.extension.base.io import BaseParsingTests # noqa
from pandas.tests.extension.base.methods import BaseMethodsTests # noqa
from pandas.tests.extension.base.missing import BaseMissingTests # noqa
from pandas.tests.extension.base.ops import ( # noqa
BaseArithmeticOpsTests,
BaseComparisonOpsTests,
BaseOpsUtil,
BaseUnaryOpsTests,
)
from .printing import BasePrintingTests # noqa
from .reduce import ( # noqa
from pandas.tests.extension.base.printing import BasePrintingTests # noqa
from pandas.tests.extension.base.reduce import ( # noqa
BaseBooleanReduceTests,
BaseNoReduceTests,
BaseNumericReduceTests,
)
from .reshaping import BaseReshapingTests # noqa
from .setitem import BaseSetitemTests # noqa
from pandas.tests.extension.base.reshaping import BaseReshapingTests # noqa
from pandas.tests.extension.base.setitem import BaseSetitemTests # noqa
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/casting.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

import pandas as pd
from pandas.core.internals import ObjectBlock

from .base import BaseExtensionTests
from pandas.tests.extension.base.base import BaseExtensionTests


class BaseCastingTests(BaseExtensionTests):
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

import pandas as pd
from pandas.core.internals import ExtensionBlock

from .base import BaseExtensionTests
from pandas.tests.extension.base.base import BaseExtensionTests


class BaseConstructorsTests(BaseExtensionTests):
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/dtype.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@

import pandas as pd
from pandas.api.types import is_object_dtype, is_string_dtype

from .base import BaseExtensionTests
from pandas.tests.extension.base.base import BaseExtensionTests


class BaseDtypeTests(BaseExtensionTests):
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/getitem.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
import pytest

import pandas as pd

from .base import BaseExtensionTests
from pandas.tests.extension.base.base import BaseExtensionTests


class BaseGetitemTests(BaseExtensionTests):
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/groupby.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

import pandas as pd
import pandas._testing as tm

from .base import BaseExtensionTests
from pandas.tests.extension.base.base import BaseExtensionTests


class BaseGroupbyTests(BaseExtensionTests):
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@

import pandas as pd
import pandas._testing as tm

from .base import BaseExtensionTests
from pandas.tests.extension.base.base import BaseExtensionTests


class BaseInterfaceTests(BaseExtensionTests):
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
import pytest

import pandas as pd

from .base import BaseExtensionTests
from pandas.tests.extension.base.base import BaseExtensionTests


class BaseParsingTests(BaseExtensionTests):
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
import pandas as pd
import pandas._testing as tm
from pandas.core.sorting import nargsort

from .base import BaseExtensionTests
from pandas.tests.extension.base.base import BaseExtensionTests


class BaseMethodsTests(BaseExtensionTests):
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/missing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

import pandas as pd
import pandas._testing as tm

from .base import BaseExtensionTests
from pandas.tests.extension.base.base import BaseExtensionTests


class BaseMissingTests(BaseExtensionTests):
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
import pandas as pd
import pandas._testing as tm
from pandas.core import ops

from .base import BaseExtensionTests
from pandas.tests.extension.base.base import BaseExtensionTests


class BaseOpsUtil(BaseExtensionTests):
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/printing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
import pytest

import pandas as pd

from .base import BaseExtensionTests
from pandas.tests.extension.base.base import BaseExtensionTests


class BasePrintingTests(BaseExtensionTests):
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/reduce.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

import pandas as pd
import pandas._testing as tm

from .base import BaseExtensionTests
from pandas.tests.extension.base.base import BaseExtensionTests


class BaseReduceTests(BaseExtensionTests):
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/reshaping.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@

import pandas as pd
from pandas.core.internals import ExtensionBlock

from .base import BaseExtensionTests
from pandas.tests.extension.base.base import BaseExtensionTests


class BaseReshapingTests(BaseExtensionTests):
Expand Down
3 changes: 1 addition & 2 deletions pandas/tests/extension/base/setitem.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

import pandas as pd
import pandas._testing as tm

from .base import BaseExtensionTests
from pandas.tests.extension.base.base import BaseExtensionTests


class BaseSetitemTests(BaseExtensionTests):
Expand Down
7 changes: 6 additions & 1 deletion pandas/tests/extension/decimal/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
from .array import DecimalArray, DecimalDtype, make_data, to_decimal
from pandas.tests.extension.decimal.array import (
DecimalArray,
DecimalDtype,
make_data,
to_decimal,
)

__all__ = ["DecimalArray", "DecimalDtype", "to_decimal", "make_data"]
8 changes: 6 additions & 2 deletions pandas/tests/extension/decimal/test_decimal.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@
import pandas as pd
import pandas._testing as tm
from pandas.tests.extension import base

from .array import DecimalArray, DecimalDtype, make_data, to_decimal
from pandas.tests.extension.decimal.array import (
DecimalArray,
DecimalDtype,
make_data,
to_decimal,
)


@pytest.fixture
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/extension/json/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .array import JSONArray, JSONDtype, make_data
from pandas.tests.extension.json.array import JSONArray, JSONDtype, make_data

__all__ = ["JSONArray", "JSONDtype", "make_data"]
3 changes: 1 addition & 2 deletions pandas/tests/extension/json/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
import pandas as pd
import pandas._testing as tm
from pandas.tests.extension import base

from .array import JSONArray, JSONDtype, make_data
from pandas.tests.extension.json.array import JSONArray, JSONDtype, make_data


@pytest.fixture
Expand Down
Loading