Skip to content

Commit 9e7650c

Browse files
Deprecate python2.7 (remove python2.7 testing). (#430)
1 parent d1cc2a0 commit 9e7650c

25 files changed

Lines changed: 63 additions & 245 deletions

.gitlab-ci.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,6 @@ stages:
4848
- (Get-Content .\hca\default_config.json).replace('dss.data.humancellatlas.org',"dss.${DSS_TEST_STAGE}.data.humancellatlas.org")| Set-Content .\hca\default_config.json
4949
script:
5050
- make test-win
51-
test-2.7:
52-
extends: .linux-test-base
53-
variables:
54-
PYTHON_VERSION: "2.7"
5551

5652
test-3.5:
5753
extends: .linux-test-base

.travis.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ sudo: required
33
dist: xenial
44
cache: pip
55
python:
6-
- 2.7
76
- 3.5
87
- 3.6
98
- 3.7

README.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Data Coordination Platform (DCP) of the Human Cell Atlas (HCA).
66
Currently the `hca` package supports interaction with the `Upload Service <https://github.com/HumanCellAtlas/upload-service>`_ and `Data Storage Service (DSS) <https://github.com/HumanCellAtlas/data-store>`_ for services such as uploading, downloading,
77
and querying data.
88

9+
The HCA CLI is compatible with python versions 3.5+ (we are no longer compatible with python2.7, and our last compatible python2.7 version was `hca==6.4.0`).
10+
911
Installation
1012
------------
1113
:code:`pip install hca`.

hca/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from __future__ import absolute_import, division, print_function, unicode_literals
2-
31
from .config import HCAConfig, get_config, logger
42
from . import dss, upload, query
53

hca/cli.py

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
For general help, run ``{prog} help``.
66
For help with individual commands, run ``{prog} <command> --help``.
77
"""
8-
from __future__ import absolute_import, division, print_function, unicode_literals
9-
108
import os
119
import sys
1210
import argparse
@@ -18,19 +16,13 @@
1816
import argcomplete
1917
from io import open
2018
from botocore.exceptions import NoRegionError
21-
22-
try:
23-
import xmlrpclib
24-
except ImportError:
25-
import xmlrpc.client as xmlrpclib
19+
import xmlrpc.client as xmlrpclib
2620

2721
from .version import __version__
2822
from .dss import cli as dss_cli
2923
from .upload import cli as upload_cli
3024
from .query import cli as query_cli
31-
from .util.compat import USING_PYTHON2
32-
from . import clear_hca_cache
33-
from . import logger, get_config
25+
from . import logger, get_config, clear_hca_cache
3426

3527

3628
class HCAArgumentParser(argparse.ArgumentParser):
@@ -47,8 +39,7 @@ def add_parser_func(self, func, **kwargs):
4739
subparser.set_defaults(**get_config().get(command, {}))
4840
if subparser.description is None:
4941
subparser.description = kwargs.get("help", func.__doc__)
50-
if sys.version_info < (2, 7, 9): # See https://bugs.python.org/issue9351
51-
self._defaults.pop("entry_point", None)
42+
self._defaults.pop("entry_point", None)
5243
return subparser
5344

5445
def print_help(self, file=None):
@@ -161,7 +152,6 @@ def main(args=None):
161152
raise result
162153
elif result is not None:
163154
if isinstance(result, bytes):
164-
out_stream = sys.stdout if USING_PYTHON2 else sys.stdout.buffer
165-
out_stream.write(result)
155+
sys.stdout.buffer.write(result)
166156
elif not isinstance(result, upload_cli.UploadCLICommand):
167157
print(json.dumps(result, indent=2, default=lambda x: str(x)))

hca/dss/__init__.py

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,10 @@
22
Data Storage System
33
*******************
44
"""
5-
6-
from __future__ import absolute_import, division, print_function, unicode_literals
7-
85
import errno
96
import functools
107
import json
11-
import threading
12-
from collections import defaultdict, namedtuple, OrderedDict
8+
from collections import defaultdict, namedtuple
139
import csv
1410
import concurrent.futures
1511
from datetime import datetime
@@ -27,8 +23,7 @@
2723
from requests.exceptions import ChunkedEncodingError, ConnectionError, ReadTimeout
2824

2925
from hca.dss.util import iter_paths, object_name_builder, hardlink
30-
from hca.util import USING_PYTHON2
31-
from hca.util.compat import glob_escape
26+
from glob import escape as glob_escape
3227
from ..util import SwaggerClient, DEFAULT_THREAD_COUNT
3328
from ..util.exceptions import SwaggerAPIException
3429
from .. import logger
@@ -400,7 +395,7 @@ def download_collection(self, uuid, replica, version=None, download_dir=''):
400395
'file_uuid',
401396
'file_version',
402397
'file_size'),
403-
delimiter=str('\t'), # cast for py2.7 compat
398+
delimiter='\t',
404399
quoting=csv.QUOTE_NONE)
405400
tsv.writeheader()
406401
tsv.writerows(collection)
@@ -472,7 +467,6 @@ class DownloadContext(object):
472467
# This variable is the configuration for download_manifest_v2. It specifies the length of the names of nested
473468
# directories for downloaded files.
474469
DIRECTORY_NAME_LENGTHS = [2, 4]
475-
MANIFEST_DELIMITER = b'\t' if USING_PYTHON2 else '\t'
476470

477471
def __init__(self, download_dir, dss_client, replica, num_retries, min_delay_seconds):
478472
self.runner = TaskRunner()
@@ -535,7 +529,7 @@ def _download_bundle_manifest(self, manifest_bytes, bundle_dir, dss_file):
535529

536530
def _get_full_bundle_manifest(self, bundle_uuid, version):
537531
"""
538-
Takes care of paging through the bundle and checks for name collisions
532+
Takes care of paging through the bundle and checks for name collisions.
539533
"""
540534
pages = self.dss_client.get_bundle.paginate(uuid=bundle_uuid,
541535
version=version if version else None,
@@ -734,8 +728,7 @@ def _download_manifest_tasks(self, no_metadata, no_data):
734728
with open(self.manifest) as f:
735729
bundles = defaultdict(set)
736730
# unicode_literals is on so all strings are unicode. CSV wants a str so we need to jump through a hoop.
737-
delimiter = self.MANIFEST_DELIMITER
738-
reader = csv.DictReader(f, delimiter=delimiter, quoting=csv.QUOTE_NONE)
731+
reader = csv.DictReader(f, delimiter='\t', quoting=csv.QUOTE_NONE)
739732
for row in reader:
740733
bundles[(row['bundle_uuid'], row['bundle_version'])].add(row['file_name'])
741734
for (bundle_uuid, bundle_version), data_files in bundles.items():
@@ -761,8 +754,7 @@ def _write_output_manifest(self):
761754
if 'file_path' not in fieldnames:
762755
fieldnames.append('file_path')
763756
with atomic_write(output, overwrite=True) as f:
764-
delimiter = b'\t' if USING_PYTHON2 else '\t'
765-
writer = csv.DictWriter(f, fieldnames, delimiter=delimiter, quoting=csv.QUOTE_NONE)
757+
writer = csv.DictWriter(f, fieldnames, delimiter='\t', quoting=csv.QUOTE_NONE)
766758
writer.writeheader()
767759
for row in source_manifest:
768760
row['file_path'] = self._file_path(row['file_sha256'], self.download_dir)
@@ -775,6 +767,5 @@ def _write_output_manifest(self):
775767
def _parse_manifest(cls, manifest):
776768
with open(manifest) as f:
777769
# unicode_literals is on so all strings are unicode. CSV wants a str so we need to jump through a hoop.
778-
delimiter = cls.MANIFEST_DELIMITER
779-
reader = csv.DictReader(f, delimiter=delimiter, quoting=csv.QUOTE_NONE)
770+
reader = csv.DictReader(f, delimiter='\t', quoting=csv.QUOTE_NONE)
780771
return reader.fieldnames, list(reader)

hca/dss/cli.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
from __future__ import absolute_import, division, print_function, unicode_literals
2-
3-
import sys
4-
51
from . import DSSClient
62

73
def add_commands(subparsers, help_menu=False):
@@ -10,8 +6,7 @@ def add_commands(subparsers, help_menu=False):
106
def help(args):
117
dss_parser.print_help()
128

13-
if sys.version_info >= (2, 7, 9): # See https://bugs.python.org/issue9351
14-
dss_parser.set_defaults(entry_point=help)
9+
dss_parser.set_defaults(entry_point=help)
1510
dss_subparsers = dss_parser.add_subparsers()
1611
dss_cli_client = DSSClient()
1712
dss_cli_client.build_argparse_subparsers(dss_subparsers, help_menu=help_menu)

hca/dss/infra.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
#!/usr/bin/env python
22
# coding: utf-8
3-
4-
from __future__ import absolute_import, division, print_function, unicode_literals
5-
63
import logging
74

85

hca/dss/util/__init__.py

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
import errno
21
import os
3-
4-
import platform
5-
import sys
6-
2+
from builtins import FileExistsError
73
from ...util.compat import scandir
84

95

@@ -44,26 +40,14 @@ def hardlink(source, link_name):
4440
The code for Windows support is adapted from:
4541
https://github.com/sunshowers/ntfs/blob/master/ntfsutils/hardlink.py
4642
"""
47-
if sys.version_info < (3,) and platform.system() == 'Windows': # pragma: no cover
48-
import ctypes
49-
create_hard_link = ctypes.windll.kernel32.CreateHardLinkW
50-
create_hard_link.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_void_p]
51-
create_hard_link.restype = ctypes.wintypes.BOOL
52-
res = create_hard_link(link_name, source, None)
53-
if res == 0:
54-
raise ctypes.WinError()
55-
else:
56-
try:
57-
os.link(source, link_name)
58-
except OSError as e:
59-
if e.errno != errno.EEXIST:
60-
raise
61-
else:
62-
# It's possible that the user created a different file with the same name as the
63-
# one we're trying to download. Thus we need to check the if the inode is different
64-
# and raise an error in this case.
65-
source_stat = os.stat(source)
66-
dest_stat = os.stat(link_name)
67-
# Check device first because different drives can have the same inode number
68-
if source_stat.st_dev != dest_stat.st_dev or source_stat.st_ino != dest_stat.st_ino:
69-
raise
43+
try:
44+
os.link(source, link_name)
45+
except FileExistsError:
46+
# It's possible that the user created a different file with the same name as the
47+
# one we're trying to download. Thus we need to check the if the inode is different
48+
# and raise an error in this case.
49+
source_stat = os.stat(source)
50+
dest_stat = os.stat(link_name)
51+
# Check device first because different drives can have the same inode number
52+
if source_stat.st_dev != dest_stat.st_dev or source_stat.st_ino != dest_stat.st_ino:
53+
raise

hca/query/__init__.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
DCP Query Service
33
*****************
44
"""
5-
6-
from __future__ import absolute_import, division, print_function, unicode_literals
7-
85
from ..util import SwaggerClient
96

107

0 commit comments

Comments
 (0)