1
0
Fork 0
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:
Steffen Vogel 2020-06-07 23:24:21 +02:00
parent c7fd20e478
commit f6ef7265ce
7 changed files with 177 additions and 142 deletions

View file

@ -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/*')
) )

View file

@ -1,2 +1,2 @@
from message import Message from message import Message # noqa F401
from timestamp import Timestamp from timestamp import Timestamp # noqa F401

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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:

View file

@ -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