diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | pyinfluxtools/__init__.py | 143 | ||||
-rw-r--r-- | setup.py | 24 |
3 files changed, 168 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..72723e5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*pyc diff --git a/pyinfluxtools/__init__.py b/pyinfluxtools/__init__.py new file mode 100644 index 0000000..74ec19a --- /dev/null +++ b/pyinfluxtools/__init__.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +import re + + +class WriteRequest(object): + @staticmethod + def parse(lines): + """ + Parse multiple Write objects separeted by new-line character. + + >>> lines = [] + >>> lines += ['cpu'] + >>> lines += ['cpu,host=serverA,region=us-west'] + >>> lines += ['cpu,host=serverA,region=us-west field1=1,field2=2'] + >>> lines += ['cpu,host=serverA,region=us-west field1=1,field2=2 1234'] + >>> print("\\n".join(map(str, WriteRequest.parse("\\n".join(lines))))) + cpu + cpu,host=serverA,region=us-west + cpu,host=serverA,region=us-west field1=1,field2=2 + cpu,host=serverA,region=us-west field1=1,field2=2 1234 + """ + writes = map(Write.parse, lines.split("\n")) + return list(writes) + + @staticmethod + def parseFile(file): + for line in file.readlines(): + yield Write.parse(line) + + +class Write(object): + def __init__(self, key, tags, fields, timestamp): + self.key = key + self.tags = tags + self.fields = fields + self.timestamp = timestamp + + @staticmethod + def parse(line): + """ + Parse a line from the POST request into a Write object. + + >>> Write.parse('cpu') + <Write key=cpu tags=None fields=None timestamp=None> + >>> print(Write.parse('cpu')) + cpu + + >>> Write.parse('cpu,host=serverA,region=us-west') + <Write key=cpu tags=[('host', 'serverA'), ('region', 'us-west')] fields=None timestamp=None> + >>> print(Write.parse('cpu,host=serverA,region=us-west')) + cpu,host=serverA,region=us-west + + >>> Write.parse('cpu\\,01,host=serverA,region=us-west') + <Write key=cpu,01 tags=[('host', 'serverA'), ('region', 'us-west')] fields=None timestamp=None> + >>> print(Write.parse('cpu\,01,host=serverA,region=us-west')) + cpu\,01,host=serverA,region=us-west + + >>> Write.parse('cpu,host=server\\ A,region=us\\ west') + <Write key=cpu tags=[('host', 'server A'), ('region', 'us west')] fields=None timestamp=None> + >>> print(Write.parse('cpu,host=server\\ A,region=us\\ west')) + cpu,host=server\ A,region=us\ west + + >>> Write.parse('cpu,ho\=st=server\ A,region=us\ west') + <Write key=cpu tags=[('ho=st', 'server A'), ('region', 'us west')] fields=None timestamp=None> + >>> print(Write.parse('cpu,ho\=st=server\ A,region=us\ west')) + cpu,ho\=st=server\ A,region=us\ west + + >>> print(Write.parse('cpu,ho\=st=server\ A field=123')) + cpu,ho\=st=server\ A field=123 + >>> print(Write.parse('cpu,foo=bar,foo=bar field=123,field=123')) # error: double name is accepted + cpu,foo=bar,foo=bar field=123,field=123 + >>> print(Write.parse('cpu field12=12')) + cpu field12=12 + >>> print(Write.parse('cpu field12=12 123123123')) + cpu field12=12 123123123 + >>> print(Write.parse('cpu field12=12 1231abcdef123')) + Traceback (most recent call last): + ... + ValueError: invalid literal for int() with base 10: '1231abcdef123' + """ + def unescape(string): + return re.sub(r'(?<!\\)([\\,=])', '', string) + + args = re.split(r"(?<!\\) ", line) + key, *tags = re.split(r"(?<!\\),", args[0]) + key = unescape(key) + + if tags: + tags = map(lambda tag: re.split(r"(?<!\\)=", tag), tags) + tags = map(lambda tag: (unescape(tag[0]), unescape(tag[1])), tags) + tags = list(tags) + else: + tags = None + + if len(args) > 1: + fields = re.split(r"(?<!\\),", args[1]) + fields = map(lambda field: re.split(r"(?<!\\)=", field), fields) + fields = map(lambda field: (unescape(field[0]), unescape(field[1])), fields) + fields = list(fields) + else: + fields = None + + if len(args) > 2: + timestamp = int(args[2]) + else: + timestamp = None + + return Write(key, tags, fields, timestamp) + + def __repr__(self): + return "<{} key={} tags={} fields={} timestamp={}>".format( + self.__class__.__name__, self.key, self.tags, self.fields, self.timestamp) + + def __str__(self): + def escape(string): + return re.sub(r'([\\,= ])', '\\\\\\1', string) + + def escape_kv(kvlist): + return ",".join( + map(lambda kv: escape(kv[0]) + "=" + escape(kv[1]), + kvlist)) + + result = escape(self.key) + + if self.tags: + result += "," + result += escape_kv(self.tags) + + if self.fields: + result += " " + result += escape_kv(self.fields) + + if self.timestamp: + result += " " + result += str(self.timestamp) + + return result + + +if __name__ == "__main__": + import doctest + doctest.testmod() + diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..a82b3c6 --- /dev/null +++ b/setup.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +from distutils.core import setup + +setup(name='pyinfluxtools', + version='0.1', + description='Python classes to work with influxdb', + author='Yves Fischer', + author_email='yvesf+github@xapek.org', + license="MIT", + packages = ['pyinfluxtools'], +# url='https://github.com/', +# scripts=[], +# install_requires=[], + classifiers = [ + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Operating System :: OS Independent", + "License :: OSI Approved :: MIT License", + ] +) + |