mirror of
https://github.com/YunoHost/moulinette.git
synced 2024-09-03 20:06:31 +02:00
Minimal change to support python3
This commit is contained in:
parent
54b8cab133
commit
641126e344
15 changed files with 52 additions and 55 deletions
|
@ -2,13 +2,13 @@ language: python
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- python: 2.7
|
- python: 3.5
|
||||||
env: TOXENV=py27
|
env: TOXENV=py35
|
||||||
- python: 2.7
|
- python: 3.5
|
||||||
env: TOXENV=lint
|
env: TOXENV=lint
|
||||||
- python: 3.6
|
- python: 3.6
|
||||||
env: TOXENV=format-check
|
env: TOXENV=format-check
|
||||||
- python: 2.7
|
- python: 3.5
|
||||||
env: TOXENV=docs
|
env: TOXENV=docs
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
|
|
@ -4,7 +4,7 @@ import os
|
||||||
import re
|
import re
|
||||||
import logging
|
import logging
|
||||||
import yaml
|
import yaml
|
||||||
import cPickle as pickle
|
import pickle as pickle
|
||||||
from time import time
|
from time import time
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
@ -186,7 +186,7 @@ class PatternParameter(_ExtraParameter):
|
||||||
|
|
||||||
# Use temporarly utf-8 encoded value
|
# Use temporarly utf-8 encoded value
|
||||||
try:
|
try:
|
||||||
v = unicode(arg_value, "utf-8")
|
v = str(arg_value, "utf-8")
|
||||||
except:
|
except:
|
||||||
v = arg_value
|
v = arg_value
|
||||||
|
|
||||||
|
@ -440,7 +440,7 @@ class ActionsMap(object):
|
||||||
if use_cache and os.path.exists(actionsmap_pkl):
|
if use_cache and os.path.exists(actionsmap_pkl):
|
||||||
try:
|
try:
|
||||||
# Attempt to load cache
|
# Attempt to load cache
|
||||||
with open(actionsmap_pkl) as f:
|
with open(actionsmap_pkl, "rb") as f:
|
||||||
actionsmaps[n] = pickle.load(f)
|
actionsmaps[n] = pickle.load(f)
|
||||||
# TODO: Switch to python3 and catch proper exception
|
# TODO: Switch to python3 and catch proper exception
|
||||||
except (IOError, EOFError):
|
except (IOError, EOFError):
|
||||||
|
@ -645,7 +645,7 @@ class ActionsMap(object):
|
||||||
|
|
||||||
pkl = "%s-%d-%d.pkl" % (n, am_file_stat.st_size, am_file_stat.st_mtime)
|
pkl = "%s-%d-%d.pkl" % (n, am_file_stat.st_size, am_file_stat.st_mtime)
|
||||||
|
|
||||||
with open_cachefile(pkl, "w", subdir="actionsmap") as f:
|
with open_cachefile(pkl, "wb", subdir="actionsmap") as f:
|
||||||
pickle.dump(actionsmaps[n], f)
|
pickle.dump(actionsmaps[n], f)
|
||||||
|
|
||||||
return actionsmaps
|
return actionsmaps
|
||||||
|
|
|
@ -161,7 +161,7 @@ class BaseAuthenticator(object):
|
||||||
"""Store a session to be able to use it later to reauthenticate"""
|
"""Store a session to be able to use it later to reauthenticate"""
|
||||||
|
|
||||||
# We store a hash of the session_id and the session_token (the token is assumed to be secret)
|
# We store a hash of the session_id and the session_token (the token is assumed to be secret)
|
||||||
to_hash = "{id}:{token}".format(id=session_id, token=session_token)
|
to_hash = "{id}:{token}".format(id=session_id, token=session_token).encode()
|
||||||
hash_ = hashlib.sha256(to_hash).hexdigest()
|
hash_ = hashlib.sha256(to_hash).hexdigest()
|
||||||
with self._open_sessionfile(session_id, "w") as f:
|
with self._open_sessionfile(session_id, "w") as f:
|
||||||
f.write(hash_)
|
f.write(hash_)
|
||||||
|
@ -194,7 +194,7 @@ class BaseAuthenticator(object):
|
||||||
# re-hash the {id}:{token} and compare it to the previously stored hash for this session_id ...
|
# re-hash the {id}:{token} and compare it to the previously stored hash for this session_id ...
|
||||||
# It it matches, then the user is authenticated. Otherwise, the token is invalid.
|
# It it matches, then the user is authenticated. Otherwise, the token is invalid.
|
||||||
#
|
#
|
||||||
to_hash = "{id}:{token}".format(id=session_id, token=session_token)
|
to_hash = "{id}:{token}".format(id=session_id, token=session_token).encode()
|
||||||
hash_ = hashlib.sha256(to_hash).hexdigest()
|
hash_ = hashlib.sha256(to_hash).hexdigest()
|
||||||
|
|
||||||
if not hmac.compare_digest(hash_, stored_hash):
|
if not hmac.compare_digest(hash_, stored_hash):
|
||||||
|
|
|
@ -100,13 +100,10 @@ class Translator(object):
|
||||||
try:
|
try:
|
||||||
return (
|
return (
|
||||||
self._translations[self.locale][key]
|
self._translations[self.locale][key]
|
||||||
.encode("utf-8")
|
|
||||||
.format(*args, **kwargs)
|
.format(*args, **kwargs)
|
||||||
)
|
)
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
unformatted_string = self._translations[self.locale][key].encode(
|
unformatted_string = self._translations[self.locale][key]
|
||||||
"utf-8"
|
|
||||||
)
|
|
||||||
error_message = (
|
error_message = (
|
||||||
"Failed to format translated string '%s': '%s' with arguments '%s' and '%s, raising error: %s(%s) (don't panic this is just a warning)"
|
"Failed to format translated string '%s': '%s' with arguments '%s' and '%s, raising error: %s(%s) (don't panic this is just a warning)"
|
||||||
% (key, unformatted_string, args, kwargs, e.__class__.__name__, e)
|
% (key, unformatted_string, args, kwargs, e.__class__.__name__, e)
|
||||||
|
@ -176,8 +173,8 @@ class Translator(object):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open("%s/%s.json" % (self.locale_dir, locale), "r") as f:
|
with open("%s/%s.json" % (self.locale_dir, locale), "r", encoding='utf-8') as f:
|
||||||
j = json.load(f, "utf-8")
|
j = json.load(f)
|
||||||
except IOError:
|
except IOError:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -478,7 +478,7 @@ class ExtendedArgumentParser(argparse.ArgumentParser):
|
||||||
|
|
||||||
def dequeue_callbacks(self, namespace):
|
def dequeue_callbacks(self, namespace):
|
||||||
queue = self._get_callbacks_queue(namespace, False)
|
queue = self._get_callbacks_queue(namespace, False)
|
||||||
for _i in xrange(len(queue)):
|
for _i in range(len(queue)):
|
||||||
c, v = queue.popleft()
|
c, v = queue.popleft()
|
||||||
# FIXME: break dequeue if callback returns
|
# FIXME: break dequeue if callback returns
|
||||||
c.execute(namespace, v)
|
c.execute(namespace, v)
|
||||||
|
|
|
@ -92,7 +92,7 @@ def plain_print_dict(d, depth=0):
|
||||||
print("{}{}".format("#" * (depth + 1), k))
|
print("{}{}".format("#" * (depth + 1), k))
|
||||||
plain_print_dict(v, depth + 1)
|
plain_print_dict(v, depth + 1)
|
||||||
else:
|
else:
|
||||||
if isinstance(d, unicode):
|
if isinstance(d, str):
|
||||||
d = d.encode("utf-8")
|
d = d.encode("utf-8")
|
||||||
print(d)
|
print(d)
|
||||||
|
|
||||||
|
@ -154,13 +154,13 @@ def pretty_print_dict(d, depth=0):
|
||||||
elif isinstance(value, dict):
|
elif isinstance(value, dict):
|
||||||
pretty_print_dict({key: value}, depth + 1)
|
pretty_print_dict({key: value}, depth + 1)
|
||||||
else:
|
else:
|
||||||
if isinstance(value, unicode):
|
if isinstance(value, str):
|
||||||
value = value.encode("utf-8")
|
value = value.encode("utf-8")
|
||||||
elif isinstance(v, date):
|
elif isinstance(v, date):
|
||||||
v = pretty_date(v)
|
v = pretty_date(v)
|
||||||
print("{:s}- {}".format(" " * (depth + 1), value))
|
print("{:s}- {}".format(" " * (depth + 1), value))
|
||||||
else:
|
else:
|
||||||
if isinstance(v, unicode):
|
if isinstance(v, str):
|
||||||
v = v.encode("utf-8")
|
v = v.encode("utf-8")
|
||||||
elif isinstance(v, date):
|
elif isinstance(v, date):
|
||||||
v = pretty_date(v)
|
v = pretty_date(v)
|
||||||
|
@ -494,7 +494,7 @@ class Interface(BaseInterface):
|
||||||
if is_password:
|
if is_password:
|
||||||
prompt = lambda m: getpass.getpass(colorize(m18n.g("colon", m), color))
|
prompt = lambda m: getpass.getpass(colorize(m18n.g("colon", m), color))
|
||||||
else:
|
else:
|
||||||
prompt = lambda m: raw_input(colorize(m18n.g("colon", m), color))
|
prompt = lambda m: input(colorize(m18n.g("colon", m), color))
|
||||||
value = prompt(message)
|
value = prompt(message)
|
||||||
|
|
||||||
if confirm:
|
if confirm:
|
||||||
|
@ -510,7 +510,7 @@ class Interface(BaseInterface):
|
||||||
Handle the core.MoulinetteSignals.display signal.
|
Handle the core.MoulinetteSignals.display signal.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if isinstance(message, unicode):
|
if isinstance(message, str):
|
||||||
message = message.encode("utf-8")
|
message = message.encode("utf-8")
|
||||||
if style == "success":
|
if style == "success":
|
||||||
print("{} {}".format(colorize(m18n.g("success"), "green"), message))
|
print("{} {}".format(colorize(m18n.g("success"), "green"), message))
|
||||||
|
|
|
@ -22,7 +22,7 @@ def read_file(file_path):
|
||||||
Keyword argument:
|
Keyword argument:
|
||||||
file_path -- Path to the text file
|
file_path -- Path to the text file
|
||||||
"""
|
"""
|
||||||
assert isinstance(file_path, basestring), (
|
assert isinstance(file_path, str), (
|
||||||
"Error: file_path '%s' should be a string but is of type '%s' instead"
|
"Error: file_path '%s' should be a string but is of type '%s' instead"
|
||||||
% (file_path, type(file_path))
|
% (file_path, type(file_path))
|
||||||
)
|
)
|
||||||
|
@ -37,7 +37,7 @@ def read_file(file_path):
|
||||||
file_content = f.read()
|
file_content = f.read()
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
raise MoulinetteError("cannot_open_file", file=file_path, error=str(e))
|
raise MoulinetteError("cannot_open_file", file=file_path, error=str(e))
|
||||||
except Exception:
|
except Exception as e:
|
||||||
raise MoulinetteError(
|
raise MoulinetteError(
|
||||||
"unknown_error_reading_file", file=file_path, error=str(e)
|
"unknown_error_reading_file", file=file_path, error=str(e)
|
||||||
)
|
)
|
||||||
|
@ -153,7 +153,7 @@ def write_to_file(file_path, data, file_mode="w"):
|
||||||
file_mode -- Mode used when writing the file. Option meant to be used
|
file_mode -- Mode used when writing the file. Option meant to be used
|
||||||
by append_to_file to avoid duplicating the code of this function.
|
by append_to_file to avoid duplicating the code of this function.
|
||||||
"""
|
"""
|
||||||
assert isinstance(data, basestring) or isinstance(data, list), (
|
assert isinstance(data, str) or isinstance(data, list), (
|
||||||
"Error: data '%s' should be either a string or a list but is of type '%s'"
|
"Error: data '%s' should be either a string or a list but is of type '%s'"
|
||||||
% (data, type(data))
|
% (data, type(data))
|
||||||
)
|
)
|
||||||
|
@ -166,9 +166,9 @@ def write_to_file(file_path, data, file_mode="w"):
|
||||||
)
|
)
|
||||||
|
|
||||||
# If data is a list, check elements are strings and build a single string
|
# If data is a list, check elements are strings and build a single string
|
||||||
if not isinstance(data, basestring):
|
if not isinstance(data, str):
|
||||||
for element in data:
|
for element in data:
|
||||||
assert isinstance(element, basestring), (
|
assert isinstance(element, str), (
|
||||||
"Error: element '%s' should be a string but is of type '%s' instead"
|
"Error: element '%s' should be a string but is of type '%s' instead"
|
||||||
% (element, type(element))
|
% (element, type(element))
|
||||||
)
|
)
|
||||||
|
@ -205,7 +205,7 @@ def write_to_json(file_path, data):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Assumptions
|
# Assumptions
|
||||||
assert isinstance(file_path, basestring), (
|
assert isinstance(file_path, str), (
|
||||||
"Error: file_path '%s' should be a string but is of type '%s' instead"
|
"Error: file_path '%s' should be a string but is of type '%s' instead"
|
||||||
% (file_path, type(file_path))
|
% (file_path, type(file_path))
|
||||||
)
|
)
|
||||||
|
@ -240,7 +240,7 @@ def write_to_yaml(file_path, data):
|
||||||
data -- The data to write (must be a dict or a list)
|
data -- The data to write (must be a dict or a list)
|
||||||
"""
|
"""
|
||||||
# Assumptions
|
# Assumptions
|
||||||
assert isinstance(file_path, basestring)
|
assert isinstance(file_path, str)
|
||||||
assert isinstance(data, dict) or isinstance(data, list)
|
assert isinstance(data, dict) or isinstance(data, list)
|
||||||
assert not os.path.isdir(file_path)
|
assert not os.path.isdir(file_path)
|
||||||
assert os.path.isdir(os.path.dirname(file_path))
|
assert os.path.isdir(os.path.dirname(file_path))
|
||||||
|
@ -313,14 +313,14 @@ def chown(path, uid=None, gid=None, recursive=False):
|
||||||
raise ValueError("either uid or gid argument is required")
|
raise ValueError("either uid or gid argument is required")
|
||||||
|
|
||||||
# Retrieve uid/gid
|
# Retrieve uid/gid
|
||||||
if isinstance(uid, basestring):
|
if isinstance(uid, str):
|
||||||
try:
|
try:
|
||||||
uid = getpwnam(uid).pw_uid
|
uid = getpwnam(uid).pw_uid
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise MoulinetteError("unknown_user", user=uid)
|
raise MoulinetteError("unknown_user", user=uid)
|
||||||
elif uid is None:
|
elif uid is None:
|
||||||
uid = -1
|
uid = -1
|
||||||
if isinstance(gid, basestring):
|
if isinstance(gid, str):
|
||||||
try:
|
try:
|
||||||
gid = grp.getgrnam(gid).gr_gid
|
gid = grp.getgrnam(gid).gr_gid
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|
|
@ -59,6 +59,6 @@ def download_json(url, timeout=30, expected_status_code=200):
|
||||||
try:
|
try:
|
||||||
loaded_json = json.loads(text)
|
loaded_json = json.loads(text)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raise MoulinetteError("corrupted_json", ressource=url, error=e)
|
raise MoulinetteError("corrupted_json", ressource=url, error=str(e))
|
||||||
|
|
||||||
return loaded_json
|
return loaded_json
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from multiprocessing.process import Process
|
from multiprocessing.process import BaseProcess as Process
|
||||||
from multiprocessing.queues import SimpleQueue
|
from multiprocessing.queues import SimpleQueue
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -47,9 +47,9 @@ def searchf(pattern, path, count=0, flags=re.MULTILINE):
|
||||||
content by using the search function.
|
content by using the search function.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
with open(path, "r+") as f:
|
with open(path, "rb+") as f:
|
||||||
data = mmap.mmap(f.fileno(), 0)
|
data = mmap.mmap(f.fileno(), 0)
|
||||||
match = search(pattern, data, count, flags)
|
match = search(pattern, data.read().decode(), count, flags)
|
||||||
data.close()
|
data.close()
|
||||||
return match
|
return match
|
||||||
|
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -27,7 +27,7 @@ setup(name='Moulinette',
|
||||||
license='AGPL',
|
license='AGPL',
|
||||||
packages=find_packages(exclude=['test']),
|
packages=find_packages(exclude=['test']),
|
||||||
data_files=[(LOCALES_DIR, locale_files)],
|
data_files=[(LOCALES_DIR, locale_files)],
|
||||||
python_requires='==2.7.*',
|
python_requires='>=3.5',
|
||||||
install_requires=[
|
install_requires=[
|
||||||
'argcomplete',
|
'argcomplete',
|
||||||
'psutil',
|
'psutil',
|
||||||
|
|
|
@ -129,7 +129,7 @@ def moulinette_webapi(moulinette):
|
||||||
def test_file(tmp_path):
|
def test_file(tmp_path):
|
||||||
test_text = "foo\nbar\n"
|
test_text = "foo\nbar\n"
|
||||||
test_file = tmp_path / "test.txt"
|
test_file = tmp_path / "test.txt"
|
||||||
test_file.write_bytes(test_text)
|
test_file.write_bytes(test_text.encode())
|
||||||
return test_file
|
return test_file
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ def test_file(tmp_path):
|
||||||
def test_json(tmp_path):
|
def test_json(tmp_path):
|
||||||
test_json = json.dumps({"foo": "bar"})
|
test_json = json.dumps({"foo": "bar"})
|
||||||
test_file = tmp_path / "test.json"
|
test_file = tmp_path / "test.json"
|
||||||
test_file.write_bytes(test_json)
|
test_file.write_bytes(test_json.encode())
|
||||||
return test_file
|
return test_file
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,9 @@ def test_read_file_missing_file():
|
||||||
def test_read_file_cannot_read_ioerror(test_file, mocker):
|
def test_read_file_cannot_read_ioerror(test_file, mocker):
|
||||||
error = "foobar"
|
error = "foobar"
|
||||||
|
|
||||||
with mocker.patch("__builtin__.open", side_effect=IOError(error)):
|
mocker.patch("builtins.open", side_effect=IOError(error))
|
||||||
with pytest.raises(MoulinetteError) as exception:
|
with pytest.raises(MoulinetteError) as exception:
|
||||||
read_file(str(test_file))
|
read_file(str(test_file))
|
||||||
|
|
||||||
translation = m18n.g("cannot_open_file", file=str(test_file), error=error)
|
translation = m18n.g("cannot_open_file", file=str(test_file), error=error)
|
||||||
expected_msg = translation.format(file=str(test_file), error=error)
|
expected_msg = translation.format(file=str(test_file), error=error)
|
||||||
|
@ -51,9 +51,9 @@ def test_read_json(test_json):
|
||||||
def test_read_json_cannot_read(test_json, mocker):
|
def test_read_json_cannot_read(test_json, mocker):
|
||||||
error = "foobar"
|
error = "foobar"
|
||||||
|
|
||||||
with mocker.patch("json.loads", side_effect=ValueError(error)):
|
mocker.patch("json.loads", side_effect=ValueError(error))
|
||||||
with pytest.raises(MoulinetteError) as exception:
|
with pytest.raises(MoulinetteError) as exception:
|
||||||
read_json(str(test_json))
|
read_json(str(test_json))
|
||||||
|
|
||||||
translation = m18n.g("corrupted_json", ressource=str(test_json), error=error)
|
translation = m18n.g("corrupted_json", ressource=str(test_json), error=error)
|
||||||
expected_msg = translation.format(ressource=str(test_json), error=error)
|
expected_msg = translation.format(ressource=str(test_json), error=error)
|
||||||
|
@ -77,9 +77,9 @@ def test_write_to_new_file(tmp_path):
|
||||||
def test_write_to_existing_file_bad_perms(test_file, mocker):
|
def test_write_to_existing_file_bad_perms(test_file, mocker):
|
||||||
error = "foobar"
|
error = "foobar"
|
||||||
|
|
||||||
with mocker.patch("__builtin__.open", side_effect=IOError(error)):
|
mocker.patch("builtins.open", side_effect=IOError(error))
|
||||||
with pytest.raises(MoulinetteError) as exception:
|
with pytest.raises(MoulinetteError) as exception:
|
||||||
write_to_file(str(test_file), "yolo\nswag")
|
write_to_file(str(test_file), "yolo\nswag")
|
||||||
|
|
||||||
translation = m18n.g("cannot_write_file", file=str(test_file), error=error)
|
translation = m18n.g("cannot_write_file", file=str(test_file), error=error)
|
||||||
expected_msg = translation.format(file=str(test_file), error=error)
|
expected_msg = translation.format(file=str(test_file), error=error)
|
||||||
|
@ -142,9 +142,9 @@ def text_write_list_to_json(tmp_path):
|
||||||
def test_write_to_json_bad_perms(test_json, mocker):
|
def test_write_to_json_bad_perms(test_json, mocker):
|
||||||
error = "foobar"
|
error = "foobar"
|
||||||
|
|
||||||
with mocker.patch("__builtin__.open", side_effect=IOError(error)):
|
mocker.patch("builtins.open", side_effect=IOError(error))
|
||||||
with pytest.raises(MoulinetteError) as exception:
|
with pytest.raises(MoulinetteError) as exception:
|
||||||
write_to_json(str(test_json), {"a": 1})
|
write_to_json(str(test_json), {"a": 1})
|
||||||
|
|
||||||
translation = m18n.g("cannot_write_file", file=str(test_json), error=error)
|
translation = m18n.g("cannot_write_file", file=str(test_json), error=error)
|
||||||
expected_msg = translation.format(file=str(test_json), error=error)
|
expected_msg = translation.format(file=str(test_json), error=error)
|
||||||
|
@ -165,9 +165,9 @@ def test_remove_file(test_file):
|
||||||
def test_remove_file_bad_perms(test_file, mocker):
|
def test_remove_file_bad_perms(test_file, mocker):
|
||||||
error = "foobar"
|
error = "foobar"
|
||||||
|
|
||||||
with mocker.patch("os.remove", side_effect=OSError(error)):
|
mocker.patch("os.remove", side_effect=OSError(error))
|
||||||
with pytest.raises(MoulinetteError) as exception:
|
with pytest.raises(MoulinetteError) as exception:
|
||||||
rm(str(test_file))
|
rm(str(test_file))
|
||||||
|
|
||||||
translation = m18n.g("error_removing", path=str(test_file), error=error)
|
translation = m18n.g("error_removing", path=str(test_file), error=error)
|
||||||
expected_msg = translation.format(path=str(test_file), error=error)
|
expected_msg = translation.format(path=str(test_file), error=error)
|
||||||
|
|
|
@ -18,4 +18,4 @@ def test_prependlines():
|
||||||
|
|
||||||
|
|
||||||
def test_random_ascii():
|
def test_random_ascii():
|
||||||
assert isinstance(random_ascii(length=2), unicode)
|
assert isinstance(random_ascii(length=2), str)
|
||||||
|
|
2
tox.ini
2
tox.ini
|
@ -1,6 +1,6 @@
|
||||||
[tox]
|
[tox]
|
||||||
envlist =
|
envlist =
|
||||||
py27
|
py35
|
||||||
lint
|
lint
|
||||||
docs
|
docs
|
||||||
skipdist = True
|
skipdist = True
|
||||||
|
|
Loading…
Reference in a new issue