Skip to content

Commit

Permalink
Merge pull request #59 from wildfoundry/py3-update
Browse files Browse the repository at this point in the history
Py3 update
  • Loading branch information
willmcgugan authored Feb 12, 2020
2 parents ac1e169 + d4ee5a3 commit 147e258
Show file tree
Hide file tree
Showing 13 changed files with 317 additions and 256 deletions.
13 changes: 7 additions & 6 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
#!/bin/bash

read -p "Build dataplicity agent from PyPi? " -n 1 -r
read -p "Build dataplicity agent v$(python dataplicity/_version.py) from PyPi? " -n 1 -r
echo
if [[ ! "$REPLY" =~ ^[Yy]$ ]]
then
exit 1
fi

mkdir -p bin
rm bin/dataplicity
virtualenv -qq .build -p Python2.7
rm -f bin/dataplicity
rm -rf .build
virtualenv -qq .build -p python3
source .build/bin/activate
pip -q install pex==1.2.13
pip -q install pex==2.1.1 subprocess32
echo building ./bin/dataplicity
pex dataplicity==0.4.34 --pre -r requirements.txt -o bin/dataplicity -m dataplicity.app:main
pex dataplicity==$(python dataplicity/_version.py) --pre --python-shebang="#!/usr/bin/env python" --python=$(which python2) --python=$(which python3) -r requirements.txt -o bin/dataplicity -m dataplicity.app:main
deactivate
echo built dataplicity agent v`./bin/dataplicity version`
echo built dataplicity agent v$(./bin/dataplicity version)
6 changes: 5 additions & 1 deletion dataplicity/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
__version__ = "0.4.34"
__version__ = "0.4.35"

if __name__ == "__main__":
# The build script uses this to extract the current version
print(__version__)
177 changes: 105 additions & 72 deletions dataplicity/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,112 +11,140 @@
from .client import Client
from .subcommands import run, version

log = logging.getLogger('app')
log = logging.getLogger("app")

# Map log levels on to integer values
_logging_level_names = {
'NOTSET': 0,
'DEBUG': 10,
'INFO': 20,
'WARN': 30,
'WARNING': 30,
'ERROR': 40,
'CRITICAL': 50
"NOTSET": 0,
"DEBUG": 10,
"INFO": 20,
"WARN": 30,
"WARNING": 30,
"ERROR": 40,
"CRITICAL": 50,
}


class App(object):
"""Dataplicty Agent command line interface."""
"""Dataplicity Agent command line interface."""

def __init__(self):
self.subcommands = {
name: cls(self)
for name, cls in subcommand.registry.items()
name: cls(self) for name, cls in subcommand.registry.items()
}

def _make_arg_parser(self):
"""Make an argument parse object."""
parser = argparse.ArgumentParser(
"dataplicity",
description=self.__doc__
)
parser = argparse.ArgumentParser("dataplicity", description=self.__doc__)

_version = "dataplicity agent v{}".format(__version__)
parser.add_argument('-v', '--version', action="version", version=_version,
help="Display version and exit")
parser.add_argument('--log-level', metavar='LEVEL', default='INFO',
help="Set log level (INFO or WARNING or ERROR or DEBUG)")
parser.add_argument('--log-file', metavar="PATH", default=None,
help="Set log file")
parser.add_argument('-d', '--debug', action="store_true", dest="debug", default=False,
help="Enables debug output")
parser.add_argument('-s', '--server-url', metavar="URL", dest="server_url", default=None,
help="URL of dataplicity.com api")
parser.add_argument('-m', '--m2m-url', metavar="WS URL", dest="m2m_url", default=None,
help="URL of m2m server (should start with ws:// or wss://")
parser.add_argument('-q', '--quiet', action="store_true", default=False,
help="Hide output")
parser.add_argument('--serial', dest='serial', metavar='SERIAL', default=None,
help='Set Dataplicity serial')
parser.add_argument('--auth', dest='auth_token', metavar='KEY', default=None,
help='Set Dataplicity auth token')

subparsers = parser.add_subparsers(title='available sub-commands',
dest="subcommand",
help="sub-command help")
parser.add_argument(
"-v",
"--version",
action="version",
version=_version,
help="Display version and exit",
)
parser.add_argument(
"--log-level",
metavar="LEVEL",
default="INFO",
help="Set log level (INFO or WARNING or ERROR or DEBUG)",
)
parser.add_argument(
"--log-file", metavar="PATH", default=None, help="Set log file"
)
parser.add_argument(
"-d",
"--debug",
action="store_true",
dest="debug",
default=False,
help="Enables debug output",
)
parser.add_argument(
"-s",
"--server-url",
metavar="URL",
dest="server_url",
default=None,
help="URL of dataplicity.com api",
)
parser.add_argument(
"-m",
"--m2m-url",
metavar="WS URL",
dest="m2m_url",
default=None,
help="URL of m2m server (should start with ws:// or wss://",
)
parser.add_argument(
"-q", "--quiet", action="store_true", default=False, help="Hide output"
)
parser.add_argument(
"--serial",
dest="serial",
metavar="SERIAL",
default=None,
help="Set Dataplicity serial",
)
parser.add_argument(
"--auth",
dest="auth_token",
metavar="KEY",
default=None,
help="Set Dataplicity auth token",
)

subparsers = parser.add_subparsers(
title="available sub-commands", dest="subcommand", help="sub-command help"
)

for name, _subcommand in self.subcommands.items():
subparser = subparsers.add_parser(
name,
help=_subcommand.help,
description=getattr(_subcommand, '__doc__', None)
description=getattr(_subcommand, "__doc__", None),
)
_subcommand.add_arguments(subparser)
return parser

def _init_logging(self):
"""Initialise logging."""
log_format = '%(asctime)s %(name)s\t: %(message)s'
log_level = 'CRITICAL' if self.args.quiet else self.args.log_level.upper()
log_format = "%(asctime)s %(name)s\t: %(message)s"
log_level = "CRITICAL" if self.args.quiet else self.args.log_level.upper()
try:
log_level_no = _logging_level_names[log_level]
except IndexError:
self.error('invalid log level')
self.error("invalid log level")

if self.args.log_file:
log_config = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simple': {
'class': 'logging.Formatter',
'format': log_format,
'datefmt': '[%d/%b/%Y %H:%M:%S]'
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"simple": {
"class": "logging.Formatter",
"format": log_format,
"datefmt": "[%d/%b/%Y %H:%M:%S]",
}
},
'handlers': {
'file': {
'level': log_level,
'class': 'logging.handlers.RotatingFileHandler',
'maxBytes': 5 * 1024 * 1024,
'backupCount': 5,
'filename': self.args.log_file,
'formatter': 'simple'
"handlers": {
"file": {
"level": log_level,
"class": "logging.handlers.RotatingFileHandler",
"maxBytes": 5 * 1024 * 1024,
"backupCount": 5,
"filename": self.args.log_file,
"formatter": "simple",
}
},
'loggers': {
'': {
'level': log_level,
'handlers': ['file'],
}
}
"loggers": {"": {"level": log_level, "handlers": ["file"]}},
}
logging.config.dictConfig(log_config)
else:
logging.basicConfig(
format=log_format,
datefmt="[%d/%b/%Y %H:%M:%S]",
level=log_level_no
format=log_format, datefmt="[%d/%b/%Y %H:%M:%S]", level=log_level_no
)

def make_client(self):
Expand All @@ -125,21 +153,26 @@ def make_client(self):
rpc_url=self.args.server_url,
m2m_url=self.args.m2m_url,
serial=self.args.serial,
auth_token=self.args.auth_token
auth_token=self.args.auth_token,
)
return client

def error(self, msg, code=-1):
"""Display error and exit app."""
log.critical('app exit ({%s}) code={%s}', msg, code)
sys.stderr.write(msg + '\n')
log.critical("app exit ({%s}) code={%s}", msg, code)
sys.stderr.write(msg + "\n")
sys.exit(code)

def run(self):
parser = self._make_arg_parser()
args = self.args = parser.parse_args(sys.argv[1:])

self._init_logging()
log.debug('ready')
log.debug("ready")

if args.subcommand is None:
parser.print_help()
return 1

subcommand = self.subcommands[args.subcommand]
subcommand.args = args
Expand All @@ -150,14 +183,14 @@ def run(self):
if self.args.debug:
raise
sys.stderr.write("(dataplicity {}) {}\n".format(__version__, e))
cmd = sys.argv[0].rsplit('/', 1)[-1]
debug_cmd = ' '.join([cmd, '--debug'] + sys.argv[1:])
cmd = sys.argv[0].rsplit("/", 1)[-1]
debug_cmd = " ".join([cmd, "--debug"] + sys.argv[1:])
sys.stderr.write("(run '{}' for a full traceback)\n".format(debug_cmd))
return -1


def main():
"""Dataplicity Agent entry point."""
return_code = App().run() or 0
log.debug('exit with code %s', return_code)
log.debug("exit with code %s", return_code)
sys.exit(return_code)
9 changes: 7 additions & 2 deletions dataplicity/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import platform
from threading import Event, Lock
import random
import sys
import time

from ._version import __version__
Expand Down Expand Up @@ -45,6 +46,8 @@ def _read(cls, path):
def _init(self):
try:
log.info("dataplicity %s", __version__)
log.info("python executable=%s", sys.executable)
log.info("python version=%s", sys.version.replace("\n", " "))
log.info("uname=%s", " ".join(platform.uname()))

self.remote = jsonrpc.JSONRPC(self.rpc_url)
Expand Down Expand Up @@ -293,7 +296,9 @@ def set_m2m_identity(self, identity):
auth_token=self.auth_token,
)
batch.call_with_id(
"associate_result", "m2m.associate", identity=identity or ""
"associate_result",
"m2m.associate",
identity=identity.decode("utf-8") or "",
)
# These methods may potentially throw JSONRPCErrors
batch.get_result("authenticate_result")
Expand All @@ -310,7 +315,7 @@ def set_m2m_identity(self, identity):
log.debug("set m2m identity failed, %s", e)
return None
except Exception as error:
log.error("unable to set m2m identity: %s", error)
log.error("unable to set m2m identity: %s", error, exc_info=False)
return None
else:
# If we made it here the server has acknowledged it received the identity
Expand Down
19 changes: 15 additions & 4 deletions dataplicity/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3

# Basic types and builtine
# Basic types and builtin
if PY2:
text_type = unicode
binary_type = str
string_types = (basestring,)
xrange = xrange
unichr = unichr
int_types = (int, long)
py2bytes = lambda s: s.encode('utf-8')
py2bytes = lambda s: s.encode("utf-8")
number_types = (int, long, float)
next_method_name = "next"
raw_input = raw_input
Expand Down Expand Up @@ -74,30 +74,40 @@
# For classes that convert to a unicode string, return unicode from __str__
# and decorate with this function
if PY2:

def implements_to_string(cls):
cls.__unicode__ = cls.__str__
cls.__str__ = lambda x: x.__unicode__().encode('utf-8')
cls.__str__ = lambda x: x.__unicode__().encode("utf-8")
return cls


else:
implements_to_string = lambda x: x

# To implement an iterator, call the next method __next__ and decorate the class
# with the following
if PY2:

def implements_iterator(cls):
cls.next = cls.__next__
del cls.__next__
return cls


else:
implements_iterator = lambda x: x

# If a class converts to a bool, call the method __bool__, and decorate with this function
if PY2:

def implements_bool(cls):
cls.__nonzero__ = cls.__bool__
del cls.__bool__
return cls


else:

def implements_bool(cls):
return cls

Expand All @@ -111,4 +121,5 @@ def __new__(cls, name, this_bases, d):
if this_bases is None:
return type.__new__(cls, name, (), d)
return meta(name, bases, d)
return metaclass('temporary_class', None, {})
return metaclass("temporary_class", None, {})

Loading

0 comments on commit 147e258

Please sign in to comment.