# HG changeset patch # User Denis Laxalde # Date 1554479899 -7200 # Node ID 26744ad37953c094524914a97a055f214a160ce0 # Parent 6b3523f81f424b839811e650ce275610c0467329 Drop python2 support This mostly consists in removing the dependency on "six" and updating the code to use only Python3 idioms. Notice that we previously used TemporaryDirectory from cubicweb.devtools.testlib for compatibility with Python2. We now directly import it from tempfile. diff -r 6b3523f81f42 -r 26744ad37953 cubicweb.spec --- a/cubicweb.spec Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb.spec Fri Apr 05 17:58:19 2019 +0200 @@ -21,7 +21,6 @@ BuildArch: noarch Requires: %{python} -Requires: %{python}-six >= 1.4.0 Requires: %{python}-logilab-common >= 1.4.0 Requires: %{python}-logilab-mtconverter >= 0.8.0 Requires: %{python}-rql >= 0.34.0 @@ -29,7 +28,6 @@ Requires: %{python}-logilab-database >= 1.15.0 Requires: %{python}-passlib Requires: %{python}-lxml -Requires: %{python}-unittest2 >= 0.7.0 Requires: %{python}-markdown Requires: pytz # the schema view uses `dot'; at least on el5, png output requires graphviz-gd diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/__init__.py --- a/cubicweb/__init__.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/__init__.py Fri Apr 05 17:58:19 2019 +0200 @@ -27,8 +27,6 @@ import warnings import zlib -from six import PY2, binary_type, text_type - from logilab.common.logging_ext import set_log_methods from yams.constraints import BASE_CONVERTERS, BASE_CHECKERS from yams.schema import role_name as rname @@ -40,11 +38,7 @@ from yams import ValidationError from cubicweb._exceptions import * # noqa -if PY2: - # http://bugs.python.org/issue10211 - from StringIO import StringIO as BytesIO -else: - from io import BytesIO +from io import BytesIO # ignore the pygments UserWarnings warnings.filterwarnings('ignore', category=UserWarning, @@ -63,12 +57,12 @@ # '_' is available to mark internationalized string but should not be used to # do the actual translation -_ = text_type +_ = str class Binary(BytesIO): """class to hold binary data. Use BytesIO to prevent use of unicode data""" - _allowed_types = (binary_type, bytearray, buffer if PY2 else memoryview) # noqa: F405 + _allowed_types = (bytes, bytearray, memoryview) def __init__(self, buf=b''): assert isinstance(buf, self._allowed_types), \ @@ -144,7 +138,7 @@ def check_password(eschema, value): - return isinstance(value, (binary_type, Binary)) + return isinstance(value, (bytes, Binary)) BASE_CHECKERS['Password'] = check_password @@ -153,7 +147,7 @@ def str_or_binary(value): if isinstance(value, Binary): return value - return binary_type(value) + return bytes(value) BASE_CONVERTERS['Password'] = str_or_binary diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/__pkginfo__.py --- a/cubicweb/__pkginfo__.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/__pkginfo__.py Fri Apr 05 17:58:19 2019 +0200 @@ -34,7 +34,7 @@ classifiers = [ 'Environment :: Web Environment', 'Framework :: CubicWeb', - 'Programming Language :: Python', + 'Programming Language :: Python :: 3', 'Programming Language :: JavaScript', ] diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/_exceptions.py --- a/cubicweb/_exceptions.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/_exceptions.py Fri Apr 05 17:58:19 2019 +0200 @@ -21,8 +21,6 @@ from warnings import warn -from six import PY2, text_type - from logilab.common.decorators import cachedproperty from yams import ValidationError @@ -32,21 +30,15 @@ class CubicWebException(Exception): """base class for cubicweb server exception""" msg = "" - def __unicode__(self): + + def __str__(self): if self.msg: if self.args: return self.msg % tuple(self.args) else: return self.msg else: - return u' '.join(text_type(arg) for arg in self.args) - - def __str__(self): - res = self.__unicode__() - if PY2: - res = res.encode('utf-8') - return res - + return u' '.join(str(arg) for arg in self.args) class ConfigurationError(CubicWebException): """a misconfiguration error""" @@ -98,7 +90,7 @@ def rtypes(self): if 'rtypes' in self.kwargs: return self.kwargs['rtypes'] - cstrname = text_type(self.kwargs['cstrname']) + cstrname = str(self.kwargs['cstrname']) cstr = self.session.find('CWUniqueTogetherConstraint', name=cstrname).one() return sorted(rtype.name for rtype in cstr.relations) @@ -119,7 +111,7 @@ msg1 = u'You are not allowed to perform %s operation on %s' var = None - def __unicode__(self): + def __str__(self): try: if self.args and len(self.args) == 2: return self.msg1 % self.args @@ -127,7 +119,7 @@ return u' '.join(self.args) return self.msg except Exception as ex: - return text_type(ex) + return str(ex) class Forbidden(SecurityError): """raised when a user tries to perform a forbidden action diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/_gcdebug.py --- a/cubicweb/_gcdebug.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/_gcdebug.py Fri Apr 05 17:58:19 2019 +0200 @@ -15,12 +15,8 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -from __future__ import print_function - import gc, types, weakref -from six import PY2 - from cubicweb.schema import CubicWebRelationSchema, CubicWebEntitySchema try: from cubicweb.web.request import _NeedAuthAccessMock @@ -37,9 +33,6 @@ types.ModuleType, types.FunctionType, types.MethodType, types.MemberDescriptorType, types.GetSetDescriptorType, ) -if PY2: - # weakref.WeakKeyDictionary fails isinstance check on Python 3.5. - IGNORE_CLASSES += (weakref.WeakKeyDictionary, ) if _NeedAuthAccessMock is not None: IGNORE_CLASSES = IGNORE_CLASSES + (_NeedAuthAccessMock,) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/crypto.py --- a/cubicweb/crypto.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/crypto.py Fri Apr 05 17:58:19 2019 +0200 @@ -19,8 +19,7 @@ from base64 import b64encode, b64decode - -from six.moves import cPickle as pickle +import pickle from Crypto.Cipher import Blowfish @@ -38,7 +37,7 @@ string = pickle.dumps(data) string = string + '*' * (8 - len(string) % 8) string = b64encode(_cypherer(seed).encrypt(string)) - return unicode(string) + return str(string) def decrypt(string, seed): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/cwconfig.py --- a/cubicweb/cwconfig.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/cwconfig.py Fri Apr 05 17:58:19 2019 +0200 @@ -166,8 +166,6 @@ Directory where pid files will be written """ -from __future__ import print_function - import importlib import logging import logging.config @@ -182,8 +180,6 @@ from threading import Lock from warnings import filterwarnings -from six import text_type - from logilab.common.decorators import cached from logilab.common.logging_ext import set_log_methods, init_log from logilab.common.configuration import (Configuration, Method, @@ -641,7 +637,7 @@ self.adjust_sys_path() self.load_defaults() # will be properly initialized later by _gettext_init - self.translations = {'en': (text_type, lambda ctx, msgid: text_type(msgid) )} + self.translations = {'en': (str, lambda ctx, msgid: str(msgid) )} self._site_loaded = set() # don't register ReStructured Text directives by simple import, avoid pb # with eg sphinx. @@ -990,7 +986,7 @@ # set to true while creating an instance self.creating = creating super(CubicWebConfiguration, self).__init__(debugmode) - fake_gettext = (text_type, lambda ctx, msgid: text_type(msgid)) + fake_gettext = (str, lambda ctx, msgid: str(msgid)) for lang in self.available_languages(): self.translations[lang] = fake_gettext self._cubes = None diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/cwctl.py --- a/cubicweb/cwctl.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/cwctl.py Fri Apr 05 17:58:19 2019 +0200 @@ -18,8 +18,6 @@ """the cubicweb-ctl tool, based on logilab.common.clcommands to provide a pluggable commands system. """ -from __future__ import print_function - # *ctl module should limit the number of import to be imported as quickly as # possible (for cubicweb-ctl reactivity, necessary for instance for usable bash # completion). So import locally in command helpers. diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/cwgettext.py --- a/cubicweb/cwgettext.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/cwgettext.py Fri Apr 05 17:58:19 2019 +0200 @@ -18,8 +18,6 @@ import gettext -from six import PY3 - class cwGNUTranslations(gettext.GNUTranslations): # The encoding of a msgctxt and a msgid in a .mo file is @@ -85,8 +83,7 @@ else: return msgid2 - if PY3: - ugettext = gettext.GNUTranslations.gettext + ugettext = gettext.GNUTranslations.gettext def upgettext(self, context, message): ctxt_message_id = self.CONTEXT_ENCODING % (context, message) @@ -97,7 +94,7 @@ return self.ugettext(message) if self._fallback: return self._fallback.upgettext(context, message) - return unicode(message) + return str(message) return tmsg def unpgettext(self, context, msgid1, msgid2, n): @@ -108,9 +105,9 @@ if self._fallback: return self._fallback.unpgettext(context, msgid1, msgid2, n) if n == 1: - tmsg = unicode(msgid1) + tmsg = str(msgid1) else: - tmsg = unicode(msgid2) + tmsg = str(msgid2) return tmsg diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/cwvreg.py --- a/cubicweb/cwvreg.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/cwvreg.py Fri Apr 05 17:58:19 2019 +0200 @@ -24,8 +24,6 @@ from datetime import datetime, date, time, timedelta from functools import reduce -from six import text_type, binary_type - from logilab.common.decorators import cached, clear_cache from logilab.common.deprecation import class_deprecated from logilab.common.modutils import clean_sys_modules @@ -218,9 +216,9 @@ """ obj = self.select(oid, req, rset=rset, **kwargs) res = obj.render(**kwargs) - if isinstance(res, text_type): + if isinstance(res, str): return res.encode(req.encoding) - assert isinstance(res, binary_type) + assert isinstance(res, bytes) return res def possible_views(self, req, rset=None, **kwargs): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/dataimport/csv.py --- a/cubicweb/dataimport/csv.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/dataimport/csv.py Fri Apr 05 17:58:19 2019 +0200 @@ -16,18 +16,14 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """Functions to help importing CSV data""" -from __future__ import absolute_import, print_function - import codecs import csv as csvmod -from six import PY2, PY3, string_types - from logilab.common import shellutils def count_lines(stream_or_filename): - if isinstance(stream_or_filename, string_types): + if isinstance(stream_or_filename, str): f = open(stream_or_filename) else: f = stream_or_filename @@ -42,7 +38,7 @@ def ucsvreader_pb(stream_or_path, encoding='utf-8', delimiter=',', quotechar='"', skipfirst=False, withpb=True, skip_empty=True): """same as :func:`ucsvreader` but a progress bar is displayed as we iter on rows""" - if isinstance(stream_or_path, string_types): + if isinstance(stream_or_path, str): stream = open(stream_or_path, 'rb') else: stream = stream_or_path @@ -68,19 +64,14 @@ separators) will be skipped. This is useful for Excel exports which may be full of such lines. """ - if PY3: - stream = codecs.getreader(encoding)(stream) + stream = codecs.getreader(encoding)(stream) it = iter(csvmod.reader(stream, delimiter=delimiter, quotechar=quotechar)) if not ignore_errors: if skipfirst: next(it) for row in it: - if PY2: - decoded = [item.decode(encoding) for item in row] - else: - decoded = row - if not skip_empty or any(decoded): - yield decoded + if not skip_empty or any(row): + yield row else: if skipfirst: try: @@ -97,9 +88,5 @@ # Error in CSV, ignore line and continue except csvmod.Error: continue - if PY2: - decoded = [item.decode(encoding) for item in row] - else: - decoded = row - if not skip_empty or any(decoded): - yield decoded + if not skip_empty or any(row): + yield row diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/dataimport/massive_store.py --- a/cubicweb/dataimport/massive_store.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/dataimport/massive_store.py Fri Apr 05 17:58:19 2019 +0200 @@ -22,9 +22,6 @@ import logging from uuid import uuid4 -from six import text_type -from six.moves import range - from cubicweb.dataimport import stores, pgstore from cubicweb.server.schema2sql import eschema_sql_def @@ -70,7 +67,7 @@ """ super(MassiveObjectStore, self).__init__(cnx) - self.uuid = text_type(uuid4()).replace('-', '') + self.uuid = str(uuid4()).replace('-', '') self.slave_mode = slave_mode if metagen is None: metagen = stores.MetadataGenerator(cnx) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/dataimport/pgstore.py --- a/cubicweb/dataimport/pgstore.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/dataimport/pgstore.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,17 +17,13 @@ # with CubicWeb. If not, see . """Postgres specific store""" -from __future__ import print_function - import warnings import os.path as osp from io import StringIO from time import asctime from datetime import date, datetime, time from collections import defaultdict - -from six import string_types, integer_types, text_type, add_metaclass -from six.moves import cPickle as pickle, range +import pickle from cubicweb.utils import make_uid from cubicweb.server.sqlutils import SQL_PREFIX @@ -108,7 +104,7 @@ def _copyfrom_buffer_convert_number(value, **opts): '''Convert a number into its string representation''' - return text_type(value) + return str(value) def _copyfrom_buffer_convert_string(value, **opts): '''Convert string value. @@ -140,8 +136,8 @@ # (types, converter) list. _COPYFROM_BUFFER_CONVERTERS = [ (type(None), _copyfrom_buffer_convert_None), - (integer_types + (float,), _copyfrom_buffer_convert_number), - (string_types, _copyfrom_buffer_convert_string), + ((int, float), _copyfrom_buffer_convert_number), + (str, _copyfrom_buffer_convert_string), (datetime, _copyfrom_buffer_convert_datetime), (date, _copyfrom_buffer_convert_date), (time, _copyfrom_buffer_convert_time), @@ -185,7 +181,7 @@ for types, converter in _COPYFROM_BUFFER_CONVERTERS: if isinstance(value, types): value = converter(value, **convert_opts) - assert isinstance(value, text_type) + assert isinstance(value, str) break else: raise ValueError("Unsupported value type %s" % type(value)) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/dataimport/stores.py --- a/cubicweb/dataimport/stores.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/dataimport/stores.py Fri Apr 05 17:58:19 2019 +0200 @@ -62,8 +62,6 @@ from copy import copy from itertools import count -from six import add_metaclass - import pytz from logilab.common.decorators import cached @@ -362,8 +360,7 @@ return self._mdgen.source -@add_metaclass(class_deprecated) -class MetaGenerator(object): +class MetaGenerator(object, metaclass=class_deprecated): """Class responsible for generating standard metadata for imported entities. You may want to derive it to add application specific's metadata. diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/dataimport/test/test_pgstore.py --- a/cubicweb/dataimport/test/test_pgstore.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/dataimport/test/test_pgstore.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,16 +20,11 @@ import datetime as DT -from six import PY3 from logilab.common.testlib import TestCase, unittest_main from cubicweb.dataimport import pgstore -if PY3: - long = int - - class CreateCopyFromBufferTC(TestCase): # test converters @@ -41,7 +36,7 @@ def test_convert_number(self): cnvt = pgstore._copyfrom_buffer_convert_number self.assertEqual(u'42', cnvt(42)) - self.assertEqual(u'42', cnvt(long(42))) + self.assertEqual(u'42', cnvt(int(42))) self.assertEqual(u'42.42', cnvt(42.42)) def test_convert_string(self): @@ -68,9 +63,9 @@ # test buffer def test_create_copyfrom_buffer_tuple(self): - data = ((42, long(42), 42.42, u'éléphant', DT.date(666, 1, 13), DT.time(6, 6, 6), + data = ((42, int(42), 42.42, u'éléphant', DT.date(666, 1, 13), DT.time(6, 6, 6), DT.datetime(666, 6, 13, 6, 6, 6)), - (6, long(6), 6.6, u'babar', DT.date(2014, 1, 14), DT.time(4, 2, 1), + (6, int(6), 6.6, u'babar', DT.date(2014, 1, 14), DT.time(4, 2, 1), DT.datetime(2014, 1, 1, 0, 0, 0))) results = pgstore._create_copyfrom_buffer(data) # all columns diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/__init__.py --- a/cubicweb/devtools/__init__.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/__init__.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,8 +17,6 @@ # with CubicWeb. If not, see . """Test tools for cubicweb""" -from __future__ import print_function - import os import sys import errno @@ -31,10 +29,9 @@ from hashlib import sha1 # pylint: disable=E0611 from os.path import abspath, join, exists, split, isdir, dirname from functools import partial +import pickle import filelock -from six import text_type -from six.moves import cPickle as pickle from logilab.common.decorators import cached, clear_cache @@ -93,7 +90,7 @@ DEFAULT_PSQL_SOURCES = DEFAULT_SOURCES.copy() DEFAULT_PSQL_SOURCES['system'] = DEFAULT_SOURCES['system'].copy() DEFAULT_PSQL_SOURCES['system']['db-driver'] = 'postgres' -DEFAULT_PSQL_SOURCES['system']['db-user'] = text_type(getpass.getuser()) +DEFAULT_PSQL_SOURCES['system']['db-user'] = getpass.getuser() DEFAULT_PSQL_SOURCES['system']['db-password'] = None # insert a dumb value as db-host to avoid unexpected connection to local server DEFAULT_PSQL_SOURCES['system']['db-host'] = 'REPLACEME' @@ -395,7 +392,7 @@ from cubicweb.repoapi import connect repo = self.get_repo() sources = self.config.read_sources_file() - login = text_type(sources['admin']['login']) + login = sources['admin']['login'] password = sources['admin']['password'] or 'xxx' cnx = connect(repo, login, password=password) return cnx diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/devctl.py --- a/cubicweb/devtools/devctl.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/devctl.py Fri Apr 05 17:58:19 2019 +0200 @@ -18,8 +18,6 @@ """additional cubicweb-ctl commands and command handlers for cubicweb and cubicweb's cubes development """ -from __future__ import print_function - # *ctl module should limit the number of import to be imported as quickly as # possible (for cubicweb-ctl reactivity, necessary for instance for usable bash # completion). So import locally in command helpers. @@ -33,8 +31,6 @@ from pytz import UTC -from six.moves import input - from logilab.common import STD_BLACKLIST from logilab.common.modutils import clean_sys_modules from logilab.common.fileutils import ensure_fs_mode @@ -717,7 +713,6 @@ longdesc = input( 'Enter a long description (leave empty to reuse the short one): ') dependencies = { - 'six': '>= 1.4.0', 'cubicweb': '>= %s' % cubicwebversion, } if verbose: diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/fake.py --- a/cubicweb/devtools/fake.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/fake.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ from contextlib import contextmanager -from six import string_types - from logilab.database import get_db_helper from cubicweb.req import RequestSessionBase @@ -98,7 +96,7 @@ def set_request_header(self, header, value, raw=False): """set an incoming HTTP header (for test purpose only)""" - if isinstance(value, string_types): + if isinstance(value, str): value = [value] if raw: # adding encoded header is important, else page content diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/fill.py --- a/cubicweb/devtools/fill.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/fill.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,9 +17,6 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """This modules defines func / methods for creating test repositories""" -from __future__ import print_function - - import logging from random import randint, choice @@ -28,9 +25,6 @@ from decimal import Decimal import inspect -from six import text_type, add_metaclass -from six.moves import range - from logilab.common import attrdict from logilab.mtconverter import xml_escape from yams.constraints import (SizeConstraint, StaticVocabularyConstraint, @@ -234,7 +228,7 @@ """ for cst in self.eschema.rdef(attrname).constraints: if isinstance(cst, StaticVocabularyConstraint): - return text_type(choice(cst.vocabulary())) + return choice(cst.vocabulary()) return None # XXX nothing to do here @@ -270,8 +264,7 @@ return type.__new__(mcs, name, bases, classdict) -@add_metaclass(autoextend) -class ValueGenerator(_ValueGenerator): +class ValueGenerator(_ValueGenerator, metaclass=autoextend): pass @@ -359,7 +352,7 @@ fmt = vreg.property_value('ui.float-format') value = fmt % value else: - value = text_type(value) + value = value return entity diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/httptest.py --- a/cubicweb/devtools/httptest.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/httptest.py Fri Apr 05 17:58:19 2019 +0200 @@ -18,15 +18,12 @@ """this module contains base classes and utilities for integration with running http server """ -from __future__ import print_function +import http.client import random import threading import socket - -from six.moves import range, http_client -from six.moves.urllib.parse import urlparse - +from urllib.parse import urlparse from cubicweb.devtools.testlib import CubicWebTC @@ -83,7 +80,7 @@ passwd = user response = self.web_get("login?__login=%s&__password=%s" % (user, passwd)) - assert response.status == http_client.SEE_OTHER, response.status + assert response.status == http.client.SEE_OTHER, response.status self._ident_cookie = response.getheader('Set-Cookie') assert self._ident_cookie return True @@ -95,7 +92,7 @@ self._ident_cookie = None def web_request(self, path='', method='GET', body=None, headers=None): - """Return an http_client.HTTPResponse object for the specified path + """Return an http.client.HTTPResponse object for the specified path Use available credential if available. """ @@ -131,7 +128,7 @@ def start_server(self): from cubicweb.wsgi.handler import CubicWebWSGIApplication from wsgiref import simple_server - from six.moves import queue + import queue config = self.config port = config['port'] or 8080 @@ -164,7 +161,7 @@ self.fail(start_flag.get()) parseurl = urlparse(self.config['base-url']) assert parseurl.port == self.config['port'], (self.config['base-url'], self.config['port']) - self._web_test_cnx = http_client.HTTPConnection(parseurl.hostname, + self._web_test_cnx = http.client.HTTPConnection(parseurl.hostname, parseurl.port) self._ident_cookie = None diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/instrument.py --- a/cubicweb/devtools/instrument.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/instrument.py Fri Apr 05 17:58:19 2019 +0200 @@ -14,8 +14,6 @@ # You should have received a copy of the GNU Lesser General Public License along # with this program. If not, see . """Instrumentation utilities""" -from __future__ import print_function - import os try: diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/qunit.py --- a/cubicweb/devtools/qunit.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/qunit.py Fri Apr 05 17:58:19 2019 +0200 @@ -15,16 +15,13 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -from __future__ import absolute_import, print_function - import os, os.path as osp import errno import shutil -from tempfile import mkdtemp +from queue import Queue, Empty +from tempfile import mkdtemp, TemporaryDirectory from subprocess import Popen, PIPE, STDOUT -from six.moves.queue import Queue, Empty - # imported by default to simplify further import statements from logilab.common.testlib import Tags import webtest.http @@ -34,7 +31,6 @@ from cubicweb.web.controller import Controller from cubicweb.web.views.staticcontrollers import StaticFileController, STATIC_CONTROLLERS from cubicweb.devtools import webtest as cwwebtest -from cubicweb.devtools.testlib import TemporaryDirectory class FirefoxHelper(object): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/repotest.py --- a/cubicweb/devtools/repotest.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/repotest.py Fri Apr 05 17:58:19 2019 +0200 @@ -19,8 +19,6 @@ This module contains functions to initialize a new repository. """ -from __future__ import print_function - from contextlib import contextmanager from pprint import pprint diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/stresstester.py --- a/cubicweb/devtools/stresstester.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/stresstester.py Fri Apr 05 17:58:19 2019 +0200 @@ -41,8 +41,6 @@ Copyright (c) 2003-2011 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2. http://www.logilab.fr/ -- mailto:contact@logilab.fr """ -from __future__ import print_function - import os import sys import threading diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/test/unittest_dbfill.py --- a/cubicweb/devtools/test/unittest_dbfill.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/test/unittest_dbfill.py Fri Apr 05 17:58:19 2019 +0200 @@ -23,8 +23,6 @@ import datetime import io -from six.moves import range - from logilab.common.testlib import TestCase, unittest_main from cubicweb.devtools.fill import ValueGenerator, make_tel diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/test/unittest_devctl.py --- a/cubicweb/devtools/test/unittest_devctl.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/test/unittest_devctl.py Fri Apr 05 17:58:19 2019 +0200 @@ -21,10 +21,9 @@ import os.path as osp import sys from subprocess import Popen, PIPE, STDOUT +from tempfile import TemporaryDirectory from unittest import TestCase -from cubicweb.devtools.testlib import TemporaryDirectory - def newcube(directory, name): cmd = ['cubicweb-ctl', 'newcube', '--directory', directory, name] diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/test/unittest_httptest.py --- a/cubicweb/devtools/test/unittest_httptest.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/test/unittest_httptest.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,7 +17,7 @@ # with CubicWeb. If not, see . """unittest for cubicweb.devtools.httptest module""" -from six.moves import http_client +import http.client from logilab.common.testlib import Tags from cubicweb.devtools.httptest import CubicWebServerTC @@ -28,12 +28,12 @@ def test_response(self): try: response = self.web_get() - except http_client.NotConnected as ex: + except http.client.NotConnected as ex: self.fail("Can't connection to test server: %s" % ex) def test_response_anon(self): response = self.web_get() - self.assertEqual(response.status, http_client.OK) + self.assertEqual(response.status, http.client.OK) def test_base_url(self): if self.config['base-url'] not in self.web_get().read().decode('ascii'): @@ -47,20 +47,20 @@ def test_response_denied(self): response = self.web_get() - self.assertEqual(response.status, http_client.FORBIDDEN) + self.assertEqual(response.status, http.client.FORBIDDEN) def test_login(self): response = self.web_get() - if response.status != http_client.FORBIDDEN: + if response.status != http.client.FORBIDDEN: self.skipTest('Already authenticated, "test_response_denied" must have failed') # login self.web_login(self.admlogin, self.admpassword) response = self.web_get() - self.assertEqual(response.status, http_client.OK, response.body) + self.assertEqual(response.status, http.client.OK, response.body) # logout self.web_logout() response = self.web_get() - self.assertEqual(response.status, http_client.FORBIDDEN, response.body) + self.assertEqual(response.status, http.client.FORBIDDEN, response.body) if __name__ == '__main__': diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/test/unittest_i18n.py --- a/cubicweb/devtools/test/unittest_i18n.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/test/unittest_i18n.py Fri Apr 05 17:58:19 2019 +0200 @@ -19,14 +19,13 @@ """unit tests for i18n messages generator""" from contextlib import contextmanager -from io import StringIO, BytesIO +from io import StringIO import os import os.path as osp import sys from subprocess import PIPE, Popen, STDOUT from unittest import TestCase, main -from six import PY2 from mock import patch from cubicweb.devtools import devctl @@ -91,7 +90,7 @@ @contextmanager def capture_stdout(): - stream = BytesIO() if PY2 else StringIO() + stream = StringIO() sys.stdout = stream yield stream stream.seek(0) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/test/unittest_testlib.py --- a/cubicweb/devtools/test/unittest_testlib.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/test/unittest_testlib.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ from io import BytesIO, StringIO from unittest import TextTestRunner -from six import PY2 - from logilab.common.testlib import TestSuite, TestCase, unittest_main from logilab.common.registry import yes @@ -52,7 +50,7 @@ class WebTestTC(TestCase): def setUp(self): - output = BytesIO() if PY2 else StringIO() + output = StringIO() self.runner = TextTestRunner(stream=output) def test_error_raised(self): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/test/unittest_webtest.py --- a/cubicweb/devtools/test/unittest_webtest.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/test/unittest_webtest.py Fri Apr 05 17:58:19 2019 +0200 @@ -1,4 +1,4 @@ -from six.moves import http_client +import http.client from logilab.common.testlib import Tags from cubicweb.devtools.webtest import CubicWebTestTC @@ -21,19 +21,19 @@ def test_reponse_denied(self): res = self.webapp.get('/', expect_errors=True) - self.assertEqual(http_client.FORBIDDEN, res.status_int) + self.assertEqual(http.client.FORBIDDEN, res.status_int) def test_login(self): res = self.webapp.get('/', expect_errors=True) - self.assertEqual(http_client.FORBIDDEN, res.status_int) + self.assertEqual(http.client.FORBIDDEN, res.status_int) self.login(self.admlogin, self.admpassword) res = self.webapp.get('/') - self.assertEqual(http_client.OK, res.status_int) + self.assertEqual(http.client.OK, res.status_int) self.logout() res = self.webapp.get('/', expect_errors=True) - self.assertEqual(http_client.FORBIDDEN, res.status_int) + self.assertEqual(http.client.FORBIDDEN, res.status_int) if __name__ == '__main__': diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/devtools/testlib.py --- a/cubicweb/devtools/testlib.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/devtools/testlib.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,20 +17,15 @@ # with CubicWeb. If not, see . """Base classes and utilities for cubicweb tests""" -from __future__ import print_function - import sys import re -import warnings from os.path import dirname, join, abspath from math import log from contextlib import contextmanager from inspect import isgeneratorfunction from itertools import chain - -from six import binary_type, text_type, string_types, reraise -from six.moves import range -from six.moves.urllib.parse import urlparse, parse_qs, unquote as urlunquote +from unittest import TestCase +from urllib.parse import urlparse, parse_qs, unquote as urlunquote import yams.schema @@ -53,22 +48,6 @@ from cubicweb.devtools.fill import insert_entity_queries, make_relations_queries from cubicweb.web.views.authentication import Session -if sys.version_info[:2] < (3, 4): - from unittest2 import TestCase - if not hasattr(TestCase, 'subTest'): - raise ImportError('no subTest support in available unittest2') - try: - from backports.tempfile import TemporaryDirectory # noqa - except ImportError: - # backports.tempfile not available - TemporaryDirectory = None -else: - from unittest import TestCase - from tempfile import TemporaryDirectory # noqa - -# in python 2.7, DeprecationWarning are not shown anymore by default -warnings.filterwarnings('default', category=DeprecationWarning) - # provide a data directory for the test class ################################## @@ -326,7 +305,6 @@ """provide a new RepoAccess object for a given user The access is automatically closed at the end of the test.""" - login = text_type(login) access = RepoAccess(self.repo, login, self.requestcls) self._open_access.add(access) return access @@ -347,7 +325,7 @@ db_handler.restore_database(self.test_db_id) self.repo = db_handler.get_repo(startup=True) # get an admin session (without actual login) - login = text_type(db_handler.config.default_admin_config['login']) + login = db_handler.config.default_admin_config['login'] self.admin_access = self.new_access(login) # config management ######################################################## @@ -365,7 +343,7 @@ been properly bootstrapped. """ admincfg = config.default_admin_config - cls.admlogin = text_type(admincfg['login']) + cls.admlogin = admincfg['login'] cls.admpassword = admincfg['password'] # uncomment the line below if you want rql queries to be logged # config.global_set_option('query-log-file', @@ -458,15 +436,13 @@ """create and return a new user entity""" if password is None: password = login - if login is not None: - login = text_type(login) user = req.create_entity('CWUser', login=login, upassword=password, **kwargs) req.execute('SET X in_group G WHERE X eid %%(x)s, G name IN(%s)' % ','.join(repr(str(g)) for g in groups), {'x': user.eid}) if email is not None: - req.create_entity('EmailAddress', address=text_type(email), + req.create_entity('EmailAddress', address=email, reverse_primary_email=user) user.cw_clear_relation_cache('in_group', 'subject') if commit: @@ -524,7 +500,7 @@ """ torestore = [] for erschema, etypeperms in chain(perm_overrides, perm_kwoverrides.items()): - if isinstance(erschema, string_types): + if isinstance(erschema, str): erschema = self.schema[erschema] for action, actionperms in etypeperms.items(): origperms = erschema.permissions[action] @@ -730,7 +706,7 @@ req.form will be setup using the url's query string """ with self.admin_access.web_request(url=url) as req: - if isinstance(url, text_type): + if isinstance(url, str): url = url.encode(req.encoding) # req.setup_params() expects encoded strings querystring = urlparse(url)[-2] params = parse_qs(querystring) @@ -911,7 +887,7 @@ msg = '[%s in %s] %s' % (klass, view.__regid__, exc) except Exception: msg = '[%s in %s] undisplayable exception' % (klass, view.__regid__) - reraise(AssertionError, AssertionError(msg), sys.exc_info()[-1]) + raise AssertionError(msg).with_traceback(sys.exc_info()[-1]) return self._check_html(output, view, template) def get_validator(self, view=None, content_type=None, output=None): @@ -944,7 +920,7 @@ def _check_html(self, output, view, template='main-template'): """raises an exception if the HTML is invalid""" output = output.strip() - if isinstance(output, text_type): + if isinstance(output, str): # XXX output = output.encode('utf-8') validator = self.get_validator(view, output=output) @@ -977,8 +953,8 @@ position = getattr(exc, "position", (0,))[0] if position: # define filter - if isinstance(content, binary_type): - content = text_type(content, sys.getdefaultencoding(), 'replace') + if isinstance(content, bytes): + content = str(content, sys.getdefaultencoding(), 'replace') content = validator.preprocess_data(content) content = content.splitlines() width = int(log(len(content), 10)) + 1 diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/entities/__init__.py --- a/cubicweb/entities/__init__.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/entities/__init__.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,8 +17,6 @@ # with CubicWeb. If not, see . """base application's entities class implementation: `AnyEntity`""" -from six import text_type, string_types - from logilab.common.decorators import classproperty from cubicweb import Unauthorized @@ -34,7 +32,7 @@ @classproperty def cw_etype(cls): """entity type as a unicode string""" - return text_type(cls.__regid__) + return cls.__regid__ @classmethod def cw_create_url(cls, req, **kwargs): @@ -111,8 +109,8 @@ if rtype is None: return self.dc_title().lower() value = self.cw_attr_value(rtype) - # do not restrict to `unicode` because Bytes will return a `str` value - if isinstance(value, string_types): + # do not restrict to `str` because Bytes will return a `str` value + if isinstance(value, str): return self.printable_value(rtype, format='text/plain').lower() return value diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/entities/authobjs.py --- a/cubicweb/entities/authobjs.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/entities/authobjs.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,8 +17,6 @@ # with CubicWeb. If not, see . """entity classes user and group entities""" -from six import string_types, text_type - from logilab.common.decorators import cached from cubicweb import Unauthorized @@ -110,13 +108,12 @@ return self._cw.vreg.property_value(key) def set_property(self, pkey, value): - value = text_type(value) try: prop = self._cw.execute( 'CWProperty X WHERE X pkey %(k)s, X for_user U, U eid %(u)s', {'k': pkey, 'u': self.eid}).get_entity(0, 0) except Exception: - kwargs = dict(pkey=text_type(pkey), value=value) + kwargs = dict(pkey=pkey, value=value) if self.is_in_group('managers'): kwargs['for_user'] = self self._cw.create_entity('CWProperty', **kwargs) @@ -129,7 +126,7 @@ :type groups: str or iterable(str) :param groups: a group name or an iterable on group names """ - if isinstance(groups, string_types): + if isinstance(groups, str): groups = frozenset((groups,)) elif isinstance(groups, (tuple, list)): groups = frozenset(groups) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/entities/lib.py --- a/cubicweb/entities/lib.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/entities/lib.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,9 +20,7 @@ from warnings import warn from datetime import datetime - -from six.moves import range -from six.moves.urllib.parse import urlsplit, urlunsplit +from urllib.parse import urlsplit, urlunsplit from logilab.mtconverter import xml_escape diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/entities/sources.py --- a/cubicweb/entities/sources.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/entities/sources.py Fri Apr 05 17:58:19 2019 +0200 @@ -21,8 +21,6 @@ from socket import gethostname import logging -from six import text_type - from logilab.common.textutils import text_to_dict from logilab.common.configuration import OptionError from logilab.mtconverter import xml_escape diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/entities/wfobjs.py --- a/cubicweb/entities/wfobjs.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/entities/wfobjs.py Fri Apr 05 17:58:19 2019 +0200 @@ -21,12 +21,6 @@ * workflow history (TrInfo) * adapter for workflowable entities (IWorkflowableAdapter) """ -from __future__ import print_function - - - -from six import text_type, string_types - from logilab.common.decorators import cached, clear_cache from cubicweb.entities import AnyEntity, fetch_config @@ -98,7 +92,7 @@ def transition_by_name(self, trname): rset = self._cw.execute('Any T, TN WHERE T name TN, T name %(n)s, ' 'T transition_of WF, WF eid %(wf)s', - {'n': text_type(trname), 'wf': self.eid}) + {'n': trname, 'wf': self.eid}) if rset: return rset.get_entity(0, 0) return None @@ -115,7 +109,7 @@ def add_state(self, name, initial=False, **kwargs): """add a state to this workflow""" - state = self._cw.create_entity('State', name=text_type(name), **kwargs) + state = self._cw.create_entity('State', name=name, **kwargs) self._cw.execute('SET S state_of WF WHERE S eid %(s)s, WF eid %(wf)s', {'s': state.eid, 'wf': self.eid}) if initial: @@ -127,7 +121,7 @@ def _add_transition(self, trtype, name, fromstates, requiredgroups=(), conditions=(), **kwargs): - tr = self._cw.create_entity(trtype, name=text_type(name), **kwargs) + tr = self._cw.create_entity(trtype, name=name, **kwargs) self._cw.execute('SET T transition_of WF ' 'WHERE T eid %(t)s, WF eid %(wf)s', {'t': tr.eid, 'wf': self.eid}) @@ -257,13 +251,13 @@ for gname in requiredgroups: rset = self._cw.execute('SET T require_group G ' 'WHERE T eid %(x)s, G name %(gn)s', - {'x': self.eid, 'gn': text_type(gname)}) + {'x': self.eid, 'gn': gname}) assert rset, '%s is not a known group' % gname - if isinstance(conditions, string_types): + if isinstance(conditions, str): conditions = (conditions,) for expr in conditions: - if isinstance(expr, string_types): - kwargs = {'expr': text_type(expr)} + if isinstance(expr, str): + kwargs = {'expr': expr} else: assert isinstance(expr, dict) kwargs = expr @@ -415,7 +409,7 @@ """return the default workflow for entities of this type""" # XXX CWEType method wfrset = self._cw.execute('Any WF WHERE ET default_workflow WF, ' - 'ET name %(et)s', {'et': text_type(self.entity.cw_etype)}) + 'ET name %(et)s', {'et': self.entity.cw_etype}) if wfrset: return wfrset.get_entity(0, 0) self.warning("can't find any workflow for %s", self.entity.cw_etype) @@ -480,7 +474,7 @@ 'Any T,TT, TN WHERE S allowed_transition T, S eid %(x)s, ' 'T type TT, T type %(type)s, ' 'T name TN, T transition_of WF, WF eid %(wfeid)s', - {'x': self.current_state.eid, 'type': text_type(type), + {'x': self.current_state.eid, 'type': type, 'wfeid': self.current_workflow.eid}) for tr in rset.entities(): if tr.may_be_fired(self.entity.eid): @@ -529,7 +523,7 @@ def _get_transition(self, tr): assert self.current_workflow - if isinstance(tr, string_types): + if isinstance(tr, str): _tr = self.current_workflow.transition_by_name(tr) assert _tr is not None, 'not a %s transition: %s' % ( self.__regid__, tr) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/entity.py --- a/cubicweb/entity.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/entity.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,9 +17,6 @@ # with CubicWeb. If not, see . """Base class for entity objects manipulated in clients""" -from six import text_type, string_types, integer_types -from six.moves import range - from logilab.common.decorators import cached from logilab.common.registry import yes from logilab.mtconverter import TransformData, xml_escape @@ -55,7 +52,6 @@ """return True if value can be used at the end of a Rest URL path""" if value is None: return False - value = text_type(value) # the check for ?, /, & are to prevent problems when running # behind Apache mod_proxy if value == u'' or u'?' in value or u'/' in value or u'&' in value: @@ -265,7 +261,7 @@ select = Select() mainvar = select.get_variable(mainvar) select.add_selected(mainvar) - elif isinstance(mainvar, string_types): + elif isinstance(mainvar, str): assert mainvar in select.defined_vars mainvar = select.get_variable(mainvar) # eases string -> syntax tree test transition: please remove once stable @@ -506,12 +502,12 @@ return NotImplemented def __eq__(self, other): - if isinstance(self.eid, integer_types): + if isinstance(self.eid, int): return self.eid == other.eid return self is other def __hash__(self): - if isinstance(self.eid, integer_types): + if isinstance(self.eid, int): return self.eid return super(Entity, self).__hash__() @@ -639,7 +635,7 @@ if path is None: # fallback url: / url is used as cw entities uri, # prefer it to //eid/ - return text_type(value) + return str(value) return u'%s/%s' % (path, self._cw.url_quote(value)) def cw_attr_metadata(self, attr, metadata): @@ -657,7 +653,7 @@ attr = str(attr) if value is _marker: value = getattr(self, attr) - if isinstance(value, string_types): + if isinstance(value, str): value = value.strip() if value is None or value == '': # don't use "not", 0 is an acceptable value return u'' diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/ext/rest.py --- a/cubicweb/ext/rest.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/ext/rest.py Fri Apr 05 17:58:19 2019 +0200 @@ -38,9 +38,7 @@ from itertools import chain from logging import getLogger from os.path import join - -from six import text_type -from six.moves.urllib.parse import urlsplit +from urllib.parse import urlsplit from docutils import statemachine, nodes, utils, io from docutils.core import Publisher @@ -403,7 +401,7 @@ the data formatted as HTML or the original data if an error occurred """ req = context._cw - if isinstance(data, text_type): + if isinstance(data, str): encoding = 'utf-8' # remove unprintable characters unauthorized in xml data = data.translate(ESC_UCAR_TABLE) @@ -448,8 +446,8 @@ return res except BaseException: LOGGER.exception('error while publishing ReST text') - if not isinstance(data, text_type): - data = text_type(data, encoding, 'replace') + if not isinstance(data, str): + data = data.encode(encoding, 'replace') return xml_escape(req._('error while publishing ReST text') + '\n\n' + data) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/ext/test/unittest_rest.py --- a/cubicweb/ext/test/unittest_rest.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/ext/test/unittest_rest.py Fri Apr 05 17:58:19 2019 +0200 @@ -15,7 +15,6 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -from six import PY3 from logilab.common.testlib import unittest_main from cubicweb.devtools.testlib import CubicWebTC @@ -93,8 +92,7 @@ context = self.context(req) out = rest_publish(context, ':rql:`Any X WHERE X is CWUser:toto`') self.assertTrue(out.startswith("

an error occurred while interpreting this " - "rql directive: ObjectNotFound(%s'toto'" % - ('' if PY3 else 'u')), + "rql directive: ObjectNotFound('toto'"), out) def test_rql_role_without_vid(self): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/hooks/integrity.py --- a/cubicweb/hooks/integrity.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/hooks/integrity.py Fri Apr 05 17:58:19 2019 +0200 @@ -23,8 +23,6 @@ from threading import Lock -from six import text_type - from cubicweb import validation_error, neg_role from cubicweb.schema import (META_RTYPES, WORKFLOW_RTYPES, RQLConstraint, RQLUniqueConstraint) @@ -276,7 +274,7 @@ value = edited[attr] except KeyError: continue # no text to tidy - if isinstance(value, text_type): # filter out None and Binary + if isinstance(value, str): # filter out None and Binary if getattr(entity, str(metaattr)) == 'text/html': edited[attr] = soup2xhtml(value, self._cw.encoding) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/hooks/test/unittest_hooks.py --- a/cubicweb/hooks/test/unittest_hooks.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/hooks/test/unittest_hooks.py Fri Apr 05 17:58:19 2019 +0200 @@ -24,8 +24,6 @@ from datetime import datetime -from six import text_type - from pytz import utc from cubicweb import ValidationError @@ -211,7 +209,7 @@ with self.assertRaises(ValidationError) as cm: cnx.execute('INSERT CWUser X: X login "admin", X upassword "admin"') ex = cm.exception - ex.translate(text_type) + ex.translate(str) self.assertIsInstance(ex.entity, int) self.assertEqual(ex.errors, {'': u'some relations violate a unicity constraint', diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/hooks/test/unittest_syncsession.py --- a/cubicweb/hooks/test/unittest_syncsession.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/hooks/test/unittest_syncsession.py Fri Apr 05 17:58:19 2019 +0200 @@ -22,8 +22,6 @@ syncschema.py hooks are mostly tested in server/test/unittest_migrations.py """ -from six import text_type - from cubicweb import ValidationError from cubicweb.devtools.testlib import CubicWebTC @@ -35,13 +33,13 @@ with self.assertRaises(ValidationError) as cm: req.execute('INSERT CWProperty X: X pkey "bla.bla", ' 'X value "hop", X for_user U') - cm.exception.translate(text_type) + cm.exception.translate(str) self.assertEqual(cm.exception.errors, {'pkey-subject': 'unknown property key bla.bla'}) with self.assertRaises(ValidationError) as cm: req.execute('INSERT CWProperty X: X pkey "bla.bla", X value "hop"') - cm.exception.translate(text_type) + cm.exception.translate(str) self.assertEqual(cm.exception.errors, {'pkey-subject': 'unknown property key bla.bla'}) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/i18n.py --- a/cubicweb/i18n.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/i18n.py Fri Apr 05 17:58:19 2019 +0200 @@ -16,17 +16,11 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """Some i18n/gettext utilities.""" -from __future__ import print_function - - - import re import os from os.path import join, basename, splitext, exists from glob import glob -from six import PY2 - from cubicweb.toolsutils import create_dir def extract_from_tal(files, output_file): @@ -42,11 +36,7 @@ def add_msg(w, msgid, msgctx=None): """write an empty pot msgid definition""" - if PY2 and isinstance(msgid, unicode): - msgid = msgid.encode('utf-8') if msgctx: - if PY2 and isinstance(msgctx, unicode): - msgctx = msgctx.encode('utf-8') w('msgctxt "%s"\n' % msgctx) msgid = msgid.replace('"', r'\"').splitlines() if len(msgid) > 1: diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/mail.py --- a/cubicweb/mail.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/mail.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,8 +17,6 @@ # with CubicWeb. If not, see . """Common utilies to format / send emails.""" - - from base64 import b64encode, b64decode from time import time from email.mime.multipart import MIMEMultipart @@ -28,21 +26,13 @@ from email.utils import formatdate from socket import gethostname -from six import PY2, PY3, text_type - def header(ustring): - if PY3: - return Header(ustring, 'utf-8') - return Header(ustring.encode('UTF-8'), 'UTF-8') + return Header(ustring, 'utf-8') -def addrheader(uaddr, uname=None): +def addrheader(addr, uname=None): # even if an email address should be ascii, encode it using utf8 since # automatic tests may generate non ascii email address - if PY2: - addr = uaddr.encode('UTF-8') - else: - addr = uaddr if uname: val = '%s <%s>' % (header(uname).encode(), addr) else: @@ -86,7 +76,7 @@ to_addrs and cc_addrs are expected to be a list of email address without name """ - assert isinstance(content, text_type), repr(content) + assert isinstance(content, str), repr(content) msg = MIMEText(content.encode('UTF-8'), 'plain', 'UTF-8') # safety: keep only the first newline try: @@ -97,13 +87,13 @@ if uinfo.get('email'): email = uinfo['email'] elif config and config['sender-addr']: - email = text_type(config['sender-addr']) + email = config['sender-addr'] else: email = u'' if uinfo.get('name'): name = uinfo['name'] elif config and config['sender-name']: - name = text_type(config['sender-name']) + name = config['sender-name'] else: name = u'' msg['From'] = addrheader(email, name) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/md5crypt.py --- a/cubicweb/md5crypt.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/md5crypt.py Fri Apr 05 17:58:19 2019 +0200 @@ -43,9 +43,6 @@ from hashlib import md5 # pylint: disable=E0611 -from six import text_type, indexbytes -from six.moves import range - def to64 (v, n): ret = bytearray() @@ -56,9 +53,9 @@ return ret def crypt(pw, salt): - if isinstance(pw, text_type): + if isinstance(pw, str): pw = pw.encode('utf-8') - if isinstance(salt, text_type): + if isinstance(salt, str): salt = salt.encode('ascii') # Take care of the magic string if present if salt.startswith(MAGIC): @@ -102,20 +99,20 @@ final = md5(ctx1).digest() # Final xform passwd = b'' - passwd += to64((indexbytes(final, 0) << 16) - |(indexbytes(final, 6) << 8) - |(indexbytes(final, 12)),4) - passwd += to64((indexbytes(final, 1) << 16) - |(indexbytes(final, 7) << 8) - |(indexbytes(final, 13)), 4) - passwd += to64((indexbytes(final, 2) << 16) - |(indexbytes(final, 8) << 8) - |(indexbytes(final, 14)), 4) - passwd += to64((indexbytes(final, 3) << 16) - |(indexbytes(final, 9) << 8) - |(indexbytes(final, 15)), 4) - passwd += to64((indexbytes(final, 4) << 16) - |(indexbytes(final, 10) << 8) - |(indexbytes(final, 5)), 4) - passwd += to64((indexbytes(final, 11)), 2) + passwd += to64((final[0] << 16) + |(final[6] << 8) + |(final[12]),4) + passwd += to64((final[1] << 16) + |(final[7] << 8) + |(final[13]), 4) + passwd += to64((final[2] << 16) + |(final[8] << 8) + |(final[14]), 4) + passwd += to64((final[3] << 16) + |(final[9] << 8) + |(final[15]), 4) + passwd += to64((final[4] << 16) + |(final[10] << 8) + |(final[5]), 4) + passwd += to64((final[11]), 2) return passwd diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/migration.py --- a/cubicweb/migration.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/migration.py Fri Apr 05 17:58:19 2019 +0200 @@ -16,7 +16,6 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """utilities for instances migration""" -from __future__ import print_function import sys import os @@ -25,8 +24,6 @@ from os.path import exists, join, basename, splitext from itertools import chain -from six import string_types - from logilab.common import IGNORED_EXTENSIONS from logilab.common.decorators import cached from logilab.common.configuration import REQUIRED, read_old_config @@ -405,7 +402,7 @@ """modify the list of used cubes in the in-memory config returns newly inserted cubes, including dependencies """ - if isinstance(cubes, string_types): + if isinstance(cubes, str): cubes = (cubes,) origcubes = self.config.cubes() newcubes = [p for p in self.config.expand_cubes(cubes) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/misc/migration/3.10.0_Any.py --- a/cubicweb/misc/migration/3.10.0_Any.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/misc/migration/3.10.0_Any.py Fri Apr 05 17:58:19 2019 +0200 @@ -1,5 +1,3 @@ -from six import text_type - add_entity_type('CWSource') add_relation_definition('CWSource', 'cw_source', 'CWSource') add_entity_type('CWSourceHostConfig') @@ -18,7 +16,7 @@ continue config = u'\n'.join('%s=%s' % (key, value) for key, value in cfg.items() if key != 'adapter' and value is not None) - create_entity('CWSource', name=text_type(uri), type=text_type(cfg['adapter']), + create_entity('CWSource', name=uri, type=cfg['adapter'], config=config) commit() diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/misc/migration/3.15.0_Any.py --- a/cubicweb/misc/migration/3.15.0_Any.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/misc/migration/3.15.0_Any.py Fri Apr 05 17:58:19 2019 +0200 @@ -16,7 +16,7 @@ sconfig.set_option(opt, val) except OptionError: continue - cfgstr = text_type(generate_source_config(sconfig), source._cw.encoding) + cfgstr = str(generate_source_config(sconfig), source._cw.encoding) source.cw_set(config=cfgstr) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/misc/migration/bootstrapmigration_repository.py --- a/cubicweb/misc/migration/bootstrapmigration_repository.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/misc/migration/bootstrapmigration_repository.py Fri Apr 05 17:58:19 2019 +0200 @@ -19,11 +19,6 @@ it should only include low level schema changes """ - -from __future__ import print_function - -from six import text_type - from cubicweb import ConfigurationError from cubicweb.server.session import hooks_control from cubicweb.server import schemaserial as ss @@ -120,7 +115,6 @@ default = yams.DATE_FACTORY_MAP[atype](default) else: assert atype == 'String', atype - default = text_type(default) return Binary.zpickle(default) dbh = repo.system_source.dbhelper diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/misc/migration/postcreate.py --- a/cubicweb/misc/migration/postcreate.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/misc/migration/postcreate.py Fri Apr 05 17:58:19 2019 +0200 @@ -16,19 +16,15 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """cubicweb post creation script, set user's workflow""" -from __future__ import print_function - -from six import text_type - from cubicweb import _ # insert versions create_entity('CWProperty', pkey=u'system.version.cubicweb', - value=text_type(config.cubicweb_version())) + value=str(config.cubicweb_version())) for cube in config.cubes(): create_entity('CWProperty', pkey=u'system.version.%s' % cube.lower(), - value=text_type(config.cube_version(cube))) + value=str(config.cube_version(cube))) # some entities have been added before schema entities, add their missing 'is' and # 'is_instance_of' relations @@ -56,7 +52,7 @@ print('Hopefully this is not a production instance...') elif anonlogin: from cubicweb.server import create_user - create_user(session, text_type(anonlogin), anonpwd, u'guests') + create_user(session, anonlogin, anonpwd, u'guests') # need this since we already have at least one user in the database (the default admin) for user in rql('Any X WHERE X is CWUser').entities(): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/misc/scripts/migration_helper.py --- a/cubicweb/misc/scripts/migration_helper.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/misc/scripts/migration_helper.py Fri Apr 05 17:58:19 2019 +0200 @@ -19,9 +19,6 @@ """Helper functions for migrations that aren't reliable enough or too dangerous to be available in the standard migration environment """ -from __future__ import print_function - - def drop_entity_types_fast(*etypes, **kwargs): """drop an entity type bypassing all hooks diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/multipart.py --- a/cubicweb/multipart.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/multipart.py Fri Apr 05 17:58:19 2019 +0200 @@ -37,16 +37,12 @@ __version__ = '0.1' __license__ = 'MIT' +from io import BytesIO from tempfile import TemporaryFile +from urllib.parse import parse_qs from wsgiref.headers import Headers import re, sys -try: - from io import BytesIO -except ImportError: # pragma: no cover (fallback for Python 2.5) - from StringIO import StringIO as BytesIO -from six import PY3, text_type -from six.moves.urllib.parse import parse_qs ############################################################################## ################################ Helper & Misc ################################ @@ -88,7 +84,7 @@ yield key, value def tob(data, enc='utf8'): # Convert strings to bytes (py2 and py3) - return data.encode(enc) if isinstance(data, text_type) else data + return data.encode(enc) if isinstance(data, str) else data def copy_file(stream, target, maxread=-1, buffer_size=2*16): ''' Read from :stream and write to :target until :maxread or EOF. ''' @@ -400,15 +396,11 @@ data = stream.read(mem_limit) if stream.read(1): # These is more that does not fit mem_limit raise MultipartError("Request too big. Increase MAXMEM.") - if PY3: - data = data.decode('ascii') + data = data.decode('ascii') data = parse_qs(data, keep_blank_values=True) for key, values in data.items(): for value in values: - if PY3: - forms[key] = value - else: - forms[key.decode(charset)] = value.decode(charset) + forms[key] = value else: raise MultipartError("Unsupported content type.") except MultipartError: diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/predicates.py --- a/cubicweb/predicates.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/predicates.py Fri Apr 05 17:58:19 2019 +0200 @@ -24,9 +24,6 @@ from warnings import warn from operator import eq -from six import string_types, integer_types -from six.moves import range - from logilab.common.registry import Predicate, objectify_predicate from yams.schema import BASE_TYPES, role_name @@ -610,7 +607,7 @@ super(is_instance, self).__init__(**kwargs) self.expected_etypes = expected_etypes for etype in self.expected_etypes: - assert isinstance(etype, string_types), etype + assert isinstance(etype, str), etype def __str__(self): return '%s(%s)' % (self.__class__.__name__, @@ -670,7 +667,7 @@ score = scorefunc(*args, **kwargs) if not score: return 0 - if isinstance(score, integer_types): + if isinstance(score, int): return score return 1 self.score_entity = intscore @@ -1088,7 +1085,7 @@ See :class:`cubicweb.entities.wfobjs.TrInfo` for more information. """ - if isinstance(tr_names, string_types): + if isinstance(tr_names, str): tr_names = set((tr_names,)) def match_etype_and_transition(trinfo): # take care trinfo.transition is None when calling change_state @@ -1288,7 +1285,7 @@ raise ValueError("match_form_params() can't be called with both " "positional and named arguments") if expected: - if len(expected) == 1 and not isinstance(expected[0], string_types): + if len(expected) == 1 and not isinstance(expected[0], str): raise ValueError("match_form_params() positional arguments " "must be strings") super(match_form_params, self).__init__(*expected) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/pyramid/__init__.py --- a/cubicweb/pyramid/__init__.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/pyramid/__init__.py Fri Apr 05 17:58:19 2019 +0200 @@ -21,10 +21,10 @@ """Pyramid interface to CubicWeb""" import atexit +from configparser import SafeConfigParser import os import warnings -from six.moves.configparser import SafeConfigParser import wsgicors from cubicweb.cwconfig import CubicWebConfiguration as cwcfg diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/pyramid/profile.py --- a/cubicweb/pyramid/profile.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/pyramid/profile.py Fri Apr 05 17:58:19 2019 +0200 @@ -21,7 +21,6 @@ """ Tools for profiling. See :ref:`profiling`.""" -from __future__ import print_function import cProfile import itertools diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/pyramid/pyramidctl.py --- a/cubicweb/pyramid/pyramidctl.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/pyramid/pyramidctl.py Fri Apr 05 17:58:19 2019 +0200 @@ -25,8 +25,6 @@ the pyramid script 'pserve'. """ -from __future__ import print_function - import atexit import errno import os diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/pyramid/resources.py --- a/cubicweb/pyramid/resources.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/pyramid/resources.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ """Pyramid resource definitions for CubicWeb.""" -from six import text_type - from rql import TypeResolverException from pyramid.decorator import reify @@ -62,7 +60,7 @@ # conflicting eid/type raise HTTPNotFound() else: - rset = req.execute(st.as_string(), {'x': text_type(self.value)}) + rset = req.execute(st.as_string(), {'x': self.value}) return rset diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/pyramid/test/test_config.py --- a/cubicweb/pyramid/test/test_config.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/pyramid/test/test_config.py Fri Apr 05 17:58:19 2019 +0200 @@ -19,11 +19,11 @@ import os from os import path +from tempfile import TemporaryDirectory from unittest import TestCase from mock import patch -from cubicweb.devtools.testlib import TemporaryDirectory from cubicweb.pyramid import config diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/pyramid/test/test_hooks.py --- a/cubicweb/pyramid/test/test_hooks.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/pyramid/test/test_hooks.py Fri Apr 05 17:58:19 2019 +0200 @@ -1,5 +1,3 @@ -from six import text_type - from cubicweb.pyramid.test import PyramidCWTest from cubicweb.pyramid import tools @@ -11,10 +9,10 @@ cnx.execute('DELETE CWProperty X WHERE X for_user U, U eid %(u)s', {'u': cnx.user.eid}) else: - cnx.user.set_property(u'ui.language', text_type(lang)) + cnx.user.set_property(u'ui.language', lang) cnx.commit() - request.response.text = text_type(cnx.user.properties.get('ui.language', '')) + request.response.text = cnx.user.properties.get('ui.language', '') return request.response @@ -29,7 +27,7 @@ {'u': cnx.user.eid}) cnx.commit() - request.response.text = text_type(','.join(sorted(cnx.user.groups))) + request.response.text = ','.join(sorted(cnx.user.groups)) return request.response diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/req.py --- a/cubicweb/req.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/req.py Fri Apr 05 17:58:19 2019 +0200 @@ -18,11 +18,9 @@ """Base class for request/session""" from datetime import time, datetime, timedelta - -from six import PY2, PY3, text_type -from six.moves.urllib.parse import (parse_qs, parse_qsl, - quote as urlquote, unquote as urlunquote, - urlsplit, urlunsplit) +from urllib.parse import (parse_qs, parse_qsl, + quote as urlquote, unquote as urlunquote, + urlsplit, urlunsplit) from logilab.common.decorators import cached from logilab.common.date import ustrftime, strptime, todate, todatetime @@ -73,7 +71,7 @@ self.user = None self.lang = None self.local_perm_cache = {} - self._ = text_type + self._ = str def _set_user(self, orig_user): """set the user for this req_session_base @@ -97,10 +95,10 @@ gettext, pgettext = self.vreg.config.translations[lang] except KeyError: assert self.vreg.config.mode == 'test' - gettext = text_type + gettext = str def pgettext(x, y): - return text_type(y) + return str(y) # use _cw.__ to translate a message without registering it to the catalog self._ = self.__ = gettext @@ -274,9 +272,6 @@ necessary encoding / decoding. Also it's designed to quote each part of a url path and so the '/' character will be encoded as well. """ - if PY2 and isinstance(value, text_type): - quoted = urlquote(value.encode(self.encoding), safe=safe) - return text_type(quoted, self.encoding) return urlquote(str(value), safe=safe) def url_unquote(self, quoted): @@ -285,28 +280,13 @@ decoding is based on `self.encoding` which is the encoding used in `url_quote` """ - if PY3: - return urlunquote(quoted) - if isinstance(quoted, text_type): - quoted = quoted.encode(self.encoding) - try: - return text_type(urlunquote(quoted), self.encoding) - except UnicodeDecodeError: # might occurs on manually typed URLs - return text_type(urlunquote(quoted), 'iso-8859-1') + return urlunquote(quoted) def url_parse_qsl(self, querystring): """return a list of (key, val) found in the url quoted query string""" - if PY3: - for key, val in parse_qsl(querystring): - yield key, val - return - if isinstance(querystring, text_type): - querystring = querystring.encode(self.encoding) for key, val in parse_qsl(querystring): - try: - yield text_type(key, self.encoding), text_type(val, self.encoding) - except UnicodeDecodeError: # might occurs on manually typed URLs - yield text_type(key, 'iso-8859-1'), text_type(val, 'iso-8859-1') + yield key, val + return def rebuild_url(self, url, **newparams): """return the given url with newparams inserted. If any new params @@ -314,8 +294,6 @@ newparams may only be mono-valued. """ - if PY2 and isinstance(url, text_type): - url = url.encode(self.encoding) schema, netloc, path, query, fragment = urlsplit(url) query = parse_qs(query) # sort for testing predictability @@ -386,7 +364,7 @@ as_string = formatters[attrtype] except KeyError: self.error('given bad attrtype %s', attrtype) - return text_type(value) + return str(value) return as_string(value, self, props, displaytime) def format_date(self, date, date_format=None, time=False): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/rqlrewrite.py --- a/cubicweb/rqlrewrite.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/rqlrewrite.py Fri Apr 05 17:58:19 2019 +0200 @@ -21,8 +21,6 @@ This is used for instance for read security checking in the repository. """ -from six import text_type, string_types - from rql import nodes as n, stmts, TypeResolverException from rql.utils import common_parent @@ -640,7 +638,7 @@ while argname in self.kwargs: argname = subselect.allocate_varname() subselect.add_constant_restriction(subselect.get_variable(self.u_varname), - 'eid', text_type(argname), 'Substitute') + 'eid', argname, 'Substitute') self.kwargs[argname] = self.session.user.eid add_types_restriction(self.schema, subselect, subselect, solutions=self.solutions) @@ -795,7 +793,7 @@ # insert "U eid %(u)s" stmt.add_constant_restriction( stmt.get_variable(self.u_varname), - 'eid', text_type(argname), 'Substitute') + 'eid', argname, 'Substitute') self.kwargs[argname] = self.session.user.eid return self.u_varname key = (self.current_expr, self.varmap, vname) @@ -917,7 +915,7 @@ return n.Constant(vi['const'], 'Int') return n.VariableRef(stmt.get_variable(selectvar)) vname_or_term = self._get_varname_or_term(node.name) - if isinstance(vname_or_term, string_types): + if isinstance(vname_or_term, str): return n.VariableRef(stmt.get_variable(vname_or_term)) # shared term return vname_or_term.copy(stmt) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/rset.py --- a/cubicweb/rset.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/rset.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,10 +17,6 @@ # with CubicWeb. If not, see . """The `ResultSet` class which is returned as result of an rql query""" - -from six import PY3, text_type -from six.moves import range - from logilab.common.decorators import cached, clear_cache, copy_cache from rql import nodes, stmts @@ -366,13 +362,7 @@ """return the result set's origin rql as a string, with arguments substitued """ - encoding = self.req.encoding - rqlstr = self.syntax_tree().as_string(kwargs=self.args) - if PY3: - return rqlstr - if isinstance(rqlstr, text_type): - return rqlstr - return text_type(rqlstr, encoding) + return self.syntax_tree().as_string(kwargs=self.args) # client helper methods ################################################### diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/rtags.py --- a/cubicweb/rtags.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/rtags.py Fri Apr 05 17:58:19 2019 +0200 @@ -39,8 +39,6 @@ import logging -from six import string_types - from logilab.common.logging_ext import set_log_methods from logilab.common.registry import RegistrableInstance, yes @@ -182,7 +180,7 @@ return tag def _tag_etype_attr(self, etype, attr, desttype='*', *args, **kwargs): - if isinstance(attr, string_types): + if isinstance(attr, str): attr, role = attr, 'subject' else: attr, role = attr diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/schema.py --- a/cubicweb/schema.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/schema.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,17 +17,12 @@ # with CubicWeb. If not, see . """classes to define schemas for CubicWeb""" -from __future__ import print_function - from functools import wraps import re from os.path import join from hashlib import md5 from logging import getLogger -from six import PY2, text_type, string_types, add_metaclass -from six.moves import range - from logilab.common.decorators import cached, clear_cache, monkeypatch, cachedproperty from logilab.common.logging_ext import set_log_methods from logilab.common.textutils import splitstrip @@ -145,8 +140,6 @@ added/removed for instance) """ union = parse(u'Any 1 WHERE %s' % rqlstring).as_string() - if PY2 and isinstance(union, str): - union = union.decode('utf-8') return union.split(' WHERE ', 1)[1] @@ -218,7 +211,7 @@ """ self.eid = eid # eid of the entity representing this rql expression assert mainvars, 'bad mainvars %s' % mainvars - if isinstance(mainvars, string_types): + if isinstance(mainvars, str): mainvars = set(splitstrip(mainvars)) elif not isinstance(mainvars, set): mainvars = set(mainvars) @@ -579,9 +572,9 @@ key = key + '_' + form # ensure unicode if context is not None: - return text_type(req.pgettext(context, key)) + return req.pgettext(context, key) else: - return text_type(req._(key)) + return req._(key) def _override_method(cls, method_name=None, pass_original=False): @@ -627,7 +620,7 @@ """ assert action in self.ACTIONS, action try: - return frozenset(g for g in self.permissions[action] if isinstance(g, string_types)) + return frozenset(g for g in self.permissions[action] if isinstance(g, str)) except KeyError: return () @@ -646,7 +639,7 @@ """ assert action in self.ACTIONS, action try: - return tuple(g for g in self.permissions[action] if not isinstance(g, string_types)) + return tuple(g for g in self.permissions[action] if not isinstance(g, str)) except KeyError: return () @@ -1333,8 +1326,7 @@ return cls -@add_metaclass(workflowable_definition) -class WorkflowableEntityType(ybo.EntityType): +class WorkflowableEntityType(ybo.EntityType, metaclass=workflowable_definition): """Use this base class instead of :class:`EntityType` to have workflow relations (i.e. `in_state`, `wf_info_for` and `custom_workflow`) on your entity type. diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/__init__.py --- a/cubicweb/server/__init__.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/__init__.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,13 +20,8 @@ The server module contains functions to initialize a new repository. """ -from __future__ import print_function - from contextlib import contextmanager -from six import text_type, string_types -from six.moves import filter - from logilab.common.modutils import LazyObject from logilab.common.textutils import splitstrip from logilab.common.registry import yes @@ -133,7 +128,7 @@ if not debugmode: DEBUG = 0 return - if isinstance(debugmode, string_types): + if isinstance(debugmode, str): for mode in splitstrip(debugmode, sep='|'): DEBUG |= globals()[mode] else: @@ -192,7 +187,7 @@ user = session.create_entity('CWUser', login=login, upassword=pwd) for group in groups: session.execute('SET U in_group G WHERE U eid %(u)s, G name %(group)s', - {'u': user.eid, 'group': text_type(group)}) + {'u': user.eid, 'group': group}) return user @@ -270,17 +265,17 @@ # insert base groups and default admin print('-> inserting default user and default groups.') try: - login = text_type(sourcescfg['admin']['login']) + login = sourcescfg['admin']['login'] pwd = sourcescfg['admin']['password'] except KeyError: if interactive: msg = 'enter login and password of the initial manager account' login, pwd = manager_userpasswd(msg=msg, confirm=True) else: - login, pwd = text_type(source['db-user']), source['db-password'] + login, pwd = source['db-user'], source['db-password'] # sort for eid predicatability as expected in some server tests for group in sorted(BASE_GROUPS): - cnx.create_entity('CWGroup', name=text_type(group)) + cnx.create_entity('CWGroup', name=group) admin = create_user(cnx, login, pwd, u'managers') cnx.execute('SET X owned_by U WHERE X is IN (CWGroup,CWSource), U eid %(u)s', {'u': admin.eid}) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/checkintegrity.py --- a/cubicweb/server/checkintegrity.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/checkintegrity.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,7 +20,6 @@ * integrity of a CubicWeb repository. Hum actually only the system database is checked. """ -from __future__ import print_function import sys from datetime import datetime diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/hook.py --- a/cubicweb/server/hook.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/hook.py Fri Apr 05 17:58:19 2019 +0200 @@ -245,7 +245,6 @@ .. autoclass:: cubicweb.server.hook.LateOperation .. autoclass:: cubicweb.server.hook.DataOperationMixIn """ -from __future__ import print_function from logging import getLogger from itertools import chain diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/migractions.py --- a/cubicweb/server/migractions.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/migractions.py Fri Apr 05 17:58:19 2019 +0200 @@ -26,9 +26,6 @@ * add an entity * execute raw RQL queries """ -from __future__ import print_function - - import sys import os @@ -41,8 +38,6 @@ from copy import copy from contextlib import contextmanager -from six import PY2, text_type - from logilab.common.decorators import cached, clear_cache from yams.buildobjs import EntityType @@ -153,7 +148,7 @@ def cube_upgraded(self, cube, version): self.cmd_set_property('system.version.%s' % cube.lower(), - text_type(version)) + str(version)) self.commit() def shutdown(self): @@ -1005,7 +1000,7 @@ # elif simply renaming an entity type else: self.rqlexec('SET ET name %(newname)s WHERE ET is CWEType, ET name %(on)s', - {'newname': text_type(newname), 'on': oldname}, + {'newname': newname, 'on': oldname}, ask_confirm=False) if commit: self.commit() @@ -1217,8 +1212,6 @@ values = [] for k, v in kwargs.items(): values.append('X %s %%(%s)s' % (k, k)) - if PY2 and isinstance(v, str): - kwargs[k] = unicode(v) rql = 'SET %s WHERE %s' % (','.join(values), ','.join(restriction)) self.rqlexec(rql, kwargs, ask_confirm=self.verbosity >= 2) if commit: @@ -1250,7 +1243,7 @@ self.rqlexec('SET C value %%(v)s WHERE X from_entity S, X relation_type R,' 'X constrained_by C, C cstrtype CT, CT name "SizeConstraint",' 'S name "%s", R name "%s"' % (etype, rtype), - {'v': text_type(SizeConstraint(size).serialize())}, + {'v': SizeConstraint(size).serialize()}, ask_confirm=self.verbosity >= 2) else: self.rqlexec('DELETE X constrained_by C WHERE X from_entity S, X relation_type R,' @@ -1287,7 +1280,7 @@ :rtype: `Workflow` """ - wf = self.cmd_create_entity('Workflow', name=text_type(name), + wf = self.cmd_create_entity('Workflow', name=name, **kwargs) if not isinstance(wfof, (list, tuple)): wfof = (wfof,) @@ -1297,19 +1290,18 @@ for etype in wfof: eschema = self.repo.schema[etype] - etype = text_type(etype) if ensure_workflowable: assert 'in_state' in eschema.subjrels, _missing_wf_rel(etype) assert 'custom_workflow' in eschema.subjrels, _missing_wf_rel(etype) assert 'wf_info_for' in eschema.objrels, _missing_wf_rel(etype) rset = self.rqlexec( 'SET X workflow_of ET WHERE X eid %(x)s, ET name %(et)s', - {'x': wf.eid, 'et': text_type(etype)}, ask_confirm=False) + {'x': wf.eid, 'et': etype}, ask_confirm=False) assert rset, 'unexistant entity type %s' % etype if default: self.rqlexec( 'SET ET default_workflow X WHERE X eid %(x)s, ET name %(et)s', - {'x': wf.eid, 'et': text_type(etype)}, ask_confirm=False) + {'x': wf.eid, 'et': etype}, ask_confirm=False) if commit: self.commit() return wf @@ -1340,13 +1332,13 @@ To set a user specific property value, use appropriate method on CWUser instance. """ - value = text_type(value) + value = str(value) try: prop = self.rqlexec( 'CWProperty X WHERE X pkey %(k)s, NOT X for_user U', - {'k': text_type(pkey)}, ask_confirm=False).get_entity(0, 0) + {'k': str(pkey)}, ask_confirm=False).get_entity(0, 0) except Exception: - self.cmd_create_entity('CWProperty', pkey=text_type(pkey), value=value) + self.cmd_create_entity('CWProperty', pkey=str(pkey), value=value) else: prop.cw_set(value=value) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/querier.py --- a/cubicweb/server/querier.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/querier.py Fri Apr 05 17:58:19 2019 +0200 @@ -18,13 +18,8 @@ """Helper classes to execute RQL queries on a set of sources, performing security checking and data aggregation. """ -from __future__ import print_function - from itertools import repeat -from six import text_type, string_types, integer_types -from six.moves import range, zip - from rql import RQLSyntaxError, CoercionError from rql.stmts import Union from rql.nodes import ETYPE_PYOBJ_MAP, etype_from_pyobj, Relation, Exists, Not @@ -442,13 +437,13 @@ relations = {} for subj, rtype, obj in self.relation_defs(): # if a string is given into args instead of an int, we get it here - if isinstance(subj, string_types): + if isinstance(subj, str): subj = int(subj) - elif not isinstance(subj, integer_types): + elif not isinstance(subj, int): subj = subj.entity.eid - if isinstance(obj, string_types): + if isinstance(obj, str): obj = int(obj) - elif not isinstance(obj, integer_types): + elif not isinstance(obj, int): obj = obj.entity.eid if repo.schema.rschema(rtype).inlined: if subj not in edited_entities: @@ -623,7 +618,7 @@ def parse(rql, annotate=False, parse=rqlhelper.parse): """Return a freshly parsed syntax tree for the given RQL.""" try: - return parse(text_type(rql), annotate=annotate) + return parse(rql, annotate=annotate) except UnicodeError: raise RQLSyntaxError(rql) self._parse = parse diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/repository.py --- a/cubicweb/server/repository.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/repository.py Fri Apr 05 17:58:19 2019 +0200 @@ -26,13 +26,10 @@ * handles session management """ -from __future__ import print_function - from itertools import chain from contextlib import contextmanager from logging import getLogger - -from six.moves import range, queue +import queue from logilab.common.decorators import cached, clear_cache diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/rqlannotation.py --- a/cubicweb/server/rqlannotation.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/rqlannotation.py Fri Apr 05 17:58:19 2019 +0200 @@ -19,8 +19,6 @@ code generation. """ -from __future__ import print_function - from rql import BadRQLQuery from rql.nodes import Relation, VariableRef, Constant, Variable, Or from rql.utils import common_parent diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/schema2sql.py --- a/cubicweb/server/schema2sql.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/schema2sql.py Fri Apr 05 17:58:19 2019 +0200 @@ -19,9 +19,6 @@ from hashlib import md5 -from six import string_types, text_type -from six.moves import range - from yams.constraints import (SizeConstraint, UniqueConstraint, Attribute, NOW, TODAY) from logilab import database @@ -88,9 +85,9 @@ given attributes of the entity schema (actually, the later may be a schema or a string). """ # keep giving eschema instead of table name for bw compat - table = text_type(eschema) + table = str(eschema) # unique_index_name is used as name of CWUniqueConstraint, hence it should be unicode - return text_type(build_index_name(table, attrs, 'unique_')) + return build_index_name(table, attrs, 'unique_') def iter_unique_index_names(eschema): @@ -204,7 +201,7 @@ return cstrname, ' AND '.join(condition) elif constraint.type() == 'StaticVocabularyConstraint': sample = next(iter(constraint.vocabulary())) - if not isinstance(sample, string_types): + if not isinstance(sample, str): values = ', '.join(str(word) for word in constraint.vocabulary()) else: # XXX better quoting? diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/schemaserial.py --- a/cubicweb/server/schemaserial.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/schemaserial.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,14 +17,10 @@ # with CubicWeb. If not, see . """functions for schema / permissions (de)serialization using RQL""" -from __future__ import print_function - import json import sys import sqlite3 -from six import PY2, text_type, string_types - from logilab.common.shellutils import ProgressBar, DummyProgressBar from yams import BadSchemaDefinition, schema as schemamod, buildobjs as ybo, constraints @@ -378,7 +374,7 @@ cstrtypemap = {} rql = 'INSERT CWConstraintType X: X name %(ct)s' for cstrtype in CONSTRAINTS: - cstrtypemap[cstrtype] = execute(rql, {'ct': text_type(cstrtype)}, + cstrtypemap[cstrtype] = execute(rql, {'ct': cstrtype}, build_descr=False)[0][0] pb.update() # serialize relations @@ -483,7 +479,7 @@ for i, name in enumerate(unique_together): rschema = eschema.schema.rschema(name) rtype = 'T%d' % i - substs[rtype] = text_type(rschema.type) + substs[rtype] = rschema.type relations.append('C relations %s' % rtype) restrictions.append('%(rtype)s name %%(%(rtype)s)s' % {'rtype': rtype}) relations = ', '.join(relations) @@ -494,18 +490,10 @@ def _ervalues(erschema): - try: - type_ = text_type(erschema.type) - except UnicodeDecodeError as e: - raise Exception("can't decode %s [was %s]" % (erschema.type, e)) - try: - desc = text_type(erschema.description) or u'' - except UnicodeDecodeError as e: - raise Exception("can't decode %s [was %s]" % (erschema.description, e)) return { - 'name': type_, + 'name': erschema.type, 'final': erschema.final, - 'description': desc, + 'description': erschema.description, } # rtype serialization @@ -531,10 +519,7 @@ values['final'] = rschema.final values['symmetric'] = rschema.symmetric values['inlined'] = rschema.inlined - if PY2 and isinstance(rschema.fulltext_container, str): - values['fulltext_container'] = unicode(rschema.fulltext_container) - else: - values['fulltext_container'] = rschema.fulltext_container + values['fulltext_container'] = rschema.fulltext_container relations = ['X %s %%(%s)s' % (attr, attr) for attr in sorted(values)] return relations, values @@ -547,7 +532,7 @@ def crschema_relations_values(crschema): values = _ervalues(crschema) - values['rule'] = text_type(crschema.rule) + values['rule'] = crschema.rule # XXX why oh why? del values['final'] relations = ['X %s %%(%s)s' % (attr, attr) for attr in sorted(values)] @@ -593,8 +578,6 @@ value = bool(value) elif prop == 'ordernum': value = int(value) - elif PY2 and isinstance(value, str): - value = unicode(value) if value is not None and prop == 'default': value = Binary.zpickle(value) values[amap.get(prop, prop)] = value @@ -606,7 +589,7 @@ def constraints2rql(cstrtypemap, constraints, rdefeid=None): for constraint in constraints: values = {'ct': cstrtypemap[constraint.type()], - 'value': text_type(constraint.serialize()), + 'value': constraint.serialize(), 'x': rdefeid} # when not specified, will have to be set by the caller yield 'INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X WHERE \ CT eid %(ct)s, EDEF eid %(x)s', values @@ -625,7 +608,7 @@ # may occurs when modifying persistent schema continue for group_or_rqlexpr in grantedto: - if isinstance(group_or_rqlexpr, string_types): + if isinstance(group_or_rqlexpr, str): # group try: yield ('SET X %s_permission Y WHERE Y eid %%(g)s, X eid %%(x)s' % action, @@ -639,9 +622,9 @@ rqlexpr = group_or_rqlexpr yield ('INSERT RQLExpression E: E expression %%(e)s, E exprtype %%(t)s, ' 'E mainvars %%(v)s, X %s_permission E WHERE X eid %%(x)s' % action, - {'e': text_type(rqlexpr.expression), - 'v': text_type(','.join(sorted(rqlexpr.mainvars))), - 't': text_type(rqlexpr.__class__.__name__)}) + {'e': rqlexpr.expression, + 'v': ','.join(sorted(rqlexpr.mainvars)), + 't': rqlexpr.__class__.__name__}) # update functions @@ -653,7 +636,7 @@ def updaterschema2rql(rschema, eid): if rschema.rule: yield ('SET X rule %(r)s WHERE X eid %(x)s', - {'x': eid, 'r': text_type(rschema.rule)}) + {'x': eid, 'r': rschema.rule}) else: relations, values = rschema_relations_values(rschema) values['x'] = eid diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/serverconfig.py --- a/cubicweb/server/serverconfig.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/serverconfig.py Fri Apr 05 17:58:19 2019 +0200 @@ -16,15 +16,11 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """server.serverconfig definition""" -from __future__ import print_function - - +from io import StringIO import sys from os.path import join, exists -from six.moves import StringIO - import logilab.common.configuration as lgconfig from logilab.common.decorators import cached diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/serverctl.py --- a/cubicweb/server/serverctl.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/serverctl.py Fri Apr 05 17:58:19 2019 +0200 @@ -16,18 +16,14 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """cubicweb-ctl commands and command handlers specific to the repository""" -from __future__ import print_function - # *ctl module should limit the number of import to be imported as quickly as # possible (for cubicweb-ctl reactivity, necessary for instance for usable bash # completion). So import locally in command helpers. +import sched import sys import os from contextlib import contextmanager -from six import string_types -from six.moves import input - from logilab.common.configuration import Configuration, merge_options from logilab.common.shellutils import ASK, generate_password @@ -1006,12 +1002,11 @@ def run(self, args): from cubicweb.cwctl import init_cmdline_log_threshold from cubicweb.server.repository import Repository - from cubicweb.server.utils import scheduler config = ServerConfiguration.config_for(args[0]) # Log to stdout, since the this command runs in the foreground. config.global_set_option('log-file', None) init_cmdline_log_threshold(config, self['loglevel']) - repo = Repository(config, scheduler()) + repo = Repository(config, sched.scheduler()) repo.bootstrap() try: repo.run_scheduler() @@ -1095,8 +1090,7 @@ for p in ('read', 'add', 'update', 'delete'): rule = perms.get(p) if rule: - perms[p] = tuple(str(x) if isinstance(x, string_types) else x - for x in rule) + perms[p] = tuple(rule) return perms, perms in defaultrelperms or perms in defaulteperms diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/session.py --- a/cubicweb/server/session.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/session.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,16 +17,12 @@ # with CubicWeb. If not, see . """Repository users' and internal' sessions.""" -from __future__ import print_function - import functools import sys from uuid import uuid4 from contextlib import contextmanager from logging import getLogger -from six import text_type - from logilab.common.registry import objectify_predicate from cubicweb import QueryError, ProgrammingError, schema, server @@ -641,7 +637,7 @@ def transaction_uuid(self, set=True): uuid = self.transaction_data.get('tx_uuid') if set and uuid is None: - self.transaction_data['tx_uuid'] = uuid = text_type(uuid4().hex) + self.transaction_data['tx_uuid'] = uuid = uuid4().hex self.repo.system_source.start_undoable_transaction(self, uuid) return uuid diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/sources/__init__.py --- a/cubicweb/server/sources/__init__.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/sources/__init__.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,13 +17,9 @@ # with CubicWeb. If not, see . """cubicweb server sources support""" -from __future__ import print_function - from time import time from logging import getLogger -from six import text_type - from logilab.common import configuration from logilab.common.textutils import unormalize @@ -97,7 +93,7 @@ self.uri = source_config.pop('uri') # unormalize to avoid non-ascii characters in logger's name, this will cause decoding error # on logging - set_log_methods(self, getLogger('cubicweb.sources.' + unormalize(text_type(self.uri)))) + set_log_methods(self, getLogger('cubicweb.sources.' + unormalize(self.uri))) source_config.pop('type') self.config = self._check_config_dict( eid, source_config, raise_on_error=False) @@ -155,7 +151,7 @@ except Exception as ex: if not raise_on_error: continue - msg = text_type(ex) + msg = str(ex) raise ValidationError(eid, {role_name('config', 'subject'): msg}) processed[optname] = value # cw < 3.10 bw compat diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/sources/datafeed.py --- a/cubicweb/server/sources/datafeed.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/sources/datafeed.py Fri Apr 05 17:58:19 2019 +0200 @@ -24,11 +24,10 @@ from os.path import exists from datetime import datetime, timedelta from functools import partial - -from six.moves.urllib.parse import urlparse -from six.moves.urllib.request import Request, build_opener, HTTPCookieProcessor -from six.moves.urllib.error import HTTPError -from six.moves.http_cookiejar import CookieJar +from http.cookiejar import CookieJar +from urllib.parse import urlparse +from urllib.request import Request, build_opener, HTTPCookieProcessor +from urllib.error import HTTPError from pytz import utc from lxml import etree diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/sources/ldapfeed.py --- a/cubicweb/server/sources/ldapfeed.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/sources/ldapfeed.py Fri Apr 05 17:58:19 2019 +0200 @@ -21,8 +21,6 @@ from datetime import datetime -from six import PY2, string_types - import ldap3 from logilab.common.configuration import merge_options @@ -341,15 +339,13 @@ elif self.user_attrs.get(key) == 'modification_date': itemdict[key] = datetime.strptime(value[0], '%Y%m%d%H%M%SZ') else: - if PY2 and value and isinstance(value[0], str): - value = [unicode(val, 'utf-8', 'replace') for val in value] if len(value) == 1: itemdict[key] = value = value[0] else: itemdict[key] = value # we expect memberUid to be a list of user ids, make sure of it member = self.group_rev_attrs['member'] - if isinstance(itemdict.get(member), string_types): + if isinstance(itemdict.get(member), str): itemdict[member] = [itemdict[member]] return itemdict diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/sources/native.py --- a/cubicweb/server/sources/native.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/sources/native.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,21 +17,17 @@ # with CubicWeb. If not, see . """Adapters for native cubicweb sources.""" -from __future__ import print_function - from threading import Lock from datetime import datetime from contextlib import contextmanager from os.path import basename +import pickle import re import itertools import zipfile import logging import sys -from six import PY2, text_type, string_types -from six.moves import range, cPickle as pickle, zip - from logilab.common.decorators import cached, clear_cache from logilab.common.configuration import Method from logilab.common.shellutils import getlogin, ASK @@ -121,12 +117,11 @@ class _UndoException(Exception): """something went wrong during undoing""" - def __unicode__(self): + def __str__(self): """Called by the unicode builtin; should return a Unicode object Type of _UndoException message must be `unicode` by design in CubicWeb. """ - assert isinstance(self.args[0], text_type) return self.args[0] @@ -526,7 +521,7 @@ sql, qargs, cbs = self._rql_sqlgen.generate(union, args) self._cache[cachekey] = sql, qargs, cbs args = self.merge_args(args, qargs) - assert isinstance(sql, string_types), repr(sql) + assert isinstance(sql, str), repr(sql) cursor = cnx.system_sql(sql, args) results = self.process_result(cursor, cnx, cbs) assert dbg_results(results) @@ -581,7 +576,7 @@ self.doexec(cnx, sql, attrs) if cnx.ertype_supports_undo(entity.cw_etype): self._record_tx_action(cnx, 'tx_entity_actions', u'C', - etype=text_type(entity.cw_etype), eid=entity.eid) + etype=entity.cw_etype, eid=entity.eid) def update_entity(self, cnx, entity): """replace an entity in the source""" @@ -590,7 +585,7 @@ if cnx.ertype_supports_undo(entity.cw_etype): changes = self._save_attrs(cnx, entity, attrs) self._record_tx_action(cnx, 'tx_entity_actions', u'U', - etype=text_type(entity.cw_etype), eid=entity.eid, + etype=entity.cw_etype, eid=entity.eid, changes=self._binary(pickle.dumps(changes))) sql = self.sqlgen.update(SQL_PREFIX + entity.cw_etype, attrs, ['cw_eid']) @@ -605,7 +600,7 @@ if (r.final or r.inlined) and r not in VIRTUAL_RTYPES] changes = self._save_attrs(cnx, entity, attrs) self._record_tx_action(cnx, 'tx_entity_actions', u'D', - etype=text_type(entity.cw_etype), eid=entity.eid, + etype=entity.cw_etype, eid=entity.eid, changes=self._binary(pickle.dumps(changes))) attrs = {'cw_eid': entity.eid} sql = self.sqlgen.delete(SQL_PREFIX + entity.cw_etype, attrs) @@ -616,7 +611,7 @@ self._add_relations(cnx, rtype, [(subject, object)], inlined) if cnx.ertype_supports_undo(rtype): self._record_tx_action(cnx, 'tx_relation_actions', u'A', - eid_from=subject, rtype=text_type(rtype), eid_to=object) + eid_from=subject, rtype=rtype, eid_to=object) def add_relations(self, cnx, rtype, subj_obj_list, inlined=False): """add a relations to the source""" @@ -624,7 +619,7 @@ if cnx.ertype_supports_undo(rtype): for subject, object in subj_obj_list: self._record_tx_action(cnx, 'tx_relation_actions', u'A', - eid_from=subject, rtype=text_type(rtype), eid_to=object) + eid_from=subject, rtype=rtype, eid_to=object) def _add_relations(self, cnx, rtype, subj_obj_list, inlined=False): """add a relation to the source""" @@ -656,7 +651,7 @@ self._delete_relation(cnx, subject, rtype, object, rschema.inlined) if cnx.ertype_supports_undo(rtype): self._record_tx_action(cnx, 'tx_relation_actions', u'R', - eid_from=subject, rtype=text_type(rtype), eid_to=object) + eid_from=subject, rtype=rtype, eid_to=object) def _delete_relation(self, cnx, subject, rtype, object, inlined=False): """delete a relation from the source""" @@ -832,7 +827,7 @@ """add type and source info for an eid into the system table""" assert cnx.cnxset is not None # begin by inserting eid/type/source into the entities table - attrs = {'type': text_type(entity.cw_etype), 'eid': entity.eid} + attrs = {'type': entity.cw_etype, 'eid': entity.eid} self._handle_insert_entity_sql(cnx, self.sqlgen.insert('entities', attrs), attrs) # insert core relations: is, is_instance_of and cw_source @@ -907,7 +902,7 @@ # only, and with no eid specified assert actionfilters.get('action', 'C') in 'CUD' assert 'eid' not in actionfilters - tearestr['etype'] = text_type(val) + tearestr['etype'] = val elif key == 'eid': # eid filter may apply to 'eid' of tx_entity_actions or to # 'eid_from' OR 'eid_to' of tx_relation_actions @@ -918,10 +913,10 @@ trarestr['eid_to'] = val elif key == 'action': if val in 'CUD': - tearestr['txa_action'] = text_type(val) + tearestr['txa_action'] = val else: assert val in 'AR' - trarestr['txa_action'] = text_type(val) + trarestr['txa_action'] = val else: raise AssertionError('unknow filter %s' % key) assert trarestr or tearestr, "can't only filter on 'public'" @@ -955,11 +950,10 @@ def tx_info(self, cnx, txuuid): """See :class:`cubicweb.repoapi.Connection.transaction_info`""" - return tx.Transaction(cnx, txuuid, *self._tx_info(cnx, text_type(txuuid))) + return tx.Transaction(cnx, txuuid, *self._tx_info(cnx, txuuid)) def tx_actions(self, cnx, txuuid, public): """See :class:`cubicweb.repoapi.Connection.transaction_actions`""" - txuuid = text_type(txuuid) self._tx_info(cnx, txuuid) restr = {'tx_uuid': txuuid} if public: @@ -1092,8 +1086,6 @@ elif eschema.destination(rtype) in ('Bytes', 'Password'): changes[column] = self._binary(value) edited[rtype] = Binary(value) - elif PY2 and isinstance(value, str): - edited[rtype] = text_type(value, cnx.encoding, 'replace') else: edited[rtype] = value # This must only be done after init_entitiy_caches : defered in calling functions @@ -1133,14 +1125,14 @@ try: sentity, oentity, rdef = _undo_rel_info(cnx, subj, rtype, obj) except _UndoException as ex: - errors.append(text_type(ex)) + errors.append(str(ex)) else: for role, entity in (('subject', sentity), ('object', oentity)): try: _undo_check_relation_target(entity, rdef, role) except _UndoException as ex: - errors.append(text_type(ex)) + errors.append(str(ex)) continue if not errors: self.repo.hm.call_hooks('before_add_relation', cnx, @@ -1215,7 +1207,7 @@ try: sentity, oentity, rdef = _undo_rel_info(cnx, subj, rtype, obj) except _UndoException as ex: - errors.append(text_type(ex)) + errors.append(str(ex)) else: rschema = rdef.rtype if rschema.inlined: diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/sources/rql2sql.py --- a/cubicweb/server/sources/rql2sql.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/sources/rql2sql.py Fri Apr 05 17:58:19 2019 +0200 @@ -49,9 +49,6 @@ import threading -from six import PY2, text_type -from six.moves import range - from logilab.database import FunctionDescr, SQL_FUNCTIONS_REGISTRY from rql import BadRQLQuery, CoercionError @@ -1517,8 +1514,6 @@ return self.keyword_map[value]() if constant.type == 'Substitute': _id = value - if PY2 and isinstance(_id, text_type): - _id = _id.encode() else: _id = str(id(constant)).replace('-', '', 1) self._query_attrs[_id] = value diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/sources/storages.py --- a/cubicweb/server/sources/storages.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/sources/storages.py Fri Apr 05 17:58:19 2019 +0200 @@ -23,8 +23,6 @@ from contextlib import contextmanager import tempfile -from six import PY2, PY3, text_type, binary_type - from logilab.common import nullobject from yams.schema import role_name @@ -113,15 +111,8 @@ class BytesFileSystemStorage(Storage): """store Bytes attribute value on the file system""" def __init__(self, defaultdir, fsencoding=_marker, wmode=0o444): - if PY3: - if not isinstance(defaultdir, text_type): - raise TypeError('defaultdir must be a unicode object in python 3') - if fsencoding is not _marker: - raise ValueError('fsencoding is no longer supported in python 3') - else: - self.fsencoding = fsencoding or 'utf-8' - if isinstance(defaultdir, text_type): - defaultdir = defaultdir.encode(fsencoding) + if fsencoding is not _marker: + raise ValueError('fsencoding is no longer supported in python 3') self.default_directory = defaultdir # extra umask to use when creating file # 0444 as in "only allow read bit in permission" @@ -160,7 +151,7 @@ if binary is not None: fd, fpath = self.new_fs_path(entity, attr) # bytes storage used to store file's path - binary_obj = Binary(fpath if PY2 else fpath.encode('utf-8')) + binary_obj = Binary(fpath.encode('utf-8')) entity.cw_edited.edited_attribute(attr, binary_obj) self._writecontent(fd, binary) AddFileOp.get_instance(entity._cw).add_data(fpath) @@ -204,7 +195,7 @@ entity.cw_edited.edited_attribute(attr, None) else: # register the new location for the file. - binary_obj = Binary(fpath if PY2 else fpath.encode('utf-8')) + binary_obj = Binary(fpath.encode('utf-8')) entity.cw_edited.edited_attribute(attr, binary_obj) if oldpath is not None and oldpath != fpath: # Mark the old file as useless so the file will be removed at @@ -224,19 +215,17 @@ # available. Keeping the extension is useful for example in the case of # PIL processing that use filename extension to detect content-type, as # well as providing more understandable file names on the fs. - if PY2: - attr = attr.encode('ascii') basename = [str(entity.eid), attr] name = entity.cw_attr_metadata(attr, 'name') if name is not None: - basename.append(name.encode(self.fsencoding) if PY2 else name) + basename.append(name) fd, fspath = uniquify_path(self.default_directory, '_'.join(basename)) if fspath is None: msg = entity._cw._('failed to uniquify path (%s, %s)') % ( self.default_directory, '_'.join(basename)) raise ValidationError(entity.eid, {role_name(attr, 'subject'): msg}) - assert isinstance(fspath, str) # bytes on py2, unicode on py3 + assert isinstance(fspath, str) return fd, fspath def current_fs_path(self, entity, attr): @@ -251,11 +240,8 @@ if rawvalue is None: # no previous value return None fspath = sysource._process_value(rawvalue, cu.description[0], - binarywrap=binary_type) - if PY3: - fspath = fspath.decode('utf-8') - assert isinstance(fspath, str) # bytes on py2, unicode on py3 - return fspath + binarywrap=bytes) + return fspath.decode('utf-8') def migrate_entity(self, entity, attribute): """migrate an entity attribute to the storage""" @@ -274,7 +260,7 @@ class AddFileOp(hook.DataOperationMixIn, hook.Operation): def rollback_event(self): for filepath in self.get_data(): - assert isinstance(filepath, str) # bytes on py2, unicode on py3 + assert isinstance(filepath, str) try: unlink(filepath) except Exception as ex: @@ -283,7 +269,7 @@ class DeleteFileOp(hook.DataOperationMixIn, hook.Operation): def postcommit_event(self): for filepath in self.get_data(): - assert isinstance(filepath, str) # bytes on py2, unicode on py3 + assert isinstance(filepath, str) try: unlink(filepath) except Exception as ex: diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/sqlutils.py --- a/cubicweb/server/sqlutils.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/sqlutils.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,8 +17,6 @@ # with CubicWeb. If not, see . """SQL utilities functions and classes.""" -from __future__ import print_function - import os import sys import re @@ -27,9 +25,6 @@ from logging import getLogger from datetime import time, datetime, timedelta -from six import string_types, text_type -from six.moves import filter - from pytz import utc from logilab import database as db, common as lgc @@ -52,7 +47,7 @@ env = os.environ.copy() for key, value in (extra_env or {}).items(): env.setdefault(key, value) - if isinstance(cmd, string_types): + if isinstance(cmd, str): print(cmd) return subprocess.call(cmd, shell=True, env=env) else: @@ -81,7 +76,7 @@ else: execute = cursor_or_execute sqlstmts_as_string = False - if isinstance(sqlstmts, string_types): + if isinstance(sqlstmts, str): sqlstmts_as_string = True sqlstmts = sqlstmts.split(delimiter) if withpb: @@ -475,7 +470,7 @@ for row, rowdesc in zip(rset, rset.description): for cellindex, (value, vtype) in enumerate(zip(row, rowdesc)): if vtype in ('TZDatetime', 'Date', 'Datetime') \ - and isinstance(value, text_type): + and isinstance(value, str): found_date = True value = value.rsplit('.', 1)[0] try: @@ -484,7 +479,7 @@ row[cellindex] = strptime(value, '%Y-%m-%d') if vtype == 'TZDatetime': row[cellindex] = row[cellindex].replace(tzinfo=utc) - if vtype == 'Time' and isinstance(value, text_type): + if vtype == 'Time' and isinstance(value, str): found_date = True try: row[cellindex] = strptime(value, '%H:%M:%S') @@ -517,7 +512,7 @@ self.values.add(value) def finalize(self): - return ', '.join(text_type(v) for v in self.values) + return ', '.join(str(v) for v in self.values) cnx.create_aggregate("GROUP_CONCAT", 1, group_concat) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/ssplanner.py --- a/cubicweb/server/ssplanner.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/ssplanner.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,8 +17,6 @@ # with CubicWeb. If not, see . """plan execution of rql queries on a single source""" -from six import text_type - from rql.stmts import Union, Select from rql.nodes import Constant, Relation @@ -55,7 +53,7 @@ value = rhs.eval(plan.args) eschema = edef.entity.e_schema attrtype = eschema.subjrels[rtype].objects(eschema)[0] - if attrtype == 'Password' and isinstance(value, text_type): + if attrtype == 'Password' and isinstance(value, str): value = value.encode('UTF8') edef.edited_attribute(rtype, value) elif str(rhs) in to_build: diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/test/unittest_checkintegrity.py --- a/cubicweb/server/test/unittest_checkintegrity.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/test/unittest_checkintegrity.py Fri Apr 05 17:58:19 2019 +0200 @@ -16,15 +16,10 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . +from io import StringIO import sys import unittest -from six import PY2 -if PY2: - from StringIO import StringIO -else: - from io import StringIO - from cubicweb import devtools # noqa: E402 from cubicweb.devtools.testlib import CubicWebTC # noqa: E402 from cubicweb.server.checkintegrity import check, check_indexes, reindex_entities # noqa: E402 diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/test/unittest_ldapsource.py --- a/cubicweb/server/test/unittest_ldapsource.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/test/unittest_ldapsource.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ Those tests expect to have slapd, python-ldap3 and ldapscripts packages installed. """ -from __future__ import print_function - import os import sys import shutil @@ -31,9 +29,6 @@ import unittest from os.path import join -from six import string_types -from six.moves import range - from cubicweb import AuthenticationError, ValidationError from cubicweb.devtools.testlib import CubicWebTC from cubicweb.devtools.httptest import get_available_port @@ -180,7 +175,7 @@ """ modcmd = ['dn: %s' % dn, 'changetype: add'] for key, values in mods.items(): - if isinstance(values, string_types): + if isinstance(values, str): values = [values] for value in values: modcmd.append('%s: %s' % (key, value)) @@ -200,7 +195,7 @@ modcmd = ['dn: %s' % dn, 'changetype: modify'] for (kind, key), values in mods.items(): modcmd.append('%s: %s' % (kind, key)) - if isinstance(values, string_types): + if isinstance(values, str): values = [values] for value in values: modcmd.append('%s: %s' % (key, value)) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/test/unittest_migractions.py --- a/cubicweb/server/test/unittest_migractions.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/test/unittest_migractions.py Fri Apr 05 17:58:19 2019 +0200 @@ -22,6 +22,7 @@ import sys from datetime import date from contextlib import contextmanager +from tempfile import TemporaryDirectory from logilab.common import tempattr @@ -30,7 +31,7 @@ from cubicweb import (ConfigurationError, ValidationError, ExecutionError, Binary) from cubicweb.devtools import startpgcluster, stoppgcluster -from cubicweb.devtools.testlib import CubicWebTC, TemporaryDirectory +from cubicweb.devtools.testlib import CubicWebTC from cubicweb.schema import constraint_name_for from cubicweb.server.sqlutils import SQL_PREFIX from cubicweb.server.migractions import ServerMigrationHelper diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/test/unittest_postgres.py --- a/cubicweb/server/test/unittest_postgres.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/test/unittest_postgres.py Fri Apr 05 17:58:19 2019 +0200 @@ -19,8 +19,6 @@ from datetime import datetime from threading import Thread -from six.moves import range - import logilab.database as lgdb from cubicweb import ValidationError from cubicweb.devtools import PostgresApptestConfiguration, startpgcluster, stoppgcluster diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/test/unittest_querier.py --- a/cubicweb/server/test/unittest_querier.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/test/unittest_querier.py Fri Apr 05 17:58:19 2019 +0200 @@ -25,8 +25,6 @@ import pytz -from six import PY2, integer_types, binary_type, text_type - from rql import BadRQLQuery from rql.utils import register_function, FunctionDescr @@ -134,8 +132,8 @@ def assertRQLEqual(self, expected, got): from rql import parse - self.assertMultiLineEqual(text_type(parse(expected)), - text_type(parse(got))) + self.assertMultiLineEqual(str(parse(expected)), + str(parse(got))) def test_preprocess_security(self): with self.user_groups_session('users') as cnx: @@ -265,9 +263,6 @@ self.assertEqual(rset.description[0][0], 'Datetime') rset = self.qexecute('Any %(x)s', {'x': 1}) self.assertEqual(rset.description[0][0], 'Int') - if PY2: - rset = self.qexecute('Any %(x)s', {'x': long(1)}) - self.assertEqual(rset.description[0][0], 'Int') rset = self.qexecute('Any %(x)s', {'x': True}) self.assertEqual(rset.description[0][0], 'Boolean') rset = self.qexecute('Any %(x)s', {'x': 1.0}) @@ -327,7 +322,7 @@ def test_typed_eid(self): # should return an empty result set rset = self.qexecute('Any X WHERE X eid %(x)s', {'x': '1'}) - self.assertIsInstance(rset[0][0], integer_types) + self.assertIsInstance(rset[0][0], int) def test_bytes_storage(self): feid = self.qexecute('INSERT File X: X data_name "foo.pdf", ' @@ -903,14 +898,14 @@ rset = self.qexecute('Any X, "toto" ORDERBY X WHERE X is CWGroup') self.assertEqual(rset.rows, [list(x) for x in zip((2,3,4,5), ('toto','toto','toto','toto',))]) - self.assertIsInstance(rset[0][1], text_type) + self.assertIsInstance(rset[0][1], str) self.assertEqual(rset.description, list(zip(('CWGroup', 'CWGroup', 'CWGroup', 'CWGroup'), ('String', 'String', 'String', 'String',)))) rset = self.qexecute('Any X, %(value)s ORDERBY X WHERE X is CWGroup', {'value': 'toto'}) self.assertEqual(rset.rows, list(map(list, zip((2,3,4,5), ('toto','toto','toto','toto',))))) - self.assertIsInstance(rset[0][1], text_type) + self.assertIsInstance(rset[0][1], str) self.assertEqual(rset.description, list(zip(('CWGroup', 'CWGroup', 'CWGroup', 'CWGroup'), ('String', 'String', 'String', 'String',)))) @@ -1073,10 +1068,10 @@ def test_insert_4ter(self): peid = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0] seid = self.qexecute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s", - {'x': text_type(peid)})[0][0] + {'x': str(peid)})[0][0] self.assertEqual(len(self.qexecute('Any X, Y WHERE X travaille Y')), 1) self.qexecute("INSERT Personne X: X nom 'chouette', X travaille Y WHERE Y eid %(x)s", - {'x': text_type(seid)}) + {'x': str(seid)}) self.assertEqual(len(self.qexecute('Any X, Y WHERE X travaille Y')), 2) def test_insert_5(self): @@ -1282,7 +1277,7 @@ rset = self.qexecute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'") eid1, eid2 = rset[0][0], rset[0][1] self.qexecute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s", - {'x': text_type(eid1), 'y': text_type(eid2)}) + {'x': str(eid1), 'y': str(eid2)}) rset = self.qexecute('Any X, Y WHERE X travaille Y') self.assertEqual(len(rset.rows), 1) @@ -1332,7 +1327,7 @@ eid1, eid2 = rset[0][0], rset[0][1] rset = self.qexecute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s, " "NOT EXISTS(Z ecrit_par X)", - {'x': text_type(eid1), 'y': text_type(eid2)}) + {'x': str(eid1), 'y': str(eid2)}) self.assertEqual(tuplify(rset.rows), [(eid1, eid2)]) def test_update_query_error(self): @@ -1379,7 +1374,7 @@ cursor = cnx.cnxset.cu cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'" % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX)) - passwd = binary_type(cursor.fetchone()[0]) + passwd = bytes(cursor.fetchone()[0]) self.assertEqual(passwd, crypt_password('toto', passwd)) rset = self.qexecute("Any X WHERE X is CWUser, X login 'bob', X upassword %(pwd)s", {'pwd': Binary(passwd)}) @@ -1396,7 +1391,7 @@ cursor = cnx.cnxset.cu cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'" % (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX)) - passwd = binary_type(cursor.fetchone()[0]) + passwd = bytes(cursor.fetchone()[0]) self.assertEqual(passwd, crypt_password('tutu', passwd)) rset = cnx.execute("Any X WHERE X is CWUser, X login 'bob', X upassword %(pwd)s", {'pwd': Binary(passwd)}) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/test/unittest_repository.py --- a/cubicweb/server/test/unittest_repository.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/test/unittest_repository.py Fri Apr 05 17:58:19 2019 +0200 @@ -22,8 +22,6 @@ import logging import unittest -from six.moves import range - from yams.constraints import UniqueConstraint from yams import register_base_type, unregister_base_type diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/test/unittest_rql2sql.py --- a/cubicweb/server/test/unittest_rql2sql.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/test/unittest_rql2sql.py Fri Apr 05 17:58:19 2019 +0200 @@ -16,7 +16,6 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """unit tests for module cubicweb.server.sources.rql2sql""" -from __future__ import print_function import sys import unittest diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/test/unittest_security.py --- a/cubicweb/server/test/unittest_security.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/test/unittest_security.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,8 +17,6 @@ # with CubicWeb. If not, see . """functional tests for server'security""" -from six.moves import range - from logilab.common.testlib import unittest_main from cubicweb.devtools.testlib import CubicWebTC diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/test/unittest_storage.py --- a/cubicweb/server/test/unittest_storage.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/test/unittest_storage.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,8 +17,6 @@ # with CubicWeb. If not, see . """unit tests for module cubicweb.server.sources.storages""" -from six import PY2 - from logilab.common.testlib import unittest_main, tag, Tags from cubicweb.devtools.testlib import CubicWebTC @@ -79,7 +77,7 @@ def fspath(self, cnx, entity): fspath = cnx.execute('Any fspath(D) WHERE F eid %(f)s, F data D', {'f': entity.eid})[0][0].getvalue() - return fspath if PY2 else fspath.decode('utf-8') + return fspath.decode('utf-8') def test_bfss_wrong_fspath_usage(self): with self.admin_access.repo_cnx() as cnx: diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/test/unittest_undo.py --- a/cubicweb/server/test/unittest_undo.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/test/unittest_undo.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,8 +17,6 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -from six import text_type - from cubicweb import ValidationError from cubicweb.devtools.testlib import CubicWebTC from cubicweb.server.session import Connection @@ -254,7 +252,7 @@ "%s doesn't exist anymore." % g.eid]) with self.assertRaises(ValidationError) as cm: cnx.commit() - cm.exception.translate(text_type) + cm.exception.translate(str) self.assertEqual(cm.exception.entity, self.totoeid) self.assertEqual(cm.exception.errors, {'in_group-subject': u'at least one relation in_group is ' @@ -458,9 +456,9 @@ class UndoExceptionInUnicode(CubicWebTC): # problem occurs in string manipulation for python < 2.6 - def test___unicode__method(self): + def test___str__method(self): u = _UndoException(u"voilà") - self.assertIsInstance(text_type(u), text_type) + self.assertIsInstance(str(u), str) if __name__ == '__main__': diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/test/unittest_utils.py --- a/cubicweb/server/test/unittest_utils.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/test/unittest_utils.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,6 +17,8 @@ # with CubicWeb. If not, see . """Tests for cubicweb.server.utils module.""" +import sched + from cubicweb.devtools import testlib from cubicweb.server import utils @@ -40,7 +42,7 @@ self.assertEqual(utils.crypt_password('yyy', ''), '') def test_schedule_periodic_task(self): - scheduler = utils.scheduler() + scheduler = sched.scheduler() this = [] def fill_this(x): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/server/utils.py --- a/cubicweb/server/utils.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/server/utils.py Fri Apr 05 17:58:19 2019 +0200 @@ -16,19 +16,12 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """Some utilities for the CubicWeb server.""" -from __future__ import print_function - from functools import wraps -import sched -import sys import logging from threading import Thread from getpass import getpass -from six import PY2, text_type -from six.moves import input - from passlib.utils import handlers as uh, to_hash_str from passlib.context import CryptContext @@ -92,8 +85,6 @@ print(msg) while not user: user = input('login: ') - if PY2: - user = text_type(user, sys.stdin.encoding) passwd = getpass('%s: ' % passwdmsg) if confirm: while True: @@ -106,22 +97,6 @@ return user, passwd -if PY2: - import time # noqa - - class scheduler(sched.scheduler): - """Python2 version of sched.scheduler that matches Python3 API.""" - - def __init__(self, **kwargs): - kwargs.setdefault('timefunc', time.time) - kwargs.setdefault('delayfunc', time.sleep) - # sched.scheduler is an old-style class. - sched.scheduler.__init__(self, **kwargs) - -else: - scheduler = sched.scheduler - - def schedule_periodic_task(scheduler, interval, func, *args): """Enter a task with `func(*args)` as a periodic event in `scheduler` executing at `interval` seconds. Once executed, the task would re-schedule diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/skeleton/cubicweb_CUBENAME/__pkginfo__.py.tmpl --- a/cubicweb/skeleton/cubicweb_CUBENAME/__pkginfo__.py.tmpl Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/skeleton/cubicweb_CUBENAME/__pkginfo__.py.tmpl Fri Apr 05 17:58:19 2019 +0200 @@ -20,6 +20,6 @@ classifiers = [ 'Environment :: Web Environment', 'Framework :: CubicWeb', - 'Programming Language :: Python', + 'Programming Language :: Python :: 3', 'Programming Language :: JavaScript', ] diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/sobjects/ldapparser.py --- a/cubicweb/sobjects/ldapparser.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/sobjects/ldapparser.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ unlike ldapuser source, this source is copy based and will import ldap content (beside passwords for authentication) into the system source. """ -from six.moves import map, filter - from logilab.common.decorators import cached, cachedproperty from logilab.common.shellutils import generate_password diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/sobjects/notification.py --- a/cubicweb/sobjects/notification.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/sobjects/notification.py Fri Apr 05 17:58:19 2019 +0200 @@ -22,8 +22,6 @@ from itertools import repeat -from six import text_type - from logilab.common.textutils import normalize_text from logilab.common.registry import yes @@ -179,7 +177,7 @@ def context(self, **kwargs): entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0) for key, val in kwargs.items(): - if val and isinstance(val, text_type) and val.strip(): + if val and isinstance(val, str) and val.strip(): kwargs[key] = self._cw._(val) kwargs.update({'user': self.user_data['login'], 'eid': entity.eid, @@ -252,7 +250,7 @@ def format_value(value): - if isinstance(value, text_type): + if isinstance(value, str): return u'"%s"' % value return value diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/sobjects/services.py --- a/cubicweb/sobjects/services.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/sobjects/services.py Fri Apr 05 17:58:19 2019 +0200 @@ -19,8 +19,6 @@ import threading -from six import text_type - from cubicweb.server import Service from cubicweb.predicates import match_user_groups, match_kwargs @@ -111,7 +109,7 @@ def call(self, login, password, email=None, groups=None, **cwuserkwargs): cnx = self._cw - if isinstance(password, text_type): + if isinstance(password, str): # password should *always* be utf8 encoded password = password.encode('UTF8') cwuserkwargs['login'] = login diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/test/unittest_binary.py --- a/cubicweb/test/unittest_binary.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/test/unittest_binary.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ import os.path as osp import pickle -from six import PY2 - from logilab.common.shellutils import tempdir from cubicweb import Binary @@ -32,10 +30,7 @@ Binary() Binary(b'toto') Binary(bytearray(b'toto')) - if PY2: - Binary(buffer('toto')) # noqa: F821 - else: - Binary(memoryview(b'toto')) + Binary(memoryview(b'toto')) with self.assertRaises((AssertionError, TypeError)): # TypeError is raised by BytesIO if python runs with -O Binary(u'toto') @@ -44,10 +39,7 @@ b = Binary() b.write(b'toto') b.write(bytearray(b'toto')) - if PY2: - b.write(buffer('toto')) # noqa: F821 - else: - b.write(memoryview(b'toto')) + b.write(memoryview(b'toto')) with self.assertRaises((AssertionError, TypeError)): # TypeError is raised by BytesIO if python runs with -O b.write(u'toto') diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/test/unittest_cwconfig.py --- a/cubicweb/test/unittest_cwconfig.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/test/unittest_cwconfig.py Fri Apr 05 17:58:19 2019 +0200 @@ -18,22 +18,21 @@ """cubicweb.cwconfig unit tests""" import contextlib -import compileall import functools import sys import os import pkgutil from os.path import dirname, join from pkg_resources import EntryPoint, Distribution +from tempfile import TemporaryDirectory import unittest from mock import patch -from six import PY3 from logilab.common.modutils import cleanup_sys_modules from cubicweb.devtools import ApptestConfiguration -from cubicweb.devtools.testlib import BaseTestCase, TemporaryDirectory +from cubicweb.devtools.testlib import BaseTestCase from cubicweb.cwconfig import ( CubicWebConfiguration, _expand_modname) @@ -268,13 +267,6 @@ join(tempdir, 'b', 'c.py'), join(tempdir, 'b', 'd', '__init__.py'), ): - if not PY3: - # ensure pyc file exists. - # Doesn't required for PY3 since it create __pycache__ - # directory and will not import if source file doesn't - # exists. - compileall.compile_file(source, force=True) - self.assertTrue(os.path.exists(source + 'c')) # remove source file os.remove(source) self.assertEqual(list(_expand_modname('lib.c')), []) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/test/unittest_cwctl.py --- a/cubicweb/test/unittest_cwctl.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/test/unittest_cwctl.py Fri Apr 05 17:58:19 2019 +0200 @@ -18,11 +18,9 @@ import sys import os from os.path import join -from io import StringIO, BytesIO +from io import StringIO import unittest -from six import PY2 - from mock import patch from cubicweb.cwctl import ListCommand @@ -38,7 +36,7 @@ tearDownClass = unittest_cwconfig.CubicWebConfigurationTC.tearDownClass def setUp(self): - self.stream = BytesIO() if PY2 else StringIO() + self.stream = StringIO() sys.stdout = self.stream def tearDown(self): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/test/unittest_entity.py --- a/cubicweb/test/unittest_entity.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/test/unittest_entity.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ from datetime import datetime -from six import text_type - from logilab.common import tempattr from logilab.common.decorators import clear_cache @@ -800,11 +798,11 @@ # ambiguity test person2 = req.create_entity('Personne', prenom=u'remi', nom=u'doe') person.cw_clear_all_caches() - self.assertEqual(person.rest_path(), text_type(person.eid)) - self.assertEqual(person2.rest_path(), text_type(person2.eid)) + self.assertEqual(person.rest_path(), str(person.eid)) + self.assertEqual(person2.rest_path(), str(person2.eid)) # unique attr with None value (nom in this case) friend = req.create_entity('Ami', prenom=u'bob') - self.assertEqual(friend.rest_path(), text_type(friend.eid)) + self.assertEqual(friend.rest_path(), str(friend.eid)) # 'ref' below is created without the unique but not required # attribute, make sur that the unique _and_ required 'ean' is used # as the rest attribute diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/test/unittest_predicates.py --- a/cubicweb/test/unittest_predicates.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/test/unittest_predicates.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ from operator import eq, lt, le, gt from contextlib import contextmanager -from six.moves import range - from logilab.common.testlib import TestCase, unittest_main from logilab.common.decorators import clear_cache diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/test/unittest_rqlrewrite.py --- a/cubicweb/test/unittest_rqlrewrite.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/test/unittest_rqlrewrite.py Fri Apr 05 17:58:19 2019 +0200 @@ -16,8 +16,6 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -from six import string_types - from logilab.common.testlib import mock_object from logilab.common.decorators import monkeypatch from yams import BadSchemaDefinition @@ -88,7 +86,7 @@ snippet_varmap[snippet].update(varmap) continue snippet_varmap[snippet] = varmap - if isinstance(snippet, string_types): + if isinstance(snippet, str): snippet = mock_object(snippet_rqlst=parse(u'Any X WHERE ' + snippet).children[0], expression=u'Any X WHERE ' + snippet) rqlexprs.append(snippet) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/test/unittest_rset.py --- a/cubicweb/test/unittest_rset.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/test/unittest_rset.py Fri Apr 05 17:58:19 2019 +0200 @@ -18,9 +18,8 @@ # with CubicWeb. If not, see . """unit tests for module cubicweb.rset""" -from six import string_types -from six.moves import cPickle as pickle -from six.moves.urllib.parse import urlsplit +import pickle +from urllib.parse import urlsplit from rql import parse @@ -655,17 +654,17 @@ def test_str(self): with self.admin_access.web_request() as req: rset = req.execute('(Any X,N WHERE X is CWGroup, X name N)') - self.assertIsInstance(str(rset), string_types) + self.assertIsInstance(str(rset), str) self.assertEqual(len(str(rset).splitlines()), 1) def test_repr(self): with self.admin_access.web_request() as req: rset = req.execute('(Any X,N WHERE X is CWGroup, X name N)') - self.assertIsInstance(repr(rset), string_types) + self.assertIsInstance(repr(rset), str) self.assertTrue(len(repr(rset).splitlines()) > 1) rset = req.execute('(Any X WHERE X is CWGroup, X name "managers")') - self.assertIsInstance(str(rset), string_types) + self.assertIsInstance(str(rset), str) self.assertEqual(len(str(rset).splitlines()), 1) def test_slice(self): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/test/unittest_uilib.py --- a/cubicweb/test/unittest_uilib.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/test/unittest_uilib.py Fri Apr 05 17:58:19 2019 +0200 @@ -23,11 +23,7 @@ import doctest import pkg_resources - -try: - from unittest import skipIf -except ImportError: - from unittest2 import skipIf +from unittest import skipIf from logilab.common.testlib import TestCase, unittest_main diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/test/unittest_utils.py --- a/cubicweb/test/unittest_utils.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/test/unittest_utils.py Fri Apr 05 17:58:19 2019 +0200 @@ -22,13 +22,7 @@ import decimal import doctest import re -try: - from unittest2 import TestCase -except ImportError: # Python3 - from unittest import TestCase - -from six import PY2 -from six.moves import range +from unittest import TestCase from cubicweb import Binary, Unauthorized from cubicweb.devtools.testlib import CubicWebTC @@ -419,9 +413,6 @@ def test_str(self): self._test(str) - if PY2: - def test_unicode(self): - self._test(unicode) def load_tests(loader, tests, ignore): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/toolsutils.py --- a/cubicweb/toolsutils.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/toolsutils.py Fri Apr 05 17:58:19 2019 +0200 @@ -16,8 +16,6 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """some utilities for cubicweb command line tools""" -from __future__ import print_function - # XXX move most of this in logilab.common (shellutils ?) @@ -39,8 +37,6 @@ def symlink(*args): raise NotImplementedError -from six import add_metaclass - from logilab.common.clcommands import Command as BaseCommand from logilab.common.shellutils import ASK @@ -239,8 +235,7 @@ return cls -@add_metaclass(metacmdhandler) -class CommandHandler(object): +class CommandHandler(object, metaclass=metacmdhandler): """configuration specific helper for cubicweb-ctl commands""" def __init__(self, config): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/uilib.py --- a/cubicweb/uilib.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/uilib.py Fri Apr 05 17:58:19 2019 +0200 @@ -28,8 +28,6 @@ import re from io import StringIO -from six import PY2, PY3, text_type, binary_type, string_types, integer_types - from logilab.mtconverter import xml_escape, html_unescape from logilab.common.date import ustrftime @@ -64,7 +62,7 @@ return value def print_int(value, req, props, displaytime=True): - return text_type(value) + return str(value) def print_date(value, req, props, displaytime=True): return ustrftime(value, req.property_value('ui.date-format')) @@ -94,7 +92,7 @@ _('%d seconds') def print_timedelta(value, req, props, displaytime=True): - if isinstance(value, integer_types): + if isinstance(value, int): # `date - date`, unlike `datetime - datetime` gives an int # (number of days), not a timedelta # XXX should rql be fixed to return Int instead of Interval in @@ -124,7 +122,7 @@ return req._('no') def print_float(value, req, props, displaytime=True): - return text_type(req.property_value('ui.float-format') % value) # XXX cast needed ? + return str(req.property_value('ui.float-format') % value) # XXX cast needed ? PRINTERS = { 'Bytes': print_bytes, @@ -332,11 +330,10 @@ def __init__(self, id, parent=None): self.id = id self.parent = parent - def __unicode__(self): + def __str__(self): if self.parent: return u'%s.%s' % (self.parent, self.id) - return text_type(self.id) - __str__ = __unicode__ if PY3 else lambda self: self.__unicode__().encode('utf-8') + return str(self.id) def __getattr__(self, attr): return _JSId(attr, self) def __call__(self, *args): @@ -347,14 +344,13 @@ assert isinstance(args, tuple) self.args = args self.parent = parent - def __unicode__(self): + def __str__(self): args = [] for arg in self.args: args.append(js_dumps(arg)) if self.parent: return u'%s(%s)' % (self.parent, ','.join(args)) return ','.join(args) - __str__ = __unicode__ if PY3 else lambda self: self.__unicode__().encode('utf-8') class _JS(object): def __getattr__(self, attr): @@ -387,7 +383,7 @@ 'img', 'area', 'input', 'col')) def sgml_attributes(attrs): - return u' '.join(u'%s="%s"' % (attr, xml_escape(text_type(value))) + return u' '.join(u'%s="%s"' % (attr, xml_escape(str(value))) for attr, value in sorted(attrs.items()) if value is not None) @@ -405,7 +401,7 @@ value += u' ' + sgml_attributes(attrs) if content: if escapecontent: - content = xml_escape(text_type(content)) + content = xml_escape(str(content)) value += u'>%s' % (content, tag) else: if tag in HTML4_EMPTY_TAGS: @@ -434,7 +430,7 @@ stream = StringIO() #UStringIO() don't want unicode assertion formater.format(layout, stream) res = stream.getvalue() - if isinstance(res, binary_type): + if isinstance(res, bytes): res = res.decode('UTF8') return res @@ -443,16 +439,7 @@ import traceback def exc_message(ex, encoding): - if PY3: - excmsg = str(ex) - else: - try: - excmsg = unicode(ex) - except Exception: - try: - excmsg = unicode(str(ex), encoding, 'replace') - except Exception: - excmsg = unicode(repr(ex), encoding, 'replace') + excmsg = str(ex) exctype = ex.__class__.__name__ return u'%s: %s' % (exctype, excmsg) @@ -464,8 +451,6 @@ res.append(u'\tFile %s, line %s, function %s' % tuple(stackentry[:3])) if stackentry[3]: data = xml_escape(stackentry[3]) - if PY2: - data = data.decode('utf-8', 'replace') res.append(u'\t %s' % data) res.append(u'\n') try: @@ -501,8 +486,6 @@ xml_escape(stackentry[0]), stackentry[1], xml_escape(stackentry[2]))) if stackentry[3]: string = xml_escape(stackentry[3]) - if PY2: - string = string.decode('utf-8', 'replace') strings.append(u'  %s
\n' % (string)) # add locals info for each entry try: @@ -545,16 +528,8 @@ self.wfunc(data) def writerow(self, row): - if PY3: - self.writer.writerow(row) - return - csvrow = [] - for elt in row: - if isinstance(elt, text_type): - csvrow.append(elt.encode(self.encoding)) - else: - csvrow.append(str(elt)) - self.writer.writerow(csvrow) + self.writer.writerow(row) + return def writerows(self, rows): for row in rows: @@ -570,7 +545,7 @@ def __call__(self, function): def newfunc(*args, **kwargs): ret = function(*args, **kwargs) - if isinstance(ret, string_types): + if isinstance(ret, str): return ret[:self.maxsize] return ret return newfunc @@ -579,6 +554,6 @@ def htmlescape(function): def newfunc(*args, **kwargs): ret = function(*args, **kwargs) - assert isinstance(ret, string_types) + assert isinstance(ret, str) return xml_escape(ret) return newfunc diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/utils.py --- a/cubicweb/utils.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/utils.py Fri Apr 05 17:58:19 2019 +0200 @@ -25,21 +25,13 @@ import random import re import json - -from six import PY3 - from operator import itemgetter -if PY3: - from inspect import getfullargspec as getargspec -else: - from inspect import getargspec +from inspect import getfullargspec as getargspec from itertools import repeat from uuid import uuid4 from threading import Lock from logging import getLogger -from six import text_type - from logilab.mtconverter import xml_escape from logilab.common.date import ustrftime @@ -106,7 +98,7 @@ """ def __init__(self, w, tag, closetag=None): self.written = False - self.tag = text_type(tag) + self.tag = tag self.closetag = closetag self.w = w @@ -122,7 +114,7 @@ def __exit__(self, exctype, value, traceback): if self.written is True: if self.closetag: - self.w(text_type(self.closetag)) + self.w(self.closetag) else: self.w(self.tag.replace('<', '. """exceptions used in the core of the CubicWeb web application""" - - -from six.moves import http_client +import http.client as http_client from cubicweb._exceptions import * from cubicweb.utils import json_dumps diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/application.py --- a/cubicweb/web/application.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/application.py Fri Apr 05 17:58:19 2019 +0200 @@ -19,14 +19,12 @@ import contextlib +import http.client as http_client import json import sys from time import clock, time from contextlib import contextmanager -from six import text_type, binary_type -from six.moves import http_client - from rql import BadRQLQuery from cubicweb import set_log_methods @@ -316,7 +314,7 @@ # XXX ensure we don't actually serve content if not content: content = self.need_login_content(req) - assert isinstance(content, binary_type) + assert isinstance(content, bytes) return content def core_handle(self, req): @@ -481,7 +479,7 @@ if req.status_out < 400: # don't overwrite it if it's already set req.status_out = status - json_dumper = getattr(ex, 'dumps', lambda: json.dumps({'reason': text_type(ex)})) + json_dumper = getattr(ex, 'dumps', lambda: json.dumps({'reason': str(ex)})) return json_dumper().encode('utf-8') # special case handling diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/box.py --- a/cubicweb/web/box.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/box.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ from cubicweb import _ -from six import add_metaclass - from logilab.mtconverter import xml_escape from logilab.common.deprecation import class_deprecated @@ -58,8 +56,7 @@ # old box system, deprecated ################################################### -@add_metaclass(class_deprecated) -class BoxTemplate(View): +class BoxTemplate(View, metaclass=class_deprecated): """base template for boxes, usually a (contextual) list of possible actions. Various classes attributes may be used to control the box rendering. diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/captcha.py --- a/cubicweb/web/captcha.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/captcha.py Fri Apr 05 17:58:19 2019 +0200 @@ -24,8 +24,6 @@ from random import randint, choice from io import BytesIO -from six.moves import range - from PIL import Image, ImageFont, ImageDraw, ImageFilter diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/component.py --- a/cubicweb/web/component.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/component.py Fri Apr 05 17:58:19 2019 +0200 @@ -24,8 +24,6 @@ from warnings import warn -from six import PY3, add_metaclass, text_type - from logilab.common.deprecation import class_deprecated, class_renamed, deprecated from logilab.mtconverter import xml_escape @@ -239,12 +237,9 @@ self.label = label self.attrs = attrs - def __unicode__(self): + def __str__(self): return tags.a(self.label, href=self.href, **self.attrs) - if PY3: - __str__ = __unicode__ - def render(self, w): w(tags.a(self.label, href=self.href, **self.attrs)) @@ -455,7 +450,7 @@ @property def domid(self): - return domid(self.__regid__) + text_type(self.entity.eid) + return domid(self.__regid__) + str(self.entity.eid) def lazy_view_holder(self, w, entity, oid, registry='views'): """add a holder and return a URL that may be used to replace this @@ -528,7 +523,7 @@ args['subject'], args['object']) return u'[%s] %s' % ( - xml_escape(text_type(jscall)), label, etarget.view('incontext')) + xml_escape(str(jscall)), label, etarget.view('incontext')) def related_boxitems(self, entity): return [self.box_item(entity, etarget, 'delete_relation', u'-') @@ -545,7 +540,7 @@ """returns the list of unrelated entities, using the entity's appropriate vocabulary function """ - skip = set(text_type(e.eid) for e in entity.related(self.rtype, role(self), + skip = set(str(e.eid) for e in entity.related(self.rtype, role(self), entities=True)) skip.add(None) skip.add(INTERNAL_FIELD_VALUE) @@ -663,7 +658,7 @@ if maydel: if not js_css_added: js_css_added = self.add_js_css() - jscall = text_type(js.ajaxBoxRemoveLinkedEntity( + jscall = str(js.ajaxBoxRemoveLinkedEntity( self.__regid__, entity.eid, rentity.eid, self.fname_remove, self.removed_msg and _(self.removed_msg))) @@ -678,7 +673,7 @@ if mayadd: multiple = self.rdef.role_cardinality(self.role) in '*+' w(u'
') - jscall = text_type(js.ajaxBoxShowSelector( + jscall = str(js.ajaxBoxShowSelector( self.__regid__, entity.eid, self.fname_vocabulary, self.fname_validate, self.added_msg and _(self.added_msg), _(stdmsgs.BUTTON_OK[0]), _(stdmsgs.BUTTON_CANCEL[0]), @@ -707,8 +702,7 @@ # old contextual components, deprecated ######################################## -@add_metaclass(class_deprecated) -class EntityVComponent(Component): +class EntityVComponent(Component, metaclass=class_deprecated): """abstract base class for additinal components displayed in content headers and footer according to: diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/controller.py --- a/cubicweb/web/controller.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/controller.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,10 +17,6 @@ # with CubicWeb. If not, see . """abstract controller classe for CubicWeb web client""" - - -from six import PY2 - from logilab.mtconverter import xml_escape from logilab.common.registry import yes @@ -88,8 +84,6 @@ rql = req.form.get('rql') if rql: req.ensure_ro_rql(rql) - if PY2 and not isinstance(rql, unicode): - rql = unicode(rql, req.encoding) pp = req.vreg['components'].select_or_none('magicsearch', req) if pp is not None: return pp.process_query(rql) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/cors.py --- a/cubicweb/web/cors.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/cors.py Fri Apr 05 17:58:19 2019 +0200 @@ -29,7 +29,7 @@ """ -from six.moves.urllib.parse import urlsplit +from urllib.parse import urlsplit from cubicweb.web import LOGGER info = LOGGER.info diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/facet.py --- a/cubicweb/web/facet.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/facet.py Fri Apr 05 17:58:19 2019 +0200 @@ -56,8 +56,6 @@ from copy import deepcopy from datetime import datetime, timedelta -from six import text_type, string_types - from logilab.mtconverter import xml_escape from logilab.common.graph import has_path from logilab.common.decorators import cached, cachedproperty @@ -645,7 +643,7 @@ insert_attr_select_relation( select, self.filtered_variable, self.rtype, self.role, self.target_attr, select_target_entity=False) - values = [text_type(x) for x, in self.rqlexec(select.as_string())] + values = [str(x) for x, in self.rqlexec(select.as_string())] except Exception: self.exception('while computing values for %s', self) return [] @@ -696,7 +694,7 @@ if self.i18nable: tr = self._cw._ else: - tr = text_type + tr = str if self.rql_sort: values = [(tr(label), eid) for eid, label in rset] else: @@ -720,7 +718,7 @@ # XXX handle rel is None case in RQLPathFacet? if self.restr_attr != 'eid': self.select.set_distinct(True) - if isinstance(value, string_types): + if isinstance(value, str): # only one value selected if value: self.select.add_constant_restriction( @@ -884,7 +882,7 @@ if self.i18nable: tr = self._cw._ else: - tr = text_type + tr = str if self.rql_sort: return [(tr(value), value) for value, in rset] values = [(tr(value), value) for value, in rset] @@ -1037,7 +1035,7 @@ assert self.path and isinstance(self.path, (list, tuple)), \ 'path should be a list of 3-uples, not %s' % self.path for part in self.path: - if isinstance(part, string_types): + if isinstance(part, str): part = part.split() assert len(part) == 3, \ 'path should be a list of 3-uples, not %s' % part @@ -1090,7 +1088,7 @@ cleanup_select(select, self.filtered_variable) varmap, restrvar = self.add_path_to_select(skiplabel=True) select.append_selected(nodes.VariableRef(restrvar)) - values = [text_type(x) for x, in self.rqlexec(select.as_string())] + values = [str(x) for x, in self.rqlexec(select.as_string())] except Exception: self.exception('while computing values for %s', self) return [] @@ -1113,7 +1111,7 @@ varmap = {'X': self.filtered_variable} actual_filter_variable = None for part in self.path: - if isinstance(part, string_types): + if isinstance(part, str): part = part.split() subject, rtype, object = part if skiplabel and object == self.label_variable: @@ -1217,7 +1215,7 @@ rset = self._range_rset() if rset: minv, maxv = rset[0] - return [(text_type(minv), minv), (text_type(maxv), maxv)] + return [(str(minv), minv), (str(maxv), maxv)] return [] def possible_values(self): @@ -1236,7 +1234,7 @@ def formatvalue(self, value): """format `value` before in order to insert it in the RQL query""" - return text_type(value) + return str(value) def infvalue(self, min=False): if min: @@ -1337,7 +1335,7 @@ # *list* (see rqlexec implementation) if rset: minv, maxv = rset[0] - return [(text_type(minv), minv), (text_type(maxv), maxv)] + return [(str(minv), minv), (str(maxv), maxv)] return [] @@ -1356,7 +1354,7 @@ skiplabel=True, skipattrfilter=True) restrel = None for part in self.path: - if isinstance(part, string_types): + if isinstance(part, str): part = part.split() subject, rtype, object = part if object == self.filter_variable: @@ -1480,7 +1478,7 @@ if not val or val & mask]) def possible_values(self): - return [text_type(val) for label, val in self.vocabulary()] + return [str(val) for label, val in self.vocabulary()] ## html widets ################################################################ @@ -1559,7 +1557,7 @@ if selected: cssclass += ' facetValueSelected' w(u'
\n' - % (cssclass, xml_escape(text_type(value)))) + % (cssclass, xml_escape(str(value)))) # If it is overflowed one must add padding to compensate for the vertical # scrollbar; given current css values, 4 blanks work perfectly ... padding = u' ' * self.scrollbar_padding_factor if overflow else u'' @@ -1718,7 +1716,7 @@ imgsrc = self._cw.data_url(self.unselected_img) imgalt = self._cw._('not selected') w(u'
\n' - % (cssclass, xml_escape(text_type(self.value)))) + % (cssclass, xml_escape(str(self.value)))) w(u'
') w(u'%s ' % (imgsrc, imgalt)) w(u'' diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/form.py --- a/cubicweb/web/form.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/form.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,9 +17,6 @@ # with CubicWeb. If not, see . """abstract form classes for CubicWeb web client""" - -from six import add_metaclass - from logilab.common.decorators import iclassmethod from cubicweb.appobject import AppObject @@ -73,8 +70,7 @@ found """ -@add_metaclass(metafieldsform) -class Form(AppObject): +class Form(AppObject, metaclass=metafieldsform): __registry__ = 'forms' parent_form = None diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/formfields.py --- a/cubicweb/web/formfields.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/formfields.py Fri Apr 05 17:58:19 2019 +0200 @@ -68,8 +68,6 @@ import pytz -from six import PY2, text_type, string_types - from logilab.mtconverter import xml_escape from logilab.common import nullobject from logilab.common.date import ustrftime @@ -236,15 +234,9 @@ l.append('@%#x' % id(self)) return u'%s>' % ' '.join(l) - def __unicode__(self): + def __str__(self): return self.as_string(False) - if PY2: - def __str__(self): - return self.as_string(False).encode('UTF8') - else: - __str__ = __unicode__ - def __repr__(self): return self.as_string(True) @@ -290,7 +282,7 @@ return u'' if value is True: return u'1' - return text_type(value) + return str(value) def get_widget(self, form): """return the widget instance associated to this field""" @@ -825,7 +817,7 @@ def _process_form_value(self, form): value = form._cw.form.get(self.input_name(form)) - if isinstance(value, text_type): + if isinstance(value, str): # file modified using a text widget return Binary(value.encode(self.encoding(form))) return super(EditableFileField, self)._process_form_value(form) @@ -852,7 +844,7 @@ self.widget.attrs.setdefault('size', self.default_text_input_size) def _ensure_correctly_typed(self, form, value): - if isinstance(value, string_types): + if isinstance(value, str): value = value.strip() if not value: return None @@ -934,7 +926,7 @@ return self.format_single_value(req, 1.234) def _ensure_correctly_typed(self, form, value): - if isinstance(value, string_types): + if isinstance(value, str): value = value.strip() if not value: return None @@ -955,8 +947,7 @@ def format_single_value(self, req, value): if value: - value = format_time(value.days * 24 * 3600 + value.seconds) - return text_type(value) + return format_time(value.days * 24 * 3600 + value.seconds) return u'' def example_format(self, req): @@ -966,7 +957,7 @@ return u'20s, 10min, 24h, 4d' def _ensure_correctly_typed(self, form, value): - if isinstance(value, string_types): + if isinstance(value, str): value = value.strip() if not value: return None @@ -996,14 +987,14 @@ return self.format_single_value(req, datetime.now()) def _ensure_correctly_typed(self, form, value): - if isinstance(value, string_types): + if isinstance(value, str): value = value.strip() if not value: return None try: value = form._cw.parse_datetime(value, self.etype) except ValueError as ex: - raise ProcessFormError(text_type(ex)) + raise ProcessFormError(str(ex)) return value @@ -1107,7 +1098,7 @@ linkedto = form.linked_to.get((self.name, self.role)) if linkedto: buildent = form._cw.entity_from_eid - return [(buildent(eid).view('combobox'), text_type(eid)) + return [(buildent(eid).view('combobox'), str(eid)) for eid in linkedto] return [] @@ -1119,7 +1110,7 @@ # vocabulary doesn't include current values, add them if form.edited_entity.has_eid(): rset = form.edited_entity.related(self.name, self.role) - vocab += [(e.view('combobox'), text_type(e.eid)) + vocab += [(e.view('combobox'), str(e.eid)) for e in rset.entities()] return vocab @@ -1153,11 +1144,11 @@ if entity.eid in done: continue done.add(entity.eid) - res.append((entity.view('combobox'), text_type(entity.eid))) + res.append((entity.view('combobox'), str(entity.eid))) return res def format_single_value(self, req, value): - return text_type(value) + return str(value) def process_form_value(self, form): """process posted form and return correctly typed value""" diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/formwidgets.py --- a/cubicweb/web/formwidgets.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/formwidgets.py Fri Apr 05 17:58:19 2019 +0200 @@ -98,8 +98,6 @@ from functools import reduce from datetime import date -from six import text_type, string_types - from logilab.mtconverter import xml_escape from logilab.common.date import todatetime @@ -272,7 +270,7 @@ """ posted = form._cw.form val = posted.get(field.input_name(form, self.suffix)) - if isinstance(val, string_types): + if isinstance(val, str): val = val.strip() return val @@ -463,7 +461,7 @@ options.append(u'') if 'size' not in attrs: if self._multiple: - size = text_type(min(self.default_size, len(vocab) or 1)) + size = str(min(self.default_size, len(vocab) or 1)) else: size = u'1' attrs['size'] = size @@ -727,7 +725,7 @@ else: value = self.value attrs = self.attributes(form, field) - attrs.setdefault('size', text_type(self.default_size)) + attrs.setdefault('size', str(self.default_size)) return tags.input(name=field.input_name(form, self.suffix), value=value, type='text', **attrs) @@ -801,7 +799,7 @@ try: date = todatetime(req.parse_datetime(datestr, 'Date')) except ValueError as exc: - raise ProcessFormError(text_type(exc)) + raise ProcessFormError(str(exc)) timestr = req.form.get(field.input_name(form, 'time')) if timestr: timestr = timestr.strip() @@ -810,7 +808,7 @@ try: time = req.parse_datetime(timestr, 'Time') except ValueError as exc: - raise ProcessFormError(text_type(exc)) + raise ProcessFormError(str(exc)) return date.replace(hour=time.hour, minute=time.minute, second=time.second) @@ -1014,12 +1012,12 @@ req = form._cw values = {} path = req.form.get(field.input_name(form, 'path')) - if isinstance(path, string_types): + if isinstance(path, str): path = path.strip() if path is None: path = u'' fqs = req.form.get(field.input_name(form, 'fqs')) - if isinstance(fqs, string_types): + if isinstance(fqs, str): fqs = fqs.strip() or None if fqs: for i, line in enumerate(fqs.split('\n')): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/htmlwidgets.py --- a/cubicweb/web/htmlwidgets.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/htmlwidgets.py Fri Apr 05 17:58:19 2019 +0200 @@ -24,9 +24,6 @@ import random from math import floor -from six import add_metaclass -from six.moves import range - from logilab.mtconverter import xml_escape from logilab.common.deprecation import class_deprecated @@ -118,8 +115,7 @@ self.w(u'
') -@add_metaclass(class_deprecated) -class SideBoxWidget(BoxWidget): +class SideBoxWidget(BoxWidget, metaclass=class_deprecated): """default CubicWeb's sidebox widget""" __deprecation_warning__ = '[3.10] class %(cls)s is deprecated' @@ -210,8 +206,7 @@ self.w(u'
') -@add_metaclass(class_deprecated) -class BoxField(HTMLWidget): +class BoxField(HTMLWidget, metaclass=class_deprecated): """couples label / value meant to be displayed in a box""" __deprecation_warning__ = '[3.10] class %(cls)s is deprecated' def __init__(self, label, value): @@ -224,8 +219,7 @@ % (self.label, self.value)) -@add_metaclass(class_deprecated) -class BoxSeparator(HTMLWidget): +class BoxSeparator(HTMLWidget, metaclass=class_deprecated): """a menu separator""" __deprecation_warning__ = '[3.10] class %(cls)s is deprecated' @@ -233,8 +227,7 @@ self.w(u'
    ') -@add_metaclass(class_deprecated) -class BoxLink(HTMLWidget): +class BoxLink(HTMLWidget, metaclass=class_deprecated): """a link in a box""" __deprecation_warning__ = '[3.10] class %(cls)s is deprecated' def __init__(self, href, label, _class='', title='', ident='', escape=False): @@ -256,8 +249,7 @@ self.w(u'
  • %s
  • \n' % (self._class, link)) -@add_metaclass(class_deprecated) -class BoxHtml(HTMLWidget): +class BoxHtml(HTMLWidget, metaclass=class_deprecated): """a form in a box""" __deprecation_warning__ = '[3.10] class %(cls)s is deprecated' def __init__(self, rawhtml): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/http_headers.py --- a/cubicweb/web/http_headers.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/http_headers.py Fri Apr 05 17:58:19 2019 +0200 @@ -6,9 +6,7 @@ from calendar import timegm import base64 import re - -from six import string_types -from six.moves.urllib.parse import urlparse +from urllib.parse import urlparse def dashCapitalize(s): @@ -383,7 +381,7 @@ def unique(seq): '''if seq is not a string, check it's a sequence of one element and return it''' - if isinstance(seq, string_types): + if isinstance(seq, str): return seq if len(seq) != 1: raise ValueError('single value required, not %s' % seq) @@ -455,10 +453,10 @@ """ if (value in (True, 1) or - isinstance(value, string_types) and value.lower() == 'true'): + isinstance(value, str) and value.lower() == 'true'): return 'true' if (value in (False, 0) or - isinstance(value, string_types) and value.lower() == 'false'): + isinstance(value, str) and value.lower() == 'false'): return 'false' raise ValueError("Invalid true/false header value: %s" % value) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/request.py --- a/cubicweb/web/request.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/request.py Fri Apr 05 17:58:19 2019 +0200 @@ -23,12 +23,10 @@ from hashlib import sha1 # pylint: disable=E0611 from calendar import timegm from datetime import date, datetime +import http.client from io import BytesIO - -from six import PY2, text_type, string_types -from six.moves import http_client -from six.moves.urllib.parse import urlsplit, quote as urlquote -from six.moves.http_cookies import SimpleCookie +from urllib.parse import urlsplit, quote as urlquote +from http.cookies import SimpleCookie from rql.utils import rqlvar_maker @@ -208,12 +206,8 @@ encoding = self.encoding for param, val in params.items(): if isinstance(val, (tuple, list)): - if PY2: - val = [unicode(x, encoding) for x in val] if len(val) == 1: val = val[0] - elif PY2 and isinstance(val, str): - val = unicode(val, encoding) if param in self.no_script_form_params and val: val = self.no_script_form_param(param, val) if param == '_cwmsgid': @@ -274,7 +268,7 @@ return None def set_message(self, msg): - assert isinstance(msg, text_type) + assert isinstance(msg, str) self.reset_message() self._msg = msg @@ -287,7 +281,7 @@ def set_redirect_message(self, msg): # TODO - this should probably be merged with append_to_redirect_message - assert isinstance(msg, text_type) + assert isinstance(msg, str) msgid = self.redirect_message_id() self.session.data[msgid] = msg return msgid @@ -374,7 +368,7 @@ eids = form['eid'] except KeyError: raise NothingToEdit(self._('no selected entities')) - if isinstance(eids, string_types): + if isinstance(eids, str): eids = (eids,) for peid in eids: if withtype: @@ -523,7 +517,7 @@ :param localfile: if True, the default data dir prefix is added to the JS filename """ - if isinstance(jsfiles, string_types): + if isinstance(jsfiles, str): jsfiles = (jsfiles,) for jsfile in jsfiles: if localfile: @@ -543,7 +537,7 @@ the css inclusion. cf: http://msdn.microsoft.com/en-us/library/ms537512(VS.85).aspx """ - if isinstance(cssfiles, string_types): + if isinstance(cssfiles, str): cssfiles = (cssfiles,) if ieonly: if self.ie_browser(): @@ -613,7 +607,7 @@ lang_prefix = '' if self.lang is not None and self.vreg.config.get('language-mode') == 'url-prefix': lang_prefix = '%s/' % self.lang - return lang_prefix + path + return lang_prefix + str(path) def url(self, includeparams=True): """return currently accessed url""" @@ -666,9 +660,9 @@ # overwrite headers_out to forge a brand new not-modified response self.headers_out = self._forge_cached_headers() if self.http_method() in ('HEAD', 'GET'): - self.status_out = http_client.NOT_MODIFIED + self.status_out = http.client.NOT_MODIFIED else: - self.status_out = http_client.PRECONDITION_FAILED + self.status_out = http.client.PRECONDITION_FAILED # XXX replace by True once validate_cache bw compat method is dropped return self.status_out # XXX replace by False once validate_cache bw compat method is dropped diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/schemaviewer.py --- a/cubicweb/web/schemaviewer.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/schemaviewer.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ from cubicweb import _ -from six import string_types - from logilab.common.ureports import Section, Title, Table, Link, Span, Text from yams.schema2dot import CARD_MAP @@ -228,7 +226,7 @@ elif isinstance(val, (list, tuple)): val = sorted(val) val = ', '.join(str(v) for v in val) - elif val and isinstance(val, string_types): + elif val and isinstance(val, str): val = _(val) else: val = str(val) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/test/data/cubicweb_file/entities.py --- a/cubicweb/web/test/data/cubicweb_file/entities.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/test/data/cubicweb_file/entities.py Fri Apr 05 17:58:19 2019 +0200 @@ -1,4 +1,3 @@ -from six import text_type from logilab.mtconverter import guess_mimetype_and_encoding from cubicweb.entities import AnyEntity, fetch_config @@ -42,9 +41,9 @@ format=format, encoding=encoding, fallbackencoding=self._cw.encoding) if format: - self.cw_edited['data_format'] = text_type(format) + self.cw_edited['data_format'] = str(format) if encoding: - self.cw_edited['data_encoding'] = text_type(encoding) + self.cw_edited['data_encoding'] = str(encoding) class UnResizeable(Exception): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/test/unittest_application.py --- a/cubicweb/web/test/unittest_application.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/test/unittest_application.py Fri Apr 05 17:58:19 2019 +0200 @@ -18,10 +18,8 @@ """unit tests for cubicweb.web.application""" import base64 - -from six import text_type -from six.moves import http_client -from six.moves.http_cookies import SimpleCookie +import http.client +from http.cookies import SimpleCookie from logilab.common.testlib import TestCase, unittest_main from logilab.common.decorators import clear_cache @@ -167,7 +165,7 @@ def test_publish_validation_error(self): with self.admin_access.web_request() as req: user = req.user - eid = text_type(user.eid) + eid = str(user.eid) req.form = { 'eid': eid, '__type:' + eid: 'CWUser', @@ -248,8 +246,8 @@ self.config.global_set_option('language-mode', 'http-negotiation') orig_translations = self.config.translations.copy() self.config.translations = { - 'fr': (text_type, lambda x, y: text_type(y)), - 'en': (text_type, lambda x, y: text_type(y))} + 'fr': (str, lambda x, y: str(y)), + 'en': (str, lambda x, y: str(y))} try: headers = {'Accept-Language': 'fr'} with self.admin_access.web_request(headers=headers) as req: @@ -336,8 +334,8 @@ parent_eid = parent_eid or '__cubicweb_internal_field__' with self.admin_access.web_request() as req: req.form = { - 'eid': text_type(dir_eid), - '__maineid': text_type(dir_eid), + 'eid': str(dir_eid), + '__maineid': str(dir_eid), '__type:%s' % dir_eid: etype, 'parent-%s:%s' % (role, dir_eid): parent_eid, } @@ -353,8 +351,8 @@ version_eid = version_eid or '__cubicweb_internal_field__' with self.admin_access.web_request() as req: req.form = { - 'eid': text_type(ticket_eid), - '__maineid': text_type(ticket_eid), + 'eid': str(ticket_eid), + '__maineid': str(ticket_eid), '__type:%s' % ticket_eid: 'Ticket', 'in_version-subject:%s' % ticket_eid: version_eid, } @@ -395,8 +393,8 @@ with self.admin_access.web_request() as req: req.form = { - 'eid': (text_type(topd.eid), u'B'), - '__maineid': text_type(topd.eid), + 'eid': (str(topd.eid), u'B'), + '__maineid': str(topd.eid), '__type:%s' % topd.eid: 'Directory', '__type:B': 'Directory', 'parent-object:%s' % topd.eid: u'B', @@ -569,8 +567,8 @@ cnx.commit() with self.admin_access.web_request() as req: - dir_eid = text_type(mydir.eid) - perm_eid = text_type(perm.eid) + dir_eid = str(mydir.eid) + perm_eid = str(perm.eid) req.form = { 'eid': [dir_eid, perm_eid], '__maineid': dir_eid, @@ -596,7 +594,7 @@ with self.admin_access.web_request(vid='test.ajax.error', url='') as req: req.ajax_request = True app.handle_request(req) - self.assertEqual(http_client.INTERNAL_SERVER_ERROR, + self.assertEqual(http.client.INTERNAL_SERVER_ERROR, req.status_out) def _test_cleaned(self, kwargs, injected, cleaned): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/test/unittest_form.py --- a/cubicweb/web/test/unittest_form.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/test/unittest_form.py Fri Apr 05 17:58:19 2019 +0200 @@ -19,8 +19,6 @@ import time from datetime import datetime -from six import text_type - import pytz from lxml import html @@ -80,19 +78,19 @@ t = req.create_entity('Tag', name=u'x') form1 = self.vreg['forms'].select('edition', req, entity=t) choices = [reid for rview, reid in form1.field_by_name('tags', 'subject', t.e_schema).choices(form1)] - self.assertIn(text_type(b.eid), choices) + self.assertIn(str(b.eid), choices) form2 = self.vreg['forms'].select('edition', req, entity=b) choices = [reid for rview, reid in form2.field_by_name('tags', 'object', t.e_schema).choices(form2)] - self.assertIn(text_type(t.eid), choices) + self.assertIn(str(t.eid), choices) b.cw_clear_all_caches() t.cw_clear_all_caches() req.cnx.execute('SET X tags Y WHERE X is Tag, Y is BlogEntry') choices = [reid for rview, reid in form1.field_by_name('tags', 'subject', t.e_schema).choices(form1)] - self.assertIn(text_type(b.eid), choices) + self.assertIn(str(b.eid), choices) choices = [reid for rview, reid in form2.field_by_name('tags', 'object', t.e_schema).choices(form2)] - self.assertIn(text_type(t.eid), choices) + self.assertIn(str(t.eid), choices) def test_form_field_choices_new_entity(self): with self.admin_access.web_request() as req: diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/test/unittest_magicsearch.py --- a/cubicweb/web/test/unittest_magicsearch.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/test/unittest_magicsearch.py Fri Apr 05 17:58:19 2019 +0200 @@ -21,8 +21,6 @@ import sys from contextlib import contextmanager -from six.moves import range - from logilab.common.testlib import TestCase, unittest_main from rql import BadRQLQuery, RQLSyntaxError diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/test/unittest_request.py --- a/cubicweb/web/test/unittest_request.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/test/unittest_request.py Fri Apr 05 17:58:19 2019 +0200 @@ -4,8 +4,6 @@ import unittest from functools import partial -from six import text_type - from cubicweb.devtools.fake import FakeConfig, FakeCWRegistryStore from cubicweb.web.request import (CubicWebRequestBase, _parse_accept_header, @@ -84,7 +82,7 @@ vreg = FakeCWRegistryStore(FakeConfig(), initlog=False) vreg.config['base-url'] = 'http://testing.fr/cubicweb/' vreg.config['language-mode'] = 'url-prefix' - vreg.config.translations['fr'] = text_type, text_type + vreg.config.translations['fr'] = str, str req = CubicWebRequestBase(vreg) # Override from_controller to avoid getting into relative_path method, # which is not implemented in CubicWebRequestBase. diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/test/unittest_urlrewrite.py --- a/cubicweb/web/test/unittest_urlrewrite.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/test/unittest_urlrewrite.py Fri Apr 05 17:58:19 2019 +0200 @@ -16,8 +16,6 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -from six import text_type - from logilab.common import tempattr from cubicweb.devtools.testlib import CubicWebTC @@ -139,8 +137,8 @@ rgx_action(r'Any X WHERE X surname %(sn)s, ' 'X firstname %(fn)s', argsgroups=('sn', 'fn'), - transforms={'sn' : text_type.capitalize, - 'fn' : text_type.lower,})), + transforms={'sn' : str.capitalize, + 'fn' : str.lower,})), ] with self.admin_access.web_request() as req: rewriter = TestSchemaBasedRewriter(req) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/test/unittest_views_basecontrollers.py --- a/cubicweb/web/test/unittest_views_basecontrollers.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/test/unittest_views_basecontrollers.py Fri Apr 05 17:58:19 2019 +0200 @@ -18,9 +18,7 @@ """cubicweb.web.views.basecontrollers unit tests""" import time - -from six import text_type -from six.moves.urllib.parse import urlsplit, urlunsplit, urljoin, parse_qs +from urllib.parse import urlsplit, urlunsplit, urljoin, parse_qs import lxml @@ -92,7 +90,7 @@ } with self.assertRaises(ValidationError) as cm: self.ctrl_publish(req) - cm.exception.translate(text_type) + cm.exception.translate(str) expected = { '': u'some relations violate a unicity constraint', 'login': u'login is part of violated unicity constraint', @@ -149,12 +147,12 @@ user = req.user groupeids = [eid for eid, in req.execute('CWGroup G WHERE G name ' 'in ("managers", "users")')] - groups = [text_type(eid) for eid in groupeids] - eid = text_type(user.eid) + groups = [str(eid) for eid in groupeids] + eid = str(user.eid) req.form = { 'eid': eid, '__type:'+eid: 'CWUser', '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject,in_group-subject', - 'login-subject:'+eid: text_type(user.login), + 'login-subject:'+eid: str(user.login), 'surname-subject:'+eid: u'Th\xe9nault', 'firstname-subject:'+eid: u'Sylvain', 'in_group-subject:'+eid: groups, @@ -172,7 +170,7 @@ self.create_user(cnx, u'user') cnx.commit() with self.new_access(u'user').web_request() as req: - eid = text_type(req.user.eid) + eid = str(req.user.eid) req.form = { 'eid': eid, '__maineid' : eid, '__type:'+eid: 'CWUser', @@ -192,12 +190,12 @@ with self.admin_access.web_request() as req: user = req.user groupeids = [g.eid for g in user.in_group] - eid = text_type(user.eid) + eid = str(user.eid) req.form = { 'eid': eid, '__type:'+eid: 'CWUser', '_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject', - 'login-subject:'+eid: text_type(user.login), + 'login-subject:'+eid: str(user.login), 'firstname-subject:'+eid: u'Th\xe9nault', 'surname-subject:'+eid: u'Sylvain', } @@ -220,7 +218,7 @@ 'login-subject:X': u'adim', 'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto', 'surname-subject:X': u'Di Mascio', - 'in_group-subject:X': text_type(gueid), + 'in_group-subject:X': str(gueid), '__type:Y': 'EmailAddress', '_cw_entity_fields:Y': 'address-subject,use_email-object', @@ -287,7 +285,7 @@ # non regression test for #3120495. Without the fix, leads to # "unhashable type: 'list'" error with self.admin_access.web_request() as req: - cwrelation = text_type(req.execute('CWEType X WHERE X name "CWSource"')[0][0]) + cwrelation = str(req.execute('CWEType X WHERE X name "CWSource"')[0][0]) req.form = {'eid': [cwrelation], '__maineid' : cwrelation, '__type:'+cwrelation: 'CWEType', @@ -300,7 +298,7 @@ def test_edit_multiple_linked(self): with self.admin_access.web_request() as req: - peid = text_type(self.create_user(req, u'adim').eid) + peid = str(self.create_user(req, u'adim').eid) req.form = {'eid': [peid, 'Y'], '__maineid': peid, '__type:'+peid: u'CWUser', @@ -320,7 +318,7 @@ self.assertEqual(email.address, 'dima@logilab.fr') # with self.admin_access.web_request() as req: - emaileid = text_type(email.eid) + emaileid = str(email.eid) req.form = {'eid': [peid, emaileid], '__type:'+peid: u'CWUser', @@ -342,7 +340,7 @@ with self.admin_access.web_request() as req: user = req.user req.form = {'eid': 'X', - '__cloned_eid:X': text_type(user.eid), '__type:X': 'CWUser', + '__cloned_eid:X': str(user.eid), '__type:X': 'CWUser', '_cw_entity_fields:X': 'login-subject,upassword-subject', 'login-subject:X': u'toto', 'upassword-subject:X': u'toto', @@ -351,7 +349,7 @@ self.ctrl_publish(req) self.assertEqual({'upassword-subject': u'password and confirmation don\'t match'}, cm.exception.errors) - req.form = {'__cloned_eid:X': text_type(user.eid), + req.form = {'__cloned_eid:X': str(user.eid), 'eid': 'X', '__type:X': 'CWUser', '_cw_entity_fields:X': 'login-subject,upassword-subject', 'login-subject:X': u'toto', @@ -375,11 +373,11 @@ '__type:X': 'Salesterm', '_cw_entity_fields:X': 'amount-subject,described_by_test-subject', 'amount-subject:X': u'-10', - 'described_by_test-subject:X': text_type(feid), + 'described_by_test-subject:X': str(feid), } with self.assertRaises(ValidationError) as cm: self.ctrl_publish(req) - cm.exception.translate(text_type) + cm.exception.translate(str) self.assertEqual({'amount-subject': 'value -10 must be >= 0'}, cm.exception.errors) @@ -388,11 +386,11 @@ '__type:X': 'Salesterm', '_cw_entity_fields:X': 'amount-subject,described_by_test-subject', 'amount-subject:X': u'110', - 'described_by_test-subject:X': text_type(feid), + 'described_by_test-subject:X': str(feid), } with self.assertRaises(ValidationError) as cm: self.ctrl_publish(req) - cm.exception.translate(text_type) + cm.exception.translate(str) self.assertEqual(cm.exception.errors, {'amount-subject': 'value 110 must be <= 100'}) with self.admin_access.web_request(rollbackfirst=True) as req: @@ -400,7 +398,7 @@ '__type:X': 'Salesterm', '_cw_entity_fields:X': 'amount-subject,described_by_test-subject', 'amount-subject:X': u'10', - 'described_by_test-subject:X': text_type(feid), + 'described_by_test-subject:X': str(feid), } self.expect_redirect_handle_request(req, 'edit') # should be redirected on the created @@ -419,7 +417,7 @@ # ensure a value that violate a constraint is properly detected with self.admin_access.web_request(rollbackfirst=True) as req: - req.form = {'eid': [text_type(seid)], + req.form = {'eid': [str(seid)], '__type:%s'%seid: 'Salesterm', '_cw_entity_fields:%s'%seid: 'amount-subject', 'amount-subject:%s'%seid: u'-10', @@ -430,7 +428,7 @@ # ensure a value that comply a constraint is properly processed with self.admin_access.web_request(rollbackfirst=True) as req: - req.form = {'eid': [text_type(seid)], + req.form = {'eid': [str(seid)], '__type:%s'%seid: 'Salesterm', '_cw_entity_fields:%s'%seid: 'amount-subject', 'amount-subject:%s'%seid: u'20', @@ -446,7 +444,7 @@ '__type:X': 'Salesterm', '_cw_entity_fields:X': 'amount-subject,described_by_test-subject', 'amount-subject:X': u'0', - 'described_by_test-subject:X': text_type(feid), + 'described_by_test-subject:X': str(feid), } # ensure a value that is modified in an operation on a modify @@ -554,7 +552,7 @@ def test_redirect_delete_button(self): with self.admin_access.web_request() as req: eid = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid - req.form = {'eid': text_type(eid), '__type:%s'%eid: 'BlogEntry', + req.form = {'eid': str(eid), '__type:%s'%eid: 'BlogEntry', '__action_delete': ''} path, params = self.expect_redirect_handle_request(req, 'edit') self.assertEqual(path, 'blogentry') @@ -563,14 +561,14 @@ req.execute('SET X use_email E WHERE E eid %(e)s, X eid %(x)s', {'x': req.user.eid, 'e': eid}) req.cnx.commit() - req.form = {'eid': text_type(eid), '__type:%s'%eid: 'EmailAddress', + req.form = {'eid': str(eid), '__type:%s'%eid: 'EmailAddress', '__action_delete': ''} path, params = self.expect_redirect_handle_request(req, 'edit') self.assertEqual(path, 'cwuser/admin') self.assertIn('_cwmsgid', params) eid1 = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid eid2 = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid - req.form = {'eid': [text_type(eid1), text_type(eid2)], + req.form = {'eid': [str(eid1), str(eid2)], '__type:%s'%eid1: 'BlogEntry', '__type:%s'%eid2: 'EmailAddress', '__action_delete': ''} @@ -672,13 +670,13 @@ groupeids = sorted(eid for eid, in req.execute('CWGroup G ' 'WHERE G name in ("managers", "users")')) - groups = [text_type(eid) for eid in groupeids] + groups = [str(eid) for eid in groupeids] cwetypeeid = req.execute('CWEType X WHERE X name "CWEType"')[0][0] - basegroups = [text_type(eid) + basegroups = [str(eid) for eid, in req.execute('CWGroup G ' 'WHERE X read_permission G, X eid %(x)s', {'x': cwetypeeid})] - cwetypeeid = text_type(cwetypeeid) + cwetypeeid = str(cwetypeeid) req.form = { 'eid': cwetypeeid, '__type:'+cwetypeeid: 'CWEType', diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/test/unittest_views_json.py --- a/cubicweb/web/test/unittest_views_json.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/test/unittest_views_json.py Fri Apr 05 17:58:19 2019 +0200 @@ -16,7 +16,6 @@ # # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . -from six import binary_type from cubicweb.devtools.testlib import CubicWebTC @@ -50,7 +49,7 @@ 'rql': u'Any GN,COUNT(X) GROUPBY GN ORDERBY GN ' 'WHERE X in_group G, G name GN'}) data = self.ctrl_publish(req, ctrl='jsonp') - self.assertIsInstance(data, binary_type) + self.assertIsInstance(data, bytes) self.assertEqual(req.headers_out.getRawHeaders('content-type'), ['application/javascript']) # because jsonp anonymizes data, only 'guests' group should be found diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/test/unittest_viewselector.py --- a/cubicweb/web/test/unittest_viewselector.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/test/unittest_viewselector.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,7 +17,6 @@ # You should have received a copy of the GNU Lesser General Public License along # with CubicWeb. If not, see . """XXX rename, split, reorganize this""" -from __future__ import print_function from logilab.common.testlib import unittest_main diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/uihelper.py --- a/cubicweb/web/uihelper.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/uihelper.py Fri Apr 05 17:58:19 2019 +0200 @@ -45,8 +45,6 @@ """ -from six import add_metaclass - from logilab.common.deprecation import deprecated from cubicweb.web.views import uicfg @@ -94,8 +92,7 @@ super(meta_formconfig, cls).__init__(name, bases, classdict) -@add_metaclass(meta_formconfig) -class FormConfig: +class FormConfig(metaclass=meta_formconfig): """helper base class to define uicfg rules on a given entity type. In all descriptions below, attributes list can either be a list of diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/ajaxcontroller.py --- a/cubicweb/web/views/ajaxcontroller.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/ajaxcontroller.py Fri Apr 05 17:58:19 2019 +0200 @@ -61,13 +61,9 @@ """ - - +import http.client as http_client from functools import partial -from six import PY2, text_type -from six.moves import http_client - from logilab.common.date import strptime from logilab.common.registry import yes @@ -151,7 +147,7 @@ if result is None: return b'' # get unicode on @htmlize methods, encoded string on @jsonize methods - elif isinstance(result, text_type): + elif isinstance(result, str): return result.encode(self._cw.encoding) return result diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/authentication.py --- a/cubicweb/web/views/authentication.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/authentication.py Fri Apr 05 17:58:19 2019 +0200 @@ -17,8 +17,6 @@ # with CubicWeb. If not, see . """user authentication component""" -from six import text_type - from logilab.common.deprecation import class_renamed from logilab.common.textutils import unormalize @@ -114,8 +112,8 @@ self.sessionid = make_uid(unormalize(user.login)) self.data = {} - def __unicode__(self): - return '' % (text_type(self.user.login), id(self)) + def __str__(self): + return '' % (self.user.login, id(self)) @property def anonymous_session(self): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/autoform.py --- a/cubicweb/web/views/autoform.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/autoform.py Fri Apr 05 17:58:19 2019 +0200 @@ -118,8 +118,6 @@ .. Controlling the generic relation fields """ -from six.moves import range - from logilab.mtconverter import xml_escape from logilab.common.decorators import iclassmethod, cached from logilab.common.registry import NoSelectableObject diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/basecontrollers.py --- a/cubicweb/web/views/basecontrollers.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/basecontrollers.py Fri Apr 05 17:58:19 2019 +0200 @@ -19,8 +19,7 @@ object to handle publication. """ -from six import text_type -from six.moves import http_client +import http.client from cubicweb import (NoSelectableObject, ObjectNotFound, ValidationError, AuthenticationError, UndoTransactionException, @@ -44,7 +43,7 @@ raise AuthenticationError() else: # Cookie authentication - self._cw.status_out = http_client.FORBIDDEN + self._cw.status_out = http.client.FORBIDDEN return self.appli.need_login_content(self._cw) class LoginControllerForAuthed(Controller): @@ -187,7 +186,7 @@ except Exception as ex: req.cnx.rollback() req.exception('unexpected error while validating form') - return (False, text_type(ex), ctrl._edited_entity) + return (False, str(ex), ctrl._edited_entity) return (False, '???', None) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/baseviews.py --- a/cubicweb/web/views/baseviews.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/baseviews.py Fri Apr 05 17:58:19 2019 +0200 @@ -77,8 +77,6 @@ from cubicweb import _ -from six.moves import range - from logilab.mtconverter import TransformError, xml_escape from logilab.common.registry import yes diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/boxes.py --- a/cubicweb/web/views/boxes.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/boxes.py Fri Apr 05 17:58:19 2019 +0200 @@ -28,8 +28,6 @@ from cubicweb import _ -from six import text_type, add_metaclass - from logilab.mtconverter import xml_escape from cubicweb import Unauthorized @@ -212,7 +210,7 @@ @property def domid(self): - return super(RsetBox, self).domid + text_type(abs(id(self))) + text_type(abs(id(self.cw_rset))) + return super(RsetBox, self).domid + str(abs(id(self))) + str(abs(id(self.cw_rset))) def render_title(self, w): w(self.cw_extra_kwargs['title']) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/csvexport.py --- a/cubicweb/web/views/csvexport.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/csvexport.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,9 +20,6 @@ from cubicweb import _ -from six import PY2 -from six.moves import range - from cubicweb.schema import display_name from cubicweb.predicates import any_rset, empty_rset from cubicweb.uilib import UnicodeCSVWriter @@ -32,7 +29,7 @@ """mixin class for CSV views""" templatable = False content_type = "text/comma-separated-values" - binary = PY2 # python csv module is unicode aware in py3k + binary = False csv_params = {'dialect': 'excel', 'quotechar': '"', 'delimiter': ';', diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/cwsources.py --- a/cubicweb/web/views/cwsources.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/cwsources.py Fri Apr 05 17:58:19 2019 +0200 @@ -21,8 +21,6 @@ import logging -from six.moves import range - from logilab.common.decorators import cachedproperty from cubicweb import _ diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/cwuser.py --- a/cubicweb/web/views/cwuser.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/cwuser.py Fri Apr 05 17:58:19 2019 +0200 @@ -22,9 +22,6 @@ from hashlib import sha1 # pylint: disable=E0611 -from six import text_type -from six.moves import range - from logilab.mtconverter import xml_escape from cubicweb import tags @@ -252,6 +249,6 @@ 'group': tableview.MainEntityColRenderer(), 'nb_users': tableview.EntityTableColRenderer( header=_('num. users'), - renderfunc=lambda w, x: w(text_type(x.num_users())), + renderfunc=lambda w, x: w(str(x.num_users())), sortfunc=lambda x: x.num_users()), } diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/debug.py --- a/cubicweb/web/views/debug.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/debug.py Fri Apr 05 17:58:19 2019 +0200 @@ -21,8 +21,6 @@ from time import strftime, localtime -from six import text_type - from logilab.mtconverter import xml_escape from cubicweb.predicates import none_rset, match_user_groups @@ -98,7 +96,7 @@ if k.endswith('_cache_size'): stats[k] = '%s / %s' % (stats[k]['size'], stats[k]['maxsize']) def format_stat(sname, sval): - return '%s %s' % (xml_escape(text_type(sval)), + return '%s %s' % (xml_escape(str(sval)), sname.endswith('percent') and '%' or '') pyvalue = [(sname, format_stat(sname, sval)) for sname, sval in sorted(stats.items())] diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/editcontroller.py --- a/cubicweb/web/views/editcontroller.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/editcontroller.py Fri Apr 05 17:58:19 2019 +0200 @@ -22,8 +22,6 @@ from datetime import datetime -from six import text_type - from logilab.common.graph import ordered_nodes from rql.utils import rqlvar_maker @@ -201,7 +199,7 @@ if '__linkto' in req.form and 'eid' in req.form: self.execute_linkto() elif '__delete' not in req.form: - raise ValidationError(None, {None: text_type(ex)}) + raise ValidationError(None, {None: str(ex)}) # all pending inlined relations to newly created entities have been # treated now (pop to ensure there are no attempt to add new ones) pending_inlined = req.data.pop('pending_inlined') @@ -234,7 +232,7 @@ autoform.delete_relations(self._cw, todelete) self._cw.remove_pending_operations() if self.errors: - errors = dict((f.name, text_type(ex)) for f, ex in self.errors) + errors = dict((f.name, str(ex)) for f, ex in self.errors) raise ValidationError(valerror_eid(form.get('__maineid')), errors) def _insert_entity(self, etype, eid, rqlquery): @@ -285,7 +283,7 @@ rqlquery.set_inlined(field.name, form_.edited_entity.eid) if not rqlquery.canceled: if self.errors: - errors = dict((f.role_name(), text_type(ex)) for f, ex in self.errors) + errors = dict((f.role_name(), str(ex)) for f, ex in self.errors) raise ValidationError(valerror_eid(entity.eid), errors) if eid is None: # creation or copy entity.eid = eid = self._insert_entity(etype, formparams['eid'], rqlquery) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/editforms.py --- a/cubicweb/web/views/editforms.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/editforms.py Fri Apr 05 17:58:19 2019 +0200 @@ -23,8 +23,6 @@ from copy import copy -from six.moves import range - from logilab.common.registry import yes from cubicweb import _ diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/formrenderers.py --- a/cubicweb/web/views/formrenderers.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/formrenderers.py Fri Apr 05 17:58:19 2019 +0200 @@ -37,8 +37,6 @@ from warnings import warn -from six import text_type - from logilab.mtconverter import xml_escape from logilab.common.registry import yes @@ -121,7 +119,7 @@ data.insert(0, errormsg) # NOTE: we call unicode because `tag` objects may be found within data # e.g. from the cwtags library - w(''.join(text_type(x) for x in data)) + w(''.join(str(x) for x in data)) def render_content(self, w, form, values): if self.display_progress_div: diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/forms.py --- a/cubicweb/web/views/forms.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/forms.py Fri Apr 05 17:58:19 2019 +0200 @@ -45,8 +45,6 @@ import time import inspect -from six import text_type - from logilab.common import dictattr, tempattr from logilab.common.decorators import iclassmethod, cached from logilab.common.textutils import splitstrip @@ -286,7 +284,7 @@ except ProcessFormError as exc: errors.append((field, exc)) if errors: - errors = dict((f.role_name(), text_type(ex)) for f, ex in errors) + errors = dict((f.role_name(), str(ex)) for f, ex in errors) raise ValidationError(None, errors) return processed diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/ibreadcrumbs.py --- a/cubicweb/web/views/ibreadcrumbs.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/ibreadcrumbs.py Fri Apr 05 17:58:19 2019 +0200 @@ -22,8 +22,6 @@ from warnings import warn -from six import text_type - from logilab.mtconverter import xml_escape from cubicweb import tags, uilib @@ -146,7 +144,7 @@ xml_escape(url), xml_escape(uilib.cut(title, textsize)))) else: textsize = self._cw.property_value('navigation.short-line-size') - w(xml_escape(uilib.cut(text_type(part), textsize))) + w(xml_escape(uilib.cut(str(part), textsize))) class BreadCrumbETypeVComponent(BreadCrumbEntityVComponent): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/idownloadable.py --- a/cubicweb/web/views/idownloadable.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/idownloadable.py Fri Apr 05 17:58:19 2019 +0200 @@ -22,8 +22,6 @@ from cubicweb import _ -from six.moves import range - from logilab.mtconverter import BINARY_ENCODINGS, TransformError, xml_escape from cubicweb import tags diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/magicsearch.py --- a/cubicweb/web/views/magicsearch.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/magicsearch.py Fri Apr 05 17:58:19 2019 +0200 @@ -23,8 +23,6 @@ import re from logging import getLogger -from six import text_type - from yams.interfaces import IVocabularyConstraint from rql import RQLSyntaxError, BadRQLQuery, parse @@ -388,7 +386,7 @@ self.processors = sorted(processors, key=lambda x: x.priority) def process_query(self, uquery): - assert isinstance(uquery, text_type) + assert isinstance(uquery, str) try: procname, query = uquery.split(':', 1) proc = self.by_name[procname.strip().lower()] diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/navigation.py --- a/cubicweb/web/views/navigation.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/navigation.py Fri Apr 05 17:58:19 2019 +0200 @@ -50,8 +50,6 @@ from datetime import datetime -from six import text_type - from rql.nodes import VariableRef, Constant from logilab.mtconverter import xml_escape @@ -193,10 +191,10 @@ return entity.printable_value(attrname, format='text/plain') elif col is None: # smart links disabled. def index_display(row): - return text_type(row) + return str(row) elif self._cw.vreg.schema.eschema(rset.description[0][col]).final: def index_display(row): - return text_type(rset[row][col]) + return str(rset[row][col]) else: def index_display(row): return rset.get_entity(row, col).view('text') diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/owl.py --- a/cubicweb/web/views/owl.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/owl.py Fri Apr 05 17:58:19 2019 +0200 @@ -21,8 +21,6 @@ from cubicweb import _ -from six.moves import range - from logilab.mtconverter import TransformError, xml_escape from cubicweb.view import StartupView, EntityView diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/pyviews.py --- a/cubicweb/web/views/pyviews.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/pyviews.py Fri Apr 05 17:58:19 2019 +0200 @@ -18,10 +18,6 @@ """Basic views for python values (eg without any result set) """ - -from six import text_type -from six.moves import range - from cubicweb.view import View from cubicweb.predicates import match_kwargs from cubicweb.web.views import tableview @@ -41,7 +37,7 @@ w(self.empty_cell_content) def render_cell(self, w, rownum): - w(text_type(self.data[rownum][self.colid])) + w(str(self.data[rownum][self.colid])) class PyValTableView(tableview.TableMixIn, View): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/rdf.py --- a/cubicweb/web/views/rdf.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/rdf.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ from cubicweb import _ -from six.moves import range - from yams import xy from cubicweb.schema import VIRTUAL_RTYPES diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/schema.py --- a/cubicweb/web/views/schema.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/schema.py Fri Apr 05 17:58:19 2019 +0200 @@ -26,8 +26,6 @@ import os, os.path as osp import codecs -from six import text_type - from logilab.common.graph import GraphGenerator, DotBackend from logilab.common.ureports import Section, Table from logilab.common.registry import yes @@ -281,7 +279,7 @@ def cell_call(self, row, col): defaultval = self.cw_rset.rows[row][col] if defaultval is not None: - self.w(text_type(self.cw_rset.rows[row][col].unzpickle())) + self.w(str(self.cw_rset.rows[row][col].unzpickle())) class CWETypeRelationCardinalityCell(baseviews.FinalView): __regid__ = 'etype-rel-cardinality-cell' @@ -489,7 +487,7 @@ entity = self.cw_rset.get_entity(row, col) rschema = self._cw.vreg.schema.rschema(entity.rtype.name) rdef = rschema.rdefs[(entity.stype.name, entity.otype.name)] - constraints = [xml_escape(text_type(c)) for c in getattr(rdef, 'constraints')] + constraints = [xml_escape(str(c)) for c in getattr(rdef, 'constraints')] self.w(u'
    '.join(constraints)) class CWAttributeOptionsCell(EntityView): diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/sparql.py --- a/cubicweb/web/views/sparql.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/sparql.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ from cubicweb import _ -from six.moves import range - from yams import xy from rql import TypeResolverException diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/tableview.py --- a/cubicweb/web/views/tableview.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/tableview.py Fri Apr 05 17:58:19 2019 +0200 @@ -66,9 +66,6 @@ from copy import copy from types import MethodType -from six import string_types, add_metaclass, create_bound_method -from six.moves import range - from logilab.mtconverter import xml_escape from logilab.common.decorators import cachedproperty from logilab.common.deprecation import class_deprecated @@ -286,7 +283,7 @@ attrs = renderer.attributes.copy() if renderer.sortable: sortvalue = renderer.sortvalue(rownum) - if isinstance(sortvalue, string_types): + if isinstance(sortvalue, str): sortvalue = sortvalue[:self.sortvalue_limit] if sortvalue is not None: attrs[u'cubicweb:sortvalue'] = js_dumps(sortvalue) @@ -717,7 +714,7 @@ for aname, member in[('renderfunc', renderfunc), ('sortfunc', sortfunc)]: if isinstance(member, MethodType): - member = create_bound_method(member.__func__, acopy) + member = MethodType(member.__func__, acopy) setattr(acopy, aname, member) return acopy finally: @@ -912,8 +909,7 @@ ################################################################################ -@add_metaclass(class_deprecated) -class TableView(AnyRsetView): +class TableView(AnyRsetView, metaclass=class_deprecated): """The table view accepts any non-empty rset. It uses introspection on the result set to compute column names and the proper way to display the cells. @@ -1178,8 +1174,7 @@ title = _('editable-table') -@add_metaclass(class_deprecated) -class CellView(EntityView): +class CellView(EntityView, metaclass=class_deprecated): __deprecation_warning__ = '[3.14] %(cls)s is deprecated' __regid__ = 'cell' __select__ = nonempty_rset() diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/tabs.py --- a/cubicweb/web/views/tabs.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/tabs.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ from cubicweb import _ -from six import string_types - from logilab.common.deprecation import class_renamed from logilab.mtconverter import xml_escape @@ -116,7 +114,7 @@ active_tab = uilib.domid(default_tab) viewsvreg = self._cw.vreg['views'] for tab in tabs: - if isinstance(tab, string_types): + if isinstance(tab, str): tabid, tabkwargs = tab, {} else: tabid, tabkwargs = tab diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/timetable.py --- a/cubicweb/web/views/timetable.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/timetable.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ from cubicweb import _ -from six.moves import range - from logilab.mtconverter import xml_escape from logilab.common.date import ONEDAY, date_range, todatetime diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/uicfg.py --- a/cubicweb/web/views/uicfg.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/uicfg.py Fri Apr 05 17:58:19 2019 +0200 @@ -56,8 +56,6 @@ from itertools import repeat -from six import string_types - from cubicweb import neg_role from cubicweb.rtags import (RelationTags, RelationTagsBool, RelationTagsSet, RelationTagsDict, NoTargetRelationTagsDict, @@ -692,7 +690,7 @@ self.tag_relation((sschema, rschema, oschema, role), True) def _tag_etype_attr(self, etype, attr, desttype='*', *args, **kwargs): - if isinstance(attr, string_types): + if isinstance(attr, str): attr, role = attr, 'subject' else: attr, role = attr diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/urlrewrite.py --- a/cubicweb/web/views/urlrewrite.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/urlrewrite.py Fri Apr 05 17:58:19 2019 +0200 @@ -19,8 +19,6 @@ import re -from six import string_types, add_metaclass - from cubicweb.uilib import domid from cubicweb.appobject import AppObject @@ -53,8 +51,7 @@ return super(metarewriter, mcs).__new__(mcs, name, bases, classdict) -@add_metaclass(metarewriter) -class URLRewriter(AppObject): +class URLRewriter(AppObject, metaclass=metarewriter): """Base class for URL rewriters. Url rewriters should have a `rules` dict that maps an input URI @@ -124,14 +121,14 @@ required_groups = None if required_groups and not req.user.matching_groups(required_groups): continue - if isinstance(inputurl, string_types): + if isinstance(inputurl, str): if inputurl == uri: req.form.update(infos) break elif inputurl.match(uri): # it's a regexp # XXX what about i18n? (vtitle for instance) for param, value in infos.items(): - if isinstance(value, string_types): + if isinstance(value, str): req.form[param] = inputurl.sub(value, uri) else: req.form[param] = value @@ -224,7 +221,7 @@ required_groups = None if required_groups and not req.user.matching_groups(required_groups): continue - if isinstance(inputurl, string_types): + if isinstance(inputurl, str): if inputurl == uri: return callback(inputurl, uri, req, self._cw.vreg.schema) elif inputurl.match(uri): # it's a regexp diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/wdoc.py --- a/cubicweb/web/views/wdoc.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/wdoc.py Fri Apr 05 17:58:19 2019 +0200 @@ -26,8 +26,6 @@ from os.path import join from xml.etree.ElementTree import parse -from six import text_type - from logilab.common.registry import yes from cubicweb.predicates import match_form_params @@ -91,9 +89,9 @@ for title in node.findall('title'): title_lang = title.attrib['{http://www.w3.org/XML/1998/namespace}lang'] if title_lang == lang: - return text_type(title.text) + return title.text if title_lang == 'en': - fallback_title = text_type(title.text) + fallback_title = title.text return fallback_title diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/workflow.py --- a/cubicweb/web/views/workflow.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/workflow.py Fri Apr 05 17:58:19 2019 +0200 @@ -24,8 +24,6 @@ from cubicweb import _ -from six import text_type - from logilab.mtconverter import xml_escape from cubicweb import Unauthorized @@ -309,7 +307,7 @@ wf = req.entity_from_eid(wfeid) rschema = req.vreg.schema[field.name] param = 'toeid' if field.role == 'subject' else 'fromeid' - return sorted((e.view('combobox'), text_type(e.eid)) + return sorted((e.view('combobox'), str(e.eid)) for e in getattr(wf, 'reverse_%s' % wfrelation) if rschema.has_perm(req, 'add', **{param: e.eid})) diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/xbel.py --- a/cubicweb/web/views/xbel.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/xbel.py Fri Apr 05 17:58:19 2019 +0200 @@ -20,8 +20,6 @@ from cubicweb import _ -from six.moves import range - from logilab.mtconverter import xml_escape from cubicweb.predicates import is_instance diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/views/xmlrss.py --- a/cubicweb/web/views/xmlrss.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/views/xmlrss.py Fri Apr 05 17:58:19 2019 +0200 @@ -22,8 +22,6 @@ from base64 import b64encode from time import timezone -from six.moves import range - from logilab.mtconverter import xml_escape from cubicweb.predicates import (is_instance, non_final_entity, one_line_rset, diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/webconfig.py --- a/cubicweb/web/webconfig.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/webconfig.py Fri Apr 05 17:58:19 2019 +0200 @@ -25,8 +25,6 @@ from uuid import uuid4 from os.path import dirname, join, exists, split, isdir -from six import text_type - from logilab.common.decorators import cached, cachedproperty from logilab.common.configuration import Method, merge_options @@ -134,8 +132,6 @@ try: user = self['anonymous-user'] or None passwd = self['anonymous-password'] - if user: - user = text_type(user) except KeyError: user, passwd = None, None except UnicodeDecodeError: @@ -301,7 +297,7 @@ def sign_text(self, text): """sign some text for later checking""" # hmac.new expect bytes - if isinstance(text, text_type): + if isinstance(text, str): text = text.encode('utf-8') # replace \r\n so we do not depend on whether a browser "reencode" # original message using \r\n or not diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/web/webctl.py --- a/cubicweb/web/webctl.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/web/webctl.py Fri Apr 05 17:58:19 2019 +0200 @@ -18,7 +18,6 @@ """cubicweb-ctl commands and command handlers common to twisted/modpython web configuration """ -from __future__ import print_function import os import os.path as osp diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/wfutils.py --- a/cubicweb/wfutils.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/wfutils.py Fri Apr 05 17:58:19 2019 +0200 @@ -45,8 +45,6 @@ import collections -from six import text_type - from cubicweb import NoResultError @@ -91,7 +89,6 @@ by calling :func:`cleanupworkflow`. :return: The created/updated workflow entity """ - name = text_type(name) try: wf = cnx.find('Workflow', name=name).one() except NoResultError: diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/wsgi/__init__.py --- a/cubicweb/wsgi/__init__.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/wsgi/__init__.py Fri Apr 05 17:58:19 2019 +0200 @@ -27,9 +27,9 @@ from email import message, message_from_string +from http.cookies import SimpleCookie from pprint import pformat as _pformat -from six.moves.http_cookies import SimpleCookie def pformat(obj): """pretty prints `obj` if possible""" diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/wsgi/handler.py --- a/cubicweb/wsgi/handler.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/wsgi/handler.py Fri Apr 05 17:58:19 2019 +0200 @@ -21,8 +21,6 @@ from itertools import chain, repeat -from six.moves import zip - from cubicweb import AuthenticationError from cubicweb.web import DirectResponse from cubicweb.web.application import CubicWebPublisher diff -r 6b3523f81f42 -r 26744ad37953 cubicweb/wsgi/request.py --- a/cubicweb/wsgi/request.py Fri Apr 05 17:21:14 2019 +0200 +++ b/cubicweb/wsgi/request.py Fri Apr 05 17:58:19 2019 +0200 @@ -28,8 +28,7 @@ import tempfile from io import BytesIO - -from six.moves.urllib.parse import parse_qs +from urllib.parse import parse_qs from cubicweb.multipart import ( copy_file, parse_form_data, parse_options_header) diff -r 6b3523f81f42 -r 26744ad37953 debian/control --- a/debian/control Fri Apr 05 17:21:14 2019 +0200 +++ b/debian/control Fri Apr 05 17:58:19 2019 +0200 @@ -14,7 +14,6 @@ python-docutils, python-sphinx, python-logilab-common (>= 1.4.0), - python-unittest2 (>= 0.7.0), python-logilab-mtconverter, python-markdown, python-tz, @@ -46,7 +45,6 @@ python-logilab-database (>= 1.15.0), python-yams (>= 0.45.0), python-rql (>= 0.34.0), - python-unittest2 (>= 0.7.0), python-lxml, python-markdown, python-passlib, diff -r 6b3523f81f42 -r 26744ad37953 doc/changes/3.27.rst --- a/doc/changes/3.27.rst Fri Apr 05 17:21:14 2019 +0200 +++ b/doc/changes/3.27.rst Fri Apr 05 17:58:19 2019 +0200 @@ -25,6 +25,8 @@ * Support for legacy cubes (in the 'cubes' python namespace) has been dropped. Use of environment variables CW_CUBES_PATH and CUBES_DIR is removed. +* Python 2 support has been dropped. + Deprecated code drops --------------------- diff -r 6b3523f81f42 -r 26744ad37953 doc/tools/mode_plan.py --- a/doc/tools/mode_plan.py Fri Apr 05 17:21:14 2019 +0200 +++ b/doc/tools/mode_plan.py Fri Apr 05 17:58:19 2019 +0200 @@ -23,8 +23,6 @@ rename A010-joe.en.txt to A030-joe.en.txt accept [y/N]? """ -from __future__ import print_function - def ren(a,b): names = glob.glob('%s*'%a) diff -r 6b3523f81f42 -r 26744ad37953 setup.py --- a/setup.py Fri Apr 05 17:21:14 2019 +0200 +++ b/setup.py Fri Apr 05 17:58:19 2019 +0200 @@ -63,7 +63,6 @@ package_data=package_data, include_package_data=True, install_requires=[ - 'six >= 1.4.0', 'logilab-common >= 1.4.0', 'logilab-mtconverter >= 0.8.0', 'rql >= 0.34.0', @@ -73,7 +72,6 @@ 'passlib', 'pytz', 'Markdown', - 'unittest2 >= 0.7.0', 'filelock', ], entry_points={ diff -r 6b3523f81f42 -r 26744ad37953 tox.ini --- a/tox.ini Fri Apr 05 17:21:14 2019 +0200 +++ b/tox.ini Fri Apr 05 17:58:19 2019 +0200 @@ -1,12 +1,12 @@ [tox] envlist = check-manifest,flake8, - py{27,3}-{server,web,misc} + py3-{server,web,misc} [testenv] +basepython=python3 deps = -r{toxinidir}/requirements/dev.txt - py27: backports.tempfile misc: -r{toxinidir}/requirements/test-misc.txt server: -r{toxinidir}/requirements/test-server.txt web: -r{toxinidir}/requirements/test-web.txt @@ -17,7 +17,6 @@ web: {envpython} -m pytest {posargs} {toxinidir}/cubicweb/web/test [testenv:flake8] -basepython=python3 skip_install = true deps = flake8 >= 3.6