mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-30 00:00:11 +01:00
python: flake8 liniting
This commit is contained in:
parent
c7fd20e478
commit
f6ef7265ce
7 changed files with 177 additions and 142 deletions
|
@ -1,4 +1,3 @@
|
||||||
import os
|
|
||||||
from setuptools import setup, find_namespace_packages
|
from setuptools import setup, find_namespace_packages
|
||||||
from glob import glob
|
from glob import glob
|
||||||
|
|
||||||
|
@ -6,33 +5,33 @@ with open('README.md') as f:
|
||||||
long_description = f.read()
|
long_description = f.read()
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name = 'villas-node',
|
name='villas-node',
|
||||||
version = '0.10.0',
|
version='0.10.0',
|
||||||
author = 'Steffen Vogel',
|
author='Steffen Vogel',
|
||||||
author_email = 'acs-software@eonerc.rwth-aachen.de',
|
author_email='acs-software@eonerc.rwth-aachen.de',
|
||||||
description = 'Python-support for VILLASnode simulation-data gateway',
|
description='Python-support for VILLASnode simulation-data gateway',
|
||||||
license = 'GPL-3.0',
|
license='GPL-3.0',
|
||||||
keywords = 'simulation power system real-time villas',
|
keywords='simulation power system real-time villas',
|
||||||
url = 'https://git.rwth-aachen.de/acs/public/villas/VILLASnode',
|
url='https://git.rwth-aachen.de/acs/public/villas/VILLASnode',
|
||||||
packages = find_namespace_packages(include=['villas.*']),
|
packages=find_namespace_packages(include=['villas.*']),
|
||||||
long_description = long_description,
|
long_description=long_description,
|
||||||
long_description_content_type = 'text/markdown',
|
long_description_content_type='text/markdown',
|
||||||
classifiers = [
|
classifiers=[
|
||||||
'Development Status :: 4 - Beta',
|
'Development Status :: 4 - Beta',
|
||||||
'Topic :: Scientific/Engineering',
|
'Topic :: Scientific/Engineering',
|
||||||
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
|
'License :: OSI Approved :: '
|
||||||
|
'GNU General Public License v3 or later (GPLv3+)',
|
||||||
'Operating System :: MacOS :: MacOS X',
|
'Operating System :: MacOS :: MacOS X',
|
||||||
'Operating System :: Microsoft :: Windows',
|
'Operating System :: Microsoft :: Windows',
|
||||||
'Operating System :: POSIX :: Linux',
|
'Operating System :: POSIX :: Linux',
|
||||||
'Programming Language :: Python :: 3'
|
'Programming Language :: Python :: 3'
|
||||||
],
|
],
|
||||||
install_requires = [
|
install_requires=[
|
||||||
'requests',
|
'requests',
|
||||||
'linuxfd'
|
'linuxfd'
|
||||||
],
|
],
|
||||||
setup_requires = [
|
setup_requires=[
|
||||||
'm2r'
|
'm2r'
|
||||||
],
|
],
|
||||||
scripts = glob('bin/*')
|
scripts=glob('bin/*')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
from message import Message
|
from message import Message # noqa F401
|
||||||
from timestamp import Timestamp
|
from timestamp import Timestamp # noqa F401
|
||||||
|
|
|
@ -1,24 +1,30 @@
|
||||||
import .timestamp
|
import villas.human.timestamp as ts
|
||||||
|
from functools import total_ordering
|
||||||
|
|
||||||
|
|
||||||
|
@total_ordering
|
||||||
class Message:
|
class Message:
|
||||||
"""Parsing a VILLASnode sample from a file (not a UDP package!!)"""
|
"""Parsing a VILLASnode sample from a file (not a UDP package!!)"""
|
||||||
|
|
||||||
def __init__(self, ts, values, source = None):
|
def __init__(self, ts, values, source=None):
|
||||||
self.source = source
|
self.source = source
|
||||||
self.ts = ts
|
self.ts = ts
|
||||||
self.values = values
|
self.values = values
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def parse(self, line, source = None):
|
def parse(cls, line, source=None):
|
||||||
csv = line.split()
|
csv = line.split()
|
||||||
|
|
||||||
t = ts.Timestamp.parse(csv[0])
|
t = ts.Timestamp.parse(csv[0])
|
||||||
v = map(float, csv[1:])
|
v = map(float, csv[1:])
|
||||||
|
|
||||||
return Message(t, v, source)
|
return Message(t, v, source)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '%s %s' % (self.ts, " ".join(map(str, self.values)))
|
return '%s %s' % (self.ts, " ".join(map(str, self.values)))
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __eq__(self, other):
|
||||||
return cmp(self.ts, other.ts)
|
return self.ts == other.ts
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return self.ts < other.ts
|
||||||
|
|
|
@ -1,46 +1,54 @@
|
||||||
import re
|
import re
|
||||||
|
from functools import total_ordering
|
||||||
|
|
||||||
|
|
||||||
|
@total_ordering
|
||||||
class Timestamp:
|
class Timestamp:
|
||||||
"""Parsing the VILLASnode human-readable timestamp format"""
|
"""Parsing the VILLASnode human-readable timestamp format"""
|
||||||
|
|
||||||
def __init__(self, seconds = 0, nanoseconds = None, offset = None, sequence = None):
|
def __init__(self, seconds=0, nanoseconds=None,
|
||||||
self.seconds = seconds
|
offset=None, sequence=None):
|
||||||
self.nanoseconds = nanoseconds
|
self.seconds = seconds
|
||||||
self.offset = offset
|
self.nanoseconds = nanoseconds
|
||||||
self.sequence = sequence
|
self.offset = offset
|
||||||
|
self.sequence = sequence
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def parse(self, ts):
|
def parse(cls, ts):
|
||||||
m = re.match('(\d+)(?:\.(\d+))?([-+]\d+(?:\.\d+)?(?:e[+-]?\d+)?)?(?:\((\d+)\))?', ts)
|
m = re.match(r'(\d+)(?:\.(\d+))?([-+]\d+(?:\.\d+)?'
|
||||||
|
r'(?:e[+-]?\d+)?)?(?:\((\d+)\))?', ts)
|
||||||
|
|
||||||
seconds = int(m.group(1)); # Mandatory
|
seconds = int(m.group(1)) # Mandatory
|
||||||
nanoseconds = int(m.group(2)) if m.group(2) else None
|
nanoseconds = int(m.group(2)) if m.group(2) else None
|
||||||
offset = float(m.group(3)) if m.group(3) else None
|
offset = float(m.group(3)) if m.group(3) else None
|
||||||
sequence = int(m.group(4)) if m.group(4) else None
|
sequence = int(m.group(4)) if m.group(4) else None
|
||||||
|
|
||||||
return Timestamp(seconds, nanoseconds, offset, sequence)
|
return Timestamp(seconds, nanoseconds, offset, sequence)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
str = "%u" % (self.seconds)
|
str = "%u" % (self.seconds)
|
||||||
|
|
||||||
if self.nanoseconds is not None:
|
if self.nanoseconds is not None:
|
||||||
str += ".%09u" % self.nanoseconds
|
str += ".%09u" % self.nanoseconds
|
||||||
if self.offset is not None:
|
if self.offset is not None:
|
||||||
str += "+%u" % self.offset
|
str += "+%u" % self.offset
|
||||||
if self.sequence is not None:
|
if self.sequence is not None:
|
||||||
str += "(%u)" % self.sequence
|
str += "(%u)" % self.sequence
|
||||||
|
|
||||||
return str
|
return str
|
||||||
|
|
||||||
def __float__(self):
|
def __float__(self):
|
||||||
sum = float(self.seconds)
|
sum = float(self.seconds)
|
||||||
|
|
||||||
if self.nanoseconds is not None:
|
if self.nanoseconds is not None:
|
||||||
sum += self.nanoseconds * 1e-9
|
sum += self.nanoseconds * 1e-9
|
||||||
if self.offset is not None:
|
if self.offset is not None:
|
||||||
sum += self.offset
|
sum += self.offset
|
||||||
|
|
||||||
return sum
|
return sum
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __eg__(self, other):
|
||||||
return cmp(float(self), float(other))
|
return float(self) == float(other)
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return float(self) < float(other)
|
||||||
|
|
|
@ -7,6 +7,7 @@ from threading import Thread
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class RecvThread(Thread):
|
class RecvThread(Thread):
|
||||||
|
|
||||||
def __init__(self, cb):
|
def __init__(self, cb):
|
||||||
|
@ -78,4 +79,4 @@ def communicate(rate, recv_cb=None, send_cb=None, wait=True):
|
||||||
logger.info('Received Ctrl+C. Stopping send/recv threads')
|
logger.info('Received Ctrl+C. Stopping send/recv threads')
|
||||||
|
|
||||||
# Threads are daemon threads
|
# Threads are daemon threads
|
||||||
# and therefore killed with program termination
|
# and therefore killed with program termination
|
||||||
|
|
|
@ -9,9 +9,12 @@ import datetime
|
||||||
|
|
||||||
LOGGER = logging.getLogger('villas.node')
|
LOGGER = logging.getLogger('villas.node')
|
||||||
|
|
||||||
|
|
||||||
class Node(object):
|
class Node(object):
|
||||||
|
|
||||||
def __init__(self, log_filename = None, config_filename = None, config = { }, api = 'http://localhost:8080', executable = 'villas-node', **kwargs):
|
def __init__(self, log_filename=None, config_filename=None,
|
||||||
|
config={}, api='http://localhost:8080',
|
||||||
|
executable='villas-node', **kwargs):
|
||||||
self.config = config
|
self.config = config
|
||||||
self.config_filename = config_filename
|
self.config_filename = config_filename
|
||||||
self.log_filename = log_filename
|
self.log_filename = log_filename
|
||||||
|
@ -21,7 +24,8 @@ class Node(object):
|
||||||
self.child = None
|
self.child = None
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.config_file = tempfile.NamedTemporaryFile(mode='w+', suffix='.json')
|
self.config_file = tempfile.NamedTemporaryFile(mode='w+',
|
||||||
|
suffix='.json')
|
||||||
|
|
||||||
if self.config_filename:
|
if self.config_filename:
|
||||||
with open(self.config_filename) as f:
|
with open(self.config_filename) as f:
|
||||||
|
@ -33,13 +37,16 @@ class Node(object):
|
||||||
|
|
||||||
if self.log_filename is None:
|
if self.log_filename is None:
|
||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
self.log_filename = now.strftime('villas-node_%Y-%m-%d_%H-%M-%S.log')
|
self.log_filename = now.strftime(
|
||||||
|
'villas-node_%Y-%m-%d_%H-%M-%S.log')
|
||||||
|
|
||||||
self.log = open(self.log_filename, 'w+')
|
self.log = open(self.log_filename, 'w+')
|
||||||
|
|
||||||
LOGGER.info("Starting VILLASnode instance with config: %s", self.config_file.name)
|
LOGGER.info("Starting VILLASnode instance with config: %s",
|
||||||
|
self.config_file.name)
|
||||||
|
|
||||||
self.child = subprocess.Popen([self.executable, self.config_file.name], stdout=self.log, stderr=self.log)
|
self.child = subprocess.Popen([self.executable, self.config_file.name],
|
||||||
|
stdout=self.log, stderr=self.log)
|
||||||
|
|
||||||
def pause(self):
|
def pause(self):
|
||||||
LOGGER.info("Pausing VILLASnode instance")
|
LOGGER.info("Pausing VILLASnode instance")
|
||||||
|
@ -74,10 +81,10 @@ class Node(object):
|
||||||
def paths(self):
|
def paths(self):
|
||||||
return self.request('paths')['response']
|
return self.request('paths')['response']
|
||||||
|
|
||||||
def request(self, action, req = None):
|
def request(self, action, req=None):
|
||||||
body = {
|
body = {
|
||||||
'action' : action,
|
'action': action,
|
||||||
'id' : str(uuid.uuid4())
|
'id': str(uuid.uuid4())
|
||||||
}
|
}
|
||||||
|
|
||||||
if req is not None:
|
if req is not None:
|
||||||
|
|
|
@ -1,93 +1,107 @@
|
||||||
import re
|
import re
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from functools import total_ordering
|
||||||
|
|
||||||
|
|
||||||
|
@total_ordering
|
||||||
class Timestamp:
|
class Timestamp:
|
||||||
"""Parsing the VILLASnode human-readable timestamp format"""
|
"""Parsing the VILLASnode human-readable timestamp format"""
|
||||||
|
|
||||||
def __init__(self, seconds=None, nanoseconds=None, offset=None, sequence=None):
|
def __init__(self, seconds=None, nanoseconds=None,
|
||||||
self.seconds = seconds
|
offset=None, sequence=None):
|
||||||
self.nanoseconds = nanoseconds
|
self.seconds = seconds
|
||||||
self.offset = offset
|
self.nanoseconds = nanoseconds
|
||||||
self.sequence = sequence
|
self.offset = offset
|
||||||
|
self.sequence = sequence
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def now(self, offset=None, sequence=None):
|
def now(cls, offset=None, sequence=None):
|
||||||
n = datetime.utcnow()
|
n = datetime.utcnow()
|
||||||
|
|
||||||
secs = int(n.timestamp())
|
secs = int(n.timestamp())
|
||||||
nsecs = 1000 * n.microsecond
|
nsecs = 1000 * n.microsecond
|
||||||
|
|
||||||
return Timestamp(seconds=secs, nanoseconds=nsecs, offset=offset, sequence=sequence)
|
return Timestamp(seconds=secs, nanoseconds=nsecs,
|
||||||
|
offset=offset, sequence=sequence)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def parse(self, ts):
|
def parse(cls, ts):
|
||||||
m = re.match('(\d+)(?:\.(\d+))?([-+]\d+(?:\.\d+)?(?:e[+-]?\d+)?)?(?:\((\d+)\))?', ts)
|
m = re.match(r'(\d+)(?:\.(\d+))?([-+]\d+(?:\.\d+)?'
|
||||||
|
r'(?:e[+-]?\d+)?)?(?:\((\d+)\))?', ts)
|
||||||
|
|
||||||
seconds = int(m.group(1)); # Mandatory
|
seconds = int(m.group(1)) # Mandatory
|
||||||
nanoseconds = int(m.group(2)) if m.group(2) else None
|
nanoseconds = int(m.group(2)) if m.group(2) else None
|
||||||
offset = float(m.group(3)) if m.group(3) else None
|
offset = float(m.group(3)) if m.group(3) else None
|
||||||
sequence = int(m.group(4)) if m.group(4) else None
|
sequence = int(m.group(4)) if m.group(4) else None
|
||||||
|
|
||||||
return Timestamp(seconds, nanoseconds, offset, sequence)
|
return Timestamp(seconds, nanoseconds, offset, sequence)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
str = "%u" % (self.seconds)
|
str = "%u" % (self.seconds)
|
||||||
|
|
||||||
if self.nanoseconds is not None:
|
if self.nanoseconds is not None:
|
||||||
str += ".%09u" % self.nanoseconds
|
str += ".%09u" % self.nanoseconds
|
||||||
if self.offset is not None:
|
if self.offset is not None:
|
||||||
str += "+%u" % self.offset
|
str += "+%u" % self.offset
|
||||||
if self.sequence is not None:
|
if self.sequence is not None:
|
||||||
str += "(%u)" % self.sequence
|
str += "(%u)" % self.sequence
|
||||||
|
|
||||||
return str
|
return str
|
||||||
|
|
||||||
def __float__(self):
|
def __float__(self):
|
||||||
sum = float(self.seconds)
|
sum = float(self.seconds)
|
||||||
|
|
||||||
if self.nanoseconds is not None:
|
if self.nanoseconds is not None:
|
||||||
sum += self.nanoseconds * 1e-9
|
sum += self.nanoseconds * 1e-9
|
||||||
if self.offset is not None:
|
if self.offset is not None:
|
||||||
sum += self.offset
|
sum += self.offset
|
||||||
|
|
||||||
return sum
|
return sum
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __eq__(self, other):
|
||||||
return cmp(float(self), float(other))
|
return float(self) == float(other)
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return float(self) < float(other)
|
||||||
|
|
||||||
|
|
||||||
|
@total_ordering
|
||||||
class Sample:
|
class Sample:
|
||||||
"""Parsing a VILLASnode sample from a file (not a UDP package!!)"""
|
"""Parsing a VILLASnode sample from a file (not a UDP package!!)"""
|
||||||
|
|
||||||
def __init__(self, ts, values):
|
def __init__(self, ts, values):
|
||||||
self.ts = ts
|
self.ts = ts
|
||||||
self.values = values
|
self.values = values
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def parse(self, line):
|
def parse(cls, line):
|
||||||
csv = line.split()
|
csv = line.split()
|
||||||
|
|
||||||
ts = Timestamp.parse(csv[0])
|
ts = Timestamp.parse(csv[0])
|
||||||
vs = [ ]
|
vs = []
|
||||||
|
|
||||||
for value in csv[1:]:
|
for value in csv[1:]:
|
||||||
try:
|
try:
|
||||||
v = float(value)
|
v = float(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
value = value.lower()
|
value = value.lower()
|
||||||
try:
|
try:
|
||||||
v = complex(value)
|
v = complex(value)
|
||||||
except:
|
except Exception:
|
||||||
if value.endswith('i'):
|
if value.endswith('i'):
|
||||||
v = complex(value.replace('i', 'j'))
|
v = complex(value.replace('i', 'j'))
|
||||||
else:
|
else:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
|
|
||||||
vs.append(v)
|
vs.append(v)
|
||||||
|
|
||||||
return Sample(ts, vs)
|
return Sample(ts, vs)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '%s %s' % (self.ts, " ".join(map(str, self.values)))
|
return '%s %s' % (self.ts, " ".join(map(str, self.values)))
|
||||||
|
|
||||||
def __cmp__(self, other):
|
def __eq__(self, other):
|
||||||
return cmp(self.ts, other.ts)
|
return self.ts == other.ts
|
||||||
|
|
||||||
|
def __lt__(self, other):
|
||||||
|
return self.ts < other.ts
|
||||||
|
|
Loading…
Add table
Reference in a new issue