Skip to content

Commit

Permalink
Remove py27 and pre py35 support
Browse files Browse the repository at this point in the history
This patch, which when merged, will result in a charmhelpers 1.0.0
release, removes all py27 support code and pre py35 support.  This is
basically the removal of six and most hacks to support dual running on
py27.
  • Loading branch information
ajkavanagh committed Dec 10, 2021
1 parent b121bca commit 5bbe782
Show file tree
Hide file tree
Showing 80 changed files with 374 additions and 804 deletions.
4 changes: 0 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ jobs:
strategy:
matrix:
include:
- python-version: 2.7
env: pep8,py27
- python-version: 3.4
env: pep8,py34
- python-version: 3.5
env: pep8,py35
- python-version: 3.6
Expand Down
27 changes: 9 additions & 18 deletions HACKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,19 @@ such as making real, unmocked calls out to sudo foo, juju binaries, and perhaps
other things. This is not ideal for a number of reasons. One of those reasons
is that it pollutes the test runner (your) system.

The current recommendation for testing locally is to do so in a fresh Xenial
(16.04) lxc container. 16.04 is selected for consistency with what is available
in the Travis CI test gates. As of this writing, 18.04 is not available there.
The current recommendation for testing locally is to do so in a fresh bionic
(18.04) lxc container. This is because charmhelpers supports at least bionic
and later Ubuntu distros.

The fresh Xenial lxc system container will need to have the following packages
The fresh Bionic lxc system container will need to have the following packages
installed in order to satisfy test runner dependencies:

sudo apt install git bzr tox libapt-pkg-dev python-dev python3-dev build-essential juju -y
sudo apt install git bzr tox libapt-pkg-dev python3-dev build-essential juju -y

The tests can be executed as follows:

tox -e pep8
tox -e py3
tox -e py2

See also: .travis.yaml for what is happening in the test gate.

## Run testsuite (legacy Makefile method)

make test

Run `make` without arguments for more options.

## Test it in a charm

Expand Down Expand Up @@ -66,9 +57,9 @@ charm, get the path of the installed charmhelpers by running following command.*
Install html doc dependencies:

```bash
sudo apt-get install python-flake8 python-shelltoolbox python-tempita \
python-nose python-mock python-testtools python-jinja2 python-coverage \
python-git python-netifaces python-netaddr python-pip zip
sudo apt-get install python3-flake8 python3-shelltoolbox python3-tempita \
python3-nose python3-mock python3-testtools python3-jinja2 python3-coverage \
python3-git python3-netifaces python3-netaddr python3-pip zip
```

To build the html documentation:
Expand All @@ -82,7 +73,7 @@ To browse the html documentation locally:
```bash
make docs
cd docs/_build/html
python -m SimpleHTTPServer 8765
python3 -m SimpleHTTPServer 8765
# point web browser to http://localhost:8765
```

Expand Down
31 changes: 8 additions & 23 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PROJECT=charmhelpers
PYTHON := /usr/bin/env python
PYTHON := /usr/bin/env python3
SUITE=unstable
TESTS=tests/

Expand All @@ -21,63 +21,48 @@ deb: source

source: setup.py
scripts/update-revno
python setup.py sdist
python3 setup.py sdist

clean:
-python setup.py clean
-python3 setup.py clean
rm -rf build/ MANIFEST
find . -name '*.pyc' -delete
find . -name '__pycache__' -delete
rm -rf dist/*
rm -rf .venv
rm -rf .venv3
(which dh_clean && dh_clean) || true

userinstall:
scripts/update-revno
python setup.py install --user
python3 setup.py install --user


.venv:
dpkg-query -W -f='$${status}' gcc python-dev python-virtualenv 2>/dev/null | grep --invert-match "not-installed" || sudo apt-get install -y python-dev python-virtualenv
virtualenv .venv --system-site-packages
.venv/bin/pip install -U pip
.venv/bin/pip install -I -r test-requirements.txt
.venv/bin/pip install bzr

.venv3:
dpkg-query -W -f='$${status}' gcc python3-dev python-virtualenv python3-apt 2>/dev/null | grep --invert-match "not-installed" || sudo apt-get install -y python3-dev python-virtualenv python3-apt
virtualenv .venv3 --python=python3 --system-site-packages
.venv3/bin/pip install -U pip
.venv3/bin/pip install -I -r test-requirements.txt

# Note we don't even attempt to run tests if lint isn't passing.
test: lint test2 test3
test: lint test3
@echo OK

test2:
@echo Starting Py2 tests...
.venv/bin/nosetests -s --nologcapture tests/

test3:
@echo Starting Py3 tests...
.venv3/bin/nosetests -s --nologcapture tests/

ftest: lint
@echo Starting fast tests...
.venv/bin/nosetests --attr '!slow' --nologcapture tests/
.venv3/bin/nosetests --attr '!slow' --nologcapture tests/

lint: .venv .venv3
lint: .venv3
@echo Checking for Python syntax...
@.venv/bin/flake8 --ignore=E402,E501,W504 $(PROJECT) $(TESTS) tools/ \
&& echo Py2 OK
@.venv3/bin/flake8 --ignore=E402,E501,W504 $(PROJECT) $(TESTS) tools/ \
&& echo Py3 OK

docs:
- [ -z "`dpkg -l | grep python-sphinx`" ] && sudo apt-get install python-sphinx -y
- [ -z "`dpkg -l | grep python-pip`" ] && sudo apt-get install python-pip -y
- [ -z "`dpkg -l | grep python3-sphinx`" ] && sudo apt-get install python-sphinx -y
- [ -z "`dpkg -l | grep python3-pip`" ] && sudo apt-get install python-pip -y
- [ -z "`pip list | grep -i sphinx-pypi-upload`" ] && sudo pip install sphinx-pypi-upload
- [ -z "`pip list | grep -i sphinx_rtd_theme`" ] && sudo pip install sphinx_rtd_theme
cd docs && make html && cd -
Expand Down
14 changes: 1 addition & 13 deletions charmhelpers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,12 @@
import functools
import inspect
import subprocess
import sys

try:
import six # NOQA:F401
except ImportError:
if sys.version_info.major == 2:
subprocess.check_call(['apt-get', 'install', '-y', 'python-six'])
else:
subprocess.check_call(['apt-get', 'install', '-y', 'python3-six'])
import six # NOQA:F401

try:
import yaml # NOQA:F401
except ImportError:
if sys.version_info.major == 2:
subprocess.check_call(['apt-get', 'install', '-y', 'python-yaml'])
else:
subprocess.check_call(['apt-get', 'install', '-y', 'python3-yaml'])
subprocess.check_call(['apt-get', 'install', '-y', 'python3-yaml'])
import yaml # NOQA:F401


Expand Down
13 changes: 2 additions & 11 deletions charmhelpers/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
import argparse
import sys

import six
from six.moves import zip

import charmhelpers.core.unitdata


Expand Down Expand Up @@ -149,10 +146,7 @@ def wrapper(decorated):
def run(self):
"Run cli, processing arguments and executing subcommands."
arguments = self.argument_parser.parse_args()
if six.PY2:
argspec = inspect.getargspec(arguments.func)
else:
argspec = inspect.getfullargspec(arguments.func)
argspec = inspect.getfullargspec(arguments.func)
vargs = []
for arg in argspec.args:
vargs.append(getattr(arguments, arg))
Expand All @@ -177,10 +171,7 @@ def describe_arguments(func):
Analyze a function's signature and return a data structure suitable for
passing in as arguments to an argparse parser's add_argument() method."""

if six.PY2:
argspec = inspect.getargspec(func)
else:
argspec = inspect.getfullargspec(func)
argspec = inspect.getfullargspec(func)
# we should probably raise an exception somewhere if func includes **kwargs
if argspec.defaults:
positional_args = argspec.args[:-len(argspec.defaults)]
Expand Down
12 changes: 3 additions & 9 deletions charmhelpers/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,9 @@
:author: Stuart Bishop <[email protected]>
'''

import six

from charmhelpers.core import hookenv

from collections import OrderedDict
if six.PY3:
from collections import UserDict # pragma: nocover
else:
from UserDict import IterableUserDict as UserDict # pragma: nocover
from collections import OrderedDict, UserDict


class Relations(OrderedDict):
Expand Down Expand Up @@ -166,7 +160,7 @@ def __setitem__(self, key, value):
if self.unit != hookenv.local_unit():
raise TypeError('Attempting to set {} on remote unit {}'
''.format(key, self.unit))
if value is not None and not isinstance(value, six.string_types):
if value is not None and not isinstance(value, str):
# We don't do implicit casting. This would cause simple
# types like integers to be read back as strings in subsequent
# hooks, and mutable types would require a lot of wrapping
Expand All @@ -191,7 +185,7 @@ def data(self):
def __setitem__(self, key, value):
if not hookenv.is_leader():
raise TypeError('Not the leader. Cannot change leader settings.')
if value is not None and not isinstance(value, six.string_types):
if value is not None and not isinstance(value, str):
# We don't do implicit casting. This would cause simple
# types like integers to be read back as strings in subsequent
# hooks, and mutable types would require a lot of wrapping
Expand Down
9 changes: 3 additions & 6 deletions charmhelpers/contrib/charmhelpers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,9 @@
import yaml
import subprocess

import six
if six.PY3:
from urllib.request import urlopen
from urllib.error import (HTTPError, URLError)
else:
from urllib2 import (urlopen, HTTPError, URLError)
from urllib.request import urlopen
from urllib.error import (HTTPError, URLError)


"""Helper functions for writing Juju charms in Python."""

Expand Down
6 changes: 1 addition & 5 deletions charmhelpers/contrib/database/mysql.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import platform
import os
import glob
import six

# from string import upper

Expand Down Expand Up @@ -55,10 +54,7 @@
import MySQLdb
except ImportError:
apt_update(fatal=True)
if six.PY2:
apt_install(filter_installed_packages(['python-mysqldb']), fatal=True)
else:
apt_install(filter_installed_packages(['python3-mysqldb']), fatal=True)
apt_install(filter_installed_packages(['python3-mysqldb']), fatal=True)
import MySQLdb


Expand Down
15 changes: 6 additions & 9 deletions charmhelpers/contrib/hahelpers/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@

from socket import gethostname as get_unit_hostname

import six

from charmhelpers.core.hookenv import (
log,
relation_ids,
Expand Down Expand Up @@ -125,16 +123,16 @@ def is_crm_dc():
"""
cmd = ['crm', 'status']
try:
status = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
if not isinstance(status, six.text_type):
status = six.text_type(status, "utf-8")
status = subprocess.check_output(
cmd, stderr=subprocess.STDOUT).decode('utf-8')
except subprocess.CalledProcessError as ex:
raise CRMDCNotFound(str(ex))

current_dc = ''
for line in status.split('\n'):
if line.startswith('Current DC'):
# Current DC: juju-lytrusty-machine-2 (168108163) - partition with quorum
# Current DC: juju-lytrusty-machine-2 (168108163)
# - partition with quorum
current_dc = line.split(':')[1].split()[0]
if current_dc == get_unit_hostname():
return True
Expand All @@ -158,9 +156,8 @@ def is_crm_leader(resource, retry=False):
return is_crm_dc()
cmd = ['crm', 'resource', 'show', resource]
try:
status = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
if not isinstance(status, six.text_type):
status = six.text_type(status, "utf-8")
status = subprocess.check_output(
cmd, stderr=subprocess.STDOUT).decode('utf-8')
except subprocess.CalledProcessError:
status = None

Expand Down
5 changes: 1 addition & 4 deletions charmhelpers/contrib/hardening/apache/checks/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

import os
import re
import six
import subprocess


Expand Down Expand Up @@ -95,9 +94,7 @@ def __call__(self):
settings = utils.get_settings('apache')
ctxt = settings['hardening']

out = subprocess.check_output(['apache2', '-v'])
if six.PY3:
out = out.decode('utf-8')
out = subprocess.check_output(['apache2', '-v']).decode('utf-8')
ctxt['apache_version'] = re.search(r'.+version: Apache/(.+?)\s.+',
out).group(1)
ctxt['apache_icondir'] = '/usr/share/apache2/icons/'
Expand Down
8 changes: 2 additions & 6 deletions charmhelpers/contrib/hardening/audits/apache.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
import re
import subprocess

import six

from charmhelpers.core.hookenv import (
log,
INFO,
Expand All @@ -35,7 +33,7 @@ class DisabledModuleAudit(BaseAudit):
def __init__(self, modules):
if modules is None:
self.modules = []
elif isinstance(modules, six.string_types):
elif isinstance(modules, str):
self.modules = [modules]
else:
self.modules = modules
Expand Down Expand Up @@ -68,9 +66,7 @@ def ensure_compliance(self):
@staticmethod
def _get_loaded_modules():
"""Returns the modules which are enabled in Apache."""
output = subprocess.check_output(['apache2ctl', '-M'])
if six.PY3:
output = output.decode('utf-8')
output = subprocess.check_output(['apache2ctl', '-M']).decode('utf-8')
modules = []
for line in output.splitlines():
# Each line of the enabled module output looks like:
Expand Down
3 changes: 1 addition & 2 deletions charmhelpers/contrib/hardening/audits/apt.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
# limitations under the License.

from __future__ import absolute_import # required for external apt import
from six import string_types

from charmhelpers.fetch import (
apt_cache,
Expand Down Expand Up @@ -51,7 +50,7 @@ class RestrictedPackages(BaseAudit):

def __init__(self, pkgs, **kwargs):
super(RestrictedPackages, self).__init__(**kwargs)
if isinstance(pkgs, string_types) or not hasattr(pkgs, '__iter__'):
if isinstance(pkgs, str) or not hasattr(pkgs, '__iter__'):
self.pkgs = pkgs.split()
else:
self.pkgs = pkgs
Expand Down
3 changes: 1 addition & 2 deletions charmhelpers/contrib/hardening/audits/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
check_call,
)
from traceback import format_exc
from six import string_types
from stat import (
S_ISGID,
S_ISUID
Expand Down Expand Up @@ -63,7 +62,7 @@ def __init__(self, paths, always_comply=False, *args, **kwargs):
"""
super(BaseFileAudit, self).__init__(*args, **kwargs)
self.always_comply = always_comply
if isinstance(paths, string_types) or not hasattr(paths, '__iter__'):
if isinstance(paths, str) or not hasattr(paths, '__iter__'):
self.paths = [paths]
else:
self.paths = paths
Expand Down
Loading

0 comments on commit 5bbe782

Please sign in to comment.