Skip to content

Commit

Permalink
Drop Python 2 support (#759)
Browse files Browse the repository at this point in the history
* remove python 2 support from setup.py

* remove python 2 drop warning from init

* remove is_python_2 from feature_set_calculator

* remove use of backports.tempfile module

* remove python 2 logic from load_primitive_from_file

* remove is python 2 checks from agg primitives

* remove python2 logic from test_demo_data

* remove is_python_2 function

* remove pathlib backport

* remove funcsigs

* remove future library

* remove py27 circleci tests

* remove python 2 package dependency filters

* bump pytest to latest version

* fix tests to work with updated pytest version

* remove python 2 type check entity repr

* more repr changes

* remove is_string utils function

* update changelog

* remove unused try/except

* use exist_ok on makedirs to avoid try/catch

* remove utf-8 coding headers since it is default in python3

* remove final builtins import
  • Loading branch information
rwedge committed Oct 7, 2019
1 parent e21d639 commit 18e929d
Show file tree
Hide file tree
Showing 53 changed files with 57 additions and 297 deletions.
22 changes: 0 additions & 22 deletions .circleci/config.yml
Expand Up @@ -50,19 +50,13 @@ jobs:
- run:
name: "Trigger premium primitives tests for python 3.5"
command: "curl -u ${PP_K}: -d build_parameters[CIRCLE_JOB]=python-35 https://circleci.com/api/v1.1/project/github/FeatureLabs/premium-primitives/tree/master"
- run:
name: "Trigger premium primitives tests for python 2.7"
command: "curl -u ${PP_K}: -d build_parameters[CIRCLE_JOB]=python-27 https://circleci.com/api/v1.1/project/github/FeatureLabs/premium-primitives/tree/master"
run_premium_primitives_tests_on_release:
docker:
- image: circleci/buildpack-deps:curl
steps:
- run:
name: "Trigger premium primitives tests for python 3.5 release"
command: "curl -u ${PP_K}: -d build_parameters[CIRCLE_JOB]=python-35-ft-release https://circleci.com/api/v1.1/project/github/FeatureLabs/premium-primitives/tree/master"
- run:
name: "Trigger premium primitives tests for python 2.7 release"
command: "curl -u ${PP_K}: -d build_parameters[CIRCLE_JOB]=python-27-ft-release https://circleci.com/api/v1.1/project/github/FeatureLabs/premium-primitives/tree/master"

unit_tests:
working_directory: ~/featuretools
Expand Down Expand Up @@ -176,9 +170,6 @@ workflows:
version: 2
test_all_python_versions:
jobs:
- install_ft:
name: "py27 install featuretools"
image_tag: "2.7"
- install_ft:
name: "py35 install featuretools"
image_tag: "3.5"
Expand All @@ -187,11 +178,6 @@ workflows:
image_tag: "3.6"
- install_ft:
name: "py37 install featuretools"
- unit_tests:
name: "py27 unit tests"
image_tag: "2.7"
requires:
- "py27 install featuretools"
- unit_tests:
name: "py35 unit tests"
image_tag: "3.5"
Expand All @@ -207,11 +193,6 @@ workflows:
name: "py37 unit tests"
requires:
- "py37 install featuretools"
- lint_test:
name: "py27 lint test"
image_tag: "2.7"
requires:
- "py27 install featuretools"
- lint_test:
name: "py35 lint test"
image_tag: "3.5"
Expand All @@ -230,9 +211,6 @@ workflows:
name: "build docs"
requires:
- "py37 install featuretools"
- install_ft_complete:
name: "py27 install featuretools complete test"
image_tag: "2.7"
- install_ft_complete:
name: "py35 install featuretools complete test"
image_tag: "3.5"
Expand Down
9 changes: 3 additions & 6 deletions dev-requirements.txt
Expand Up @@ -2,16 +2,13 @@
codecov==2.0.15
flake8==3.7.8
autopep8==1.4.4
ipython==7.2.0; python_version>'3.4'
ipython==5.8.0; python_version<'3'
ipython==7.2.0
isort==4.3.21
jupyter==1.0.0
matplotlib==3.0.2; python_version>'3.4'
matplotlib==2.2.3; python_version<'3'
matplotlib==3.0.2
nbconvert==5.4.1
nbsphinx==0.4.2
Sphinx==2.0.1; python_version>'3.4'
Sphinx==1.8.5; python_version<'3'
Sphinx==2.0.1
sphinx_rtd_theme==0.4.3
nlp_primitives>=0.2.2
autonormalize >= 1.0.0
1 change: 1 addition & 0 deletions docs/source/changelog.rst
Expand Up @@ -7,6 +7,7 @@ Changelog
* Fixes
* Updates
* Changes
* Drop Python 2 support (:pr:`759`)
* Documentation Changes
* Testing Changes

Expand Down
9 changes: 0 additions & 9 deletions featuretools/__init__.py
@@ -1,5 +1,4 @@
# flake8: noqa
from __future__ import absolute_import
import warnings
from .config_init import config
from . import variable_types
Expand Down Expand Up @@ -34,11 +33,3 @@
sys.modules["featuretools." + entry_point.name] = entry_point.load()
except Exception:
pass


from .utils.gen_utils import is_python_2
if is_python_2():
warnings.warn(
"The next non-bugfix release of Featuretools will not support Python 2",
FutureWarning
)
@@ -1,12 +1,9 @@
from __future__ import division

import logging
import math
import os
import shutil
import time
import warnings
from builtins import zip
from datetime import datetime

import cloudpickle
Expand Down
1 change: 0 additions & 1 deletion featuretools/computational_backends/feature_set.py
@@ -1,6 +1,5 @@
import itertools
import logging
from builtins import object
from collections import defaultdict

from featuretools.entityset.relationship import RelationshipPath
Expand Down
6 changes: 2 additions & 4 deletions featuretools/computational_backends/feature_set_calculator.py
Expand Up @@ -16,7 +16,7 @@
IdentityFeature,
TransformFeature
)
from featuretools.utils import Trie, is_python_2
from featuretools.utils import Trie
from featuretools.utils.gen_utils import get_relationship_variable_id

warnings.simplefilter('ignore', np.RankWarning)
Expand Down Expand Up @@ -587,9 +587,7 @@ def last_n(df):
# for some reason, using the string count is significantly
# faster than any method a primitive can return
# https://stackoverflow.com/questions/55731149/use-a-function-instead-of-string-in-pandas-groupby-agg
if is_python_2() and func == pd.Series.count.__func__:
func = "count"
elif func == pd.Series.count:
if func == pd.Series.count:
func = "count"

funcname = func
Expand Down
2 changes: 0 additions & 2 deletions featuretools/computational_backends/utils.py
@@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-

import logging
import os
import warnings
Expand Down
1 change: 0 additions & 1 deletion featuretools/demo/flight.py
@@ -1,6 +1,5 @@
import math
import re
from builtins import str

import pandas as pd
from tqdm import tqdm
Expand Down
4 changes: 0 additions & 4 deletions featuretools/demo/mock_customer.py
@@ -1,7 +1,3 @@
from __future__ import division

from builtins import range

import pandas as pd
from numpy import random
from numpy.random import choice
Expand Down
7 changes: 1 addition & 6 deletions featuretools/entityset/deserialize.py
@@ -1,6 +1,7 @@
import json
import os
import tarfile
import tempfile
from pathlib import Path

import boto3
Expand All @@ -10,18 +11,12 @@
from featuretools.entityset.serialize import FORMATS
from featuretools.utils.gen_utils import (
check_schema_version,
is_python_2,
use_s3fs_es,
use_smartopen_es
)
from featuretools.utils.wrangle import _is_s3, _is_url
from featuretools.variable_types.variable import LatLong, find_variable_types

if is_python_2():
from backports import tempfile
else:
import tempfile


def description_to_variable(description, entity=None):
'''Deserialize variable from variable description.
Expand Down
13 changes: 2 additions & 11 deletions featuretools/entityset/entity.py
@@ -1,15 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function

import logging
from builtins import range

import numpy as np
import pandas as pd
import pandas.api.types as pdtypes

from featuretools import variable_types as vtypes
from featuretools.utils import is_string
from featuretools.utils.entity_utils import (
col_is_datetime,
convert_all_variable_data,
Expand Down Expand Up @@ -95,10 +90,6 @@ def __repr__(self):
repr_out += u"\n Shape:\n (Rows: {}, Columns: {})".format(
shape[0], shape[1])

# encode for python 2
if type(repr_out) != str:
repr_out = repr_out.encode("utf-8")

return repr_out

@property
Expand Down Expand Up @@ -559,10 +550,10 @@ def _create_index(index, make_index, df):

def _validate_entity_params(id, df, time_index):
'''Validation checks for Entity inputs'''
assert is_string(id), "Entity id must be a string"
assert isinstance(id, str), "Entity id must be a string"
assert len(df.columns) == len(set(df.columns)), "Duplicate column names"
for c in df.columns:
if not is_string(c):
if not isinstance(c, str):
raise ValueError("All column names must be strings (Column {} "
"is not a string)".format(c))
if time_index is not None and time_index not in df.columns:
Expand Down
8 changes: 1 addition & 7 deletions featuretools/entityset/entityset.py
@@ -1,6 +1,5 @@
import copy
import logging
from builtins import object
from collections import defaultdict

import cloudpickle
Expand All @@ -12,7 +11,6 @@
from featuretools.entityset import deserialize, serialize
from featuretools.entityset.entity import Entity
from featuretools.entityset.relationship import Relationship, RelationshipPath
from featuretools.utils import is_string

pd.options.mode.chained_assignment = None # default='warn'
logger = logging.getLogger('featuretools.entityset')
Expand Down Expand Up @@ -213,10 +211,6 @@ def __repr__(self):
(r._child_entity_id, r._child_variable_id,
r._parent_entity_id, r._parent_variable_id)

# encode for python 2
if type(repr_out) != str:
repr_out = repr_out.encode("utf-8")

return repr_out

def add_relationships(self, relationships):
Expand Down Expand Up @@ -573,7 +567,7 @@ def normalize_entity(self, base_entity_id, new_entity_id, index,
if v == index:
raise ValueError("Not copying {} as both index and variable".format(v))
break
if is_string(make_time_index):
if isinstance(make_time_index, str):
if make_time_index not in base_entity.df.columns:
raise ValueError("'make_time_index' must be a variable in the base entity")
elif make_time_index not in additional_variables + copy_variables:
Expand Down
4 changes: 0 additions & 4 deletions featuretools/entityset/relationship.py
Expand Up @@ -39,10 +39,6 @@ def __repr__(self):
(self._child_entity_id, self._child_variable_id,
self._parent_entity_id, self._parent_variable_id)

# encode for python 2
if type(ret) != str:
ret = ret.encode("utf-8")

return ret

def __eq__(self, other):
Expand Down
20 changes: 3 additions & 17 deletions featuretools/entityset/serialize.py
@@ -1,23 +1,14 @@
import datetime
import errno
import json
import os
import tarfile
import tempfile

import boto3

from featuretools.utils.gen_utils import (
is_python_2,
use_s3fs_es,
use_smartopen_es
)
from featuretools.utils.gen_utils import use_s3fs_es, use_smartopen_es
from featuretools.utils.wrangle import _is_s3, _is_url

if is_python_2():
from backports import tempfile
else:
import tempfile

FORMATS = ['csv', 'pickle', 'parquet']
SCHEMA_VERSION = "1.0.0"

Expand Down Expand Up @@ -145,12 +136,7 @@ def write_data_description(entityset, path, profile_name=None, **kwargs):
raise ValueError("Writing to URLs is not supported")
else:
path = os.path.abspath(path)
try:
os.makedirs(os.path.join(path, 'data'))
except OSError as e:
if e.errno != errno.EEXIST:
raise

os.makedirs(os.path.join(path, 'data'), exist_ok=True)
dump_data_description(entityset, path, **kwargs)


Expand Down
6 changes: 1 addition & 5 deletions featuretools/entityset/timedelta.py
@@ -1,10 +1,6 @@
from __future__ import division

import pandas as pd
from dateutil.relativedelta import relativedelta

from featuretools.utils import is_string


class Timedelta(object):
"""Represents differences in time.
Expand Down Expand Up @@ -115,7 +111,7 @@ def get_unit_type(self):
return relativedelta(**readable_times)

def check_value(self, value, unit):
if is_string(value):
if isinstance(value, str):
from featuretools.utils.wrangle import _check_timedelta
td = _check_timedelta(value)
self.times = td.times
Expand Down
10 changes: 1 addition & 9 deletions featuretools/feature_base/feature_base.py
@@ -1,5 +1,3 @@
from builtins import zip

from featuretools import Relationship, Timedelta, primitives
from featuretools.entityset.relationship import RelationshipPath
from featuretools.primitives.base import (
Expand Down Expand Up @@ -171,13 +169,7 @@ def number_output_features(self):
return self.primitive.number_output_features

def __repr__(self):
ret = "<Feature: %s>" % (self.get_name())

# encode for python 2
if type(ret) != str:
ret = ret.encode("utf-8")

return ret
return "<Feature: %s>" % (self.get_name())

def hash(self):
return hash(self.get_name() + self.entity.id)
Expand Down
2 changes: 0 additions & 2 deletions featuretools/primitives/base/primitive_base.py
@@ -1,5 +1,3 @@
from __future__ import absolute_import

import os

import numpy as np
Expand Down
7 changes: 1 addition & 6 deletions featuretools/primitives/base/utils.py
@@ -1,9 +1,4 @@
try:
# python 3
from inspect import signature
except ImportError:
# python 2
from funcsigs import signature
from inspect import signature


def inspect_function_args(new_class, function, uses_calc_time):
Expand Down

0 comments on commit 18e929d

Please sign in to comment.