{ "info": { "author": "Claudio Giovanni Mattera", "author_email": "cgim@mmmi.sdu.dk", "bugtrack_url": null, "classifiers": [], "description": "CFEI sMAP Python Library\n===========\n\nThis is a Python 3 library to interface to [sMAP] archivers.\nIt uses the [asyncio] framework to connect to the archiver, and it returns [pandas] data-frames and time-series.\n\nDocumentation available at https://sdu-cfei.github.io/cfei-smap/\n\n\nFeatures\n----\n\n* **Fetching historical data**.\n The user specifies a time interval and a query, and the library returns all time-series that satisfy the query.\n\n The user can also request a single time-series.\n In that case, all resulting time-series will be intertwined to generate a single one.\n This is useful when time-series are split in multiple streams, e.g., in case of gateway jumps.\n\n* **Subscribing to real-time data**.\n The user specifies a query and a callback, and the library will call the callback whenever a new reading is available.\n\n Since the library supports IO concurrency, the application can perform other operations, while waiting for new data.\n\n* **Posting data**.\n The users specifies a set of readings, a source name, a path and a UUID.\n It can optionally specify properties and metadata.\n\n A simpler interface is available when posting data to existing streams.\n The user specifies only UUIDs and readings, and the library will transparently retrieve and cache source names and paths.\n\n* **Concurrent requests**.\n The user can instantiate multiple concurrent requests to the sMAP archiver, the library (or, better, the asyncio framework) will execute them in parallel.\n\n A parameter defines how many concurrent requests to execute (default: 10) to not overload the sMAP archiver.\n Any further request will be transparently enqueued and executed as soon as a slot is free.\n\n* **Local caching**.\n Readings can be cached on the local machine.\n The library can detect when the requested time interval (or larger) is available locally.\n This saves execution time, network traffic and server load.\n If the cache does not correspond to the user's query, it is invalidated and data is automatically fetched from the server.\n\n *Note*: the library cannot detect when readings were replaced/added on the server.\n Cache should be used only for immutable historical data, not for data that can change.\n\n* **Command line tool**.\n The tool can be used to quickly plot single time-series data, or to export to CSV files.\n\n\nInstallation\n----\n\nThe library is available as three different packages:\n\n- Debian package, usable on Debian/Ubuntu and derivatives (anything that uses `apt`/`apt-get`).\n Install it with the following command (possibly prepended with `sudo`).\n\n dpkg -i /path/to/python3-cfei-smap_1.2.0-1_all.deb\n\n- Python wheel package, usable on Windows and almost every system with a Python 3 distribution.\n Install it with the following command (possibly prepended with `sudo`, or passing the `--user` option).\n\n pip3 install /path/to/cfei_smap-1.1-py3-none-any.whl\n\n- Tarball source package.\n It can be used by maintainers to generate a custom package.\n\n\nUsage\n----\n\n### General Instructions\n\nThis library uses the [asyncio] framework, and returns [pandas] data-frames and time-series.\n\nMost of the features are available as member functions of objects implementing `SmapInterface`.\nClients should first create one of the concrete classes, e.g., `SmapAiohttpInterface`, and then call its methods.\n\n~~~~python\nfrom cfei.smap import SmapAiohttpInterface\n\n...\n\nsmap = SmapAiohttpInterface(\"http://hostname.com:8079\")\n\nawait smap.fetch_readings(...)\n~~~~\n\n\n### Important Note about Timezones\n\nWhenever using time-series data, proper care should be taken to correctly store and represent timezones.\nUnfortunately, many tools lack support for timezones, and many users assume localtime is good enough.\nThis often results in issues when sharing time-series with other persons, or storing them in databases.\nIt also causes problems at daylight saving time changes, when the time offset of a timezone changes.\nTherefore, this library enforces using timezone-aware datetimes.\nWhenever a date is expected, it *must* be a timezone-aware datetime object in UTC, otherwise an exception will be generated.\n\nThis could make things more complicate and cumbersome when users are interested in localtime dynamics, such as occupancy behaviour or price trends, because they have to manually convert to and from UTC.\nAn example on how to convert back and forth from UTC is included in :ref:`timezones`.\n\n\n### Fetching Data\n\nTo fetch data from sMAP, the caller must specify the interval as a pair of `datetime` objects and a *where* query.\n\n~~~~python\nfrom datetime import datetime\n\nimport pytz\n\nfrom cfei.smap import SmapAiohttpInterface\n\n\nasync def main():\n smap = SmapAiohttpInterface(\"http://hostname.com:8079\")\n\n start = pytz.UTC.localize(datetime(2018, 1, 1, 10, 15))\n end = pytz.UTC.localize(datetime(2018, 1, 8, 4, 5))\n\n where = (\n \"Metadata/Location/Building = 'MyBuilding' and \"\n \"Metadata/Location/Room = 'MyRoom' and \"\n \"Metadata/Location/Media = 'air' and \"\n \"Metadata/Location/Media = 'co2'\"\n )\n\n readings_by_uuid = await smap.fetch_readings(start, end, where)\n\n # It returns a dict[UUID, pd.Series]\n\n readings = await smap.fetch_readings_intertwined(start, end, where)\n\n # It returns a single pd.Series obtained by intertwining all the results\n~~~~\n\n#### Note\n\nIf there are readings at `start` and `end` instants, the returned time-series will be defined on the *closed* interval [`start`, `end`].\nOtherwise, which is a more common scenario, the returned time-series will be defined on the *open* interval ]`start`, `end`[.\n\n\n### Posting Data\n\nUsers can post both data (a sequence of readings, i.e., timestamp, value pairs) and metadata (a set of key, value pairs) to any number of sMAP streams.\n\nThere are two options to post data to a stream:\n\n1. Providing *path*, *source name* and *UUID* (and optionally metadata and properties).\n This option can be used to create non-existing streams.\n\n from datetime import datetime\n from uuid import UUID\n\n import pandas as pd\n\n from cfei.smap import SmapAiohttpInterface\n\n async def main():\n series = pd.Series(...)\n uuid = UUID(...)\n\n await smap.post_data(series, uuid, source_name, path)\n\n2. Providing only the *UUIDs*.\n In this case the library will retrieve and cache the corresponding *path* and *source name*, before actually posting data.\n This option is only available if the streams already exist.\n\n from datetime import datetime\n from uuid import UUID\n\n import pandas as pd\n\n from cfei.smap import SmapAiohttpInterface\n\n async def main():\n series = pd.Series(...)\n uuid = UUID(...)\n\n await smap.post_readings({\n uuid: series\n })\n\n\n### Subscribing to real-time data\n\nUsers can subscribe to sMAP, and be notified of every new available reading.\n\n~~~~python\nfrom uuid import UUID\n\nfrom cfei.smap import SmapAiohttpInterface\n\n\nasync def callback(uuid, series):\n for timestamp, value in series.iteritems():\n print(\"{}: {}\".format(timestamp, value))\n\n\nasync def main():\n smap = SmapAiohttpInterface(\"http://hostname.com:8079\")\n\n where = (\n \"Metadata/Location/Building = 'MyBuilding' and \"\n \"Metadata/Location/Room = 'MyRoom' and \"\n \"Metadata/Location/Media = 'air' and \"\n \"Metadata/Location/Media = 'co2'\"\n )\n\n await smap.subscribe(where, callback)\n~~~~\n\n\n### Enabling Local Cache\n\nPass `cache=True` to the `SmapInterface` constructor to enable local cache.\n\n~~~~python\nfrom cfei.smap import SmapAiohttpInterface\n\n\nasync def main():\n smap = SmapAiohttpInterface(\"http://hostname.com:8079\", cache=True)\n\n # The first time data are fetched from server and cached locally.\n await smap.fetch_readings(start, end, where)\n\n # The second time they are loaded from local cache.\n await smap.fetch_readings(start, end, where)\n\n # This interval is strictly contained in the previous one, so data can\n # still be loaded from local cache.\n await smap.fetch_readings(\n start + timedelta(days=3),\n end - timedelta(days=2),\n where\n )\n\n # This interval is *NOT* strictly contained in the previous one, cache\n # will be invalidated and data will be fetched from server.\n await smap.fetch_readings(\n start - timedelta(days=3),\n end,\n where\n )\n~~~~\n\n\n### Note about *asyncio*\n\nThis library uses the *asyncio* framework.\nThis means that all functions and methods are actually coroutines, and they need to be called accordingly.\nThe caller can retrieve the event loop, and explicitly execute a coroutine\n\n~~~~python\nimport asyncio\n\nloop = asyncio.get_event_loop()\n\nresult = loop.run_until_complete(\n smap.method(arguments)\n)\n~~~~\n\nOtherwise, if the caller is itself a coroutine, it can use the corresponding syntax in Pyhton 3.5+\n\n~~~~python\nasync def external_coroutine():\n result = await smap.method(arguments)\n~~~~\n\n\nCommand Line Utility\n----\n\nThis library includes a command line utility named `smap`, which can be used to retrieve and plot data from sMAP archiver.\n\n~~~~\nusage: smap [-h] [-v] --url URL [--plot] [--plot-markers] [--csv]\n [--start DATETIME] [--end DATETIME]\n WHERE\n\nFetch data from sMAP\n\npositional arguments:\n WHERE sMAP query where\n\noptional arguments:\n -h, --help show this help message and exit\n -v, --verbose increase output\n --url URL sMAP archiver URL\n --plot plot results\n --plot-markers show plot markers\n --csv print results to stdout in CSV format\n --start DATETIME initial time (default: 24h ago)\n --end DATETIME final time (default: now)\n~~~~\n\nFor instance, to export a single time-series to CSV file:\n\n~~~~bash\nsmap --url http://hostname.com:8079 \"uuid = '12345678-1234-1234-1234-12345678abcd'\" \\\n --start 2018-01-17T00:00:00Z --csv -vv > output.csv\n~~~~\n\n\n[sMAP]: https://pythonhosted.org/Smap/en/2.0/archiver.html\n\n[asyncio]: https://docs.python.org/3/library/asyncio.html\n\n[pandas]: https://pandas.pydata.org/\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/sdu-cfei/cfei-smap/", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "cfei-smap", "package_url": "https://pypi.org/project/cfei-smap/", "platform": "", "project_url": "https://pypi.org/project/cfei-smap/", "project_urls": { "Homepage": "https://github.com/sdu-cfei/cfei-smap/" }, "release_url": "https://pypi.org/project/cfei-smap/1.2.0/", "requires_dist": [ "pandas", "typing", "aiohttp", "appdirs", "jsonschema", "iso8601" ], "requires_python": "", "summary": "Interface to sMAP", "version": "1.2.0" }, "last_serial": 4559789, "releases": { "1.2.0": [ { "comment_text": "", "digests": { "md5": "28e8a2b638a1aecf950211e117441324", "sha256": "aee5b75976d4443595a69f9fb61fe9733e0fdd0ad305c709bf78e9751d060f9a" }, "downloads": -1, "filename": "cfei_smap-1.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "28e8a2b638a1aecf950211e117441324", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20179, "upload_time": "2018-12-04T14:16:31", "url": "https://files.pythonhosted.org/packages/fa/9d/726ff61e334dd908de5d77838514176afcfd4f34f3b2b614dd39c719ac83/cfei_smap-1.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "68f79145e4160f876064a33496bf1bd3", "sha256": "5b72861c237dc2dc7fced62dc9a2dd16fad453283957121a9cd1bf8fe226eacf" }, "downloads": -1, "filename": "cfei-smap-1.2.0.tar.gz", "has_sig": false, "md5_digest": "68f79145e4160f876064a33496bf1bd3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 56051, "upload_time": "2018-12-04T14:16:33", "url": "https://files.pythonhosted.org/packages/e2/6b/66266cfad1362e2afb7d724d13129350294473a82ea5b425a8648ee6c738/cfei-smap-1.2.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "28e8a2b638a1aecf950211e117441324", "sha256": "aee5b75976d4443595a69f9fb61fe9733e0fdd0ad305c709bf78e9751d060f9a" }, "downloads": -1, "filename": "cfei_smap-1.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "28e8a2b638a1aecf950211e117441324", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 20179, "upload_time": "2018-12-04T14:16:31", "url": "https://files.pythonhosted.org/packages/fa/9d/726ff61e334dd908de5d77838514176afcfd4f34f3b2b614dd39c719ac83/cfei_smap-1.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "68f79145e4160f876064a33496bf1bd3", "sha256": "5b72861c237dc2dc7fced62dc9a2dd16fad453283957121a9cd1bf8fe226eacf" }, "downloads": -1, "filename": "cfei-smap-1.2.0.tar.gz", "has_sig": false, "md5_digest": "68f79145e4160f876064a33496bf1bd3", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 56051, "upload_time": "2018-12-04T14:16:33", "url": "https://files.pythonhosted.org/packages/e2/6b/66266cfad1362e2afb7d724d13129350294473a82ea5b425a8648ee6c738/cfei-smap-1.2.0.tar.gz" } ] }