{ "info": { "author": "Mehdi Sadeghi", "author_email": "mehdi@mehdix.org", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3" ], "description": "# o2g\n\n[![Build Status](https://travis-ci.org/hiposfer/o2g.svg?branch=master)](https://travis-ci.org/hiposfer/o2g) [![pypi](https://img.shields.io/pypi/v/o2g.svg)](https://pypi.python.org/pypi/o2g)\n\nA simple tool to extract GTFS feed from OpenStreetMap.\n\nOpenStreeMaps data contain information about bus, tram, train and other public transport means.\nThis information is not enought for providing a complete routing service, most importantly because\nit lacks timing data. However, it still contains routes, stop positions and some other useful data.\n\nThis tool takes an OSM file or URI and thanks to [osmium](http://osmcode.org/) library converts it to a partial\n[GTFS](https://developers.google.com/transit/gtfs/reference/) feed. GTFS is the de facto standard\nfor sharing public transport information and there are many tools around it. The resulting feed would\nnot validate if you check it, because it is of course partial. Nevertheless, it is yet valuable to us.\n\n## Installation\nThis tool uses osmium which is a C++ library built using boost, so one should install that first.\nThe best way would be using the package manager of your OS and installing [pyosmium](https://github.com/osmcode/pyosmium).\n\nAfterwards install the script from PyPI:\n\n $ pip install o2g\n\nOr install it from source (with [flit](https://flit.readthedocs.io/en/latest/)):\n\n $ git clone https://github.com/hiposfer/o2g && cd o2g\n $ flit install\n\nThis will install `o2g` package along with `o2g`, its cli tool, on your system.\n\nMake sure to run these commands with python 3.\n\n## Usage\nRun the tool over your OSM data source (or whatever osmium accepts):\n\n $ o2g --help\n usage: o2g [-h] [--area AREA] [--bbox BBOX] [--outdir OUTDIR]\n [--zipfile ZIPFILE] [--dummy]\n [--loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}] [--version]\n [OSMFILE]\n\n Export GTFS feed from OpenStreetMap data.\n\n positional arguments:\n OSMFILE an OSM data file supported by osmium\n\n optional arguments:\n -h, --help show this help message and exit\n --area AREA an OSM area name, e.g. Freiburg (default: None)\n --bbox BBOX a boundary box, e.g. 47.9485,7.7066,48.1161,8.0049\n (default: None)\n --outdir OUTDIR output directory (default: .)\n --zipfile ZIPFILE save to zipfile (default: None)\n --dummy fill the missing parts with dummy data (default:\n False)\n --loglevel {DEBUG,INFO,WARNING,ERROR,CRITICAL}\n the logging level (default: WARNING)\n --version show the version and exit\n\n`--outdir` defaults to the working directory and if `--zipfile` is provided, the feed will be zipped and stored in\nthe _outdir_ with the given name, otherwise feed will be stored as plain text in multiple files.\n\n### Area and Boundary Box\nOne can pass an area name or a bbox to `o2g` and it will download the necessary data\nfrom [Overpass API](https://overpass-api.de/). Area should be an OSM area name and\nbbox should be an OSM boundary box including south, west, north, east separated with\ncomma. Example:\n\n $ o2g --area Freiburg\n $ o2g --bbox 47.9485,7.7066,48.1161,8.0049\n $ o2g --area Freiburg --bbox 47.9485,7.7066,48.1161,8.0049\n\n### Web Demo\nThere is a small web app inside `web` folder. It accepts a URL to a osmium supported file. It will then convert it\nto a zipped GTFS feed.\n\n $ cd web\n $ pip install bottle o2g\n $ python app.py\n\nBrowse to [http://localhost:3000](http://localhost:3000) afterwards.\nAlternatively running `flit install --extras web` will install web dependencies.\n\nThis web app is also running at [http://o2g.hiposfer.com](http://o2g.hiposfer.com). It is possible to directly download a zipped GTFS feed for a given OSM URL too:\n\n $ wget 'http://o2g.hiposfer.com/o2g?url=http://download.geofabrik.de/europe/liechtenstein-latest.osm.bz2' -O gtfs.zip\n\n### Web Api with Overpass Query\nIt is alos possible to download the necessary OSM data from overpass-api.de. Passing an area name or a bbox to the web API will trigger this feature:\n\n $ wget 'http://o2g.hiposfer.com/o2g?area=Freiburg&bbox=47.9485,7.7066,48.1161,8.0049' -O gtfs.zip\n\nAs before, it is possible to get a patched and valid GTFS feed by passing the dummy flag:\n\n $ wget 'http://o2g.hiposfer.com/o2g?area=Freiburg&dummy=True -O gtfs.zip\n\n### With Docker\nIf osmium is not available in your package manager, it could be troublesome to install it manually. So here\nis a docker image that could be used directly:\n\n $ docker run -it -p 3000:3000 hiposfer/o2g\n\nThen browse to [http://localhost:3000](http://localhost:3000).\n\n### Tests\nWe use the `pytest` package for testing:\n\n $ pip install pytest (or by running `flit install`)\n $ pytest -s\n\n`-s` disables capturing and shows us more output (such as print statements and log messages).\n\n### Profiling\nIn order to profile the code we use `cProfile`:\n\n # For the `o2g` script\n $ python -m cProfile -s cumtime o2g/cli.py resources/osm/freiburg.osm.bz2 --outdir resources/out/freiburg --dummy > resources/out/benchmarks/freiburg.txt\n\nYou will find the result in [`resources/out/benchmark.txt`](resources/out/benchmark.txt).\nTheses results are produced on an Archlinux machine with an Intel(R) Core(TM) i5-3210M CPU @ 2.50GHz CPU with 16GB RAM.\n\n### Dummy Feed Information\nNot all of GTFS necessary data are available in OSM files. In order to fill the missing fields with\nsome dummy data use `--dummy` CLI option. This will produce `trips.txt`, `stop_times.txt`, `calendar`\nand `frequencies.txt` feeds. These files will contain dummy data of course.\n\n## Implementation Notes\nIn this section we describe important aspects of the implementation in order to help understand how the program works.\n\n### Field Mapping\nGTFS feeds could contain up to thirteen different CSV files with `.txt` extension. Six of these files are required for a valid\nfeed, including _agency.txt_, _stops.txt_, _routes.txt_, _trips.txt_, _stop_times.txt_ and _calendar.txt_.\nEach file contains a set of comumns. Some columns are required and some are optional.\nMost importantly, not all the fields necessary to build a GTFS feed are available in OSM data.\nTherefore we have to generate some fileds ourselves or leave them blank.\nBelow we cover how the values for each column of the files that we produce at the moment are produced.\n\n#### agency.txt\nWe use _operator_ tag on OSM relations which are tagged as `relation=route` to extract agency information.\nHowever, there are some routes without operator tags. In such cases we use a dummy agency:\n\n {'agency_id': -1, 'agency_name': 'Unkown agency', 'agency_timezone': ''}\n\n - agency_id: we use the _operator_ value to produce the _agency_id_: `agency_id = int(hashlib.sha256(op_name.encode('utf-8')).hexdigest(), 16) % 10**8`\n - agency_name: the value of the _operator_ tag\n - agency_timezone: we guess it based on the coordinates of the elements in the relation\n\n#### stops.txt\n\n - stop_id: value of the node id from OSM\n - stop_name: value of _name_ tag or _Unknown_\n - stop_lon: longitute of the node\n - stop_lat: latitute of the node\n\n#### routes.txt\n\n - route_id: id of the OSM relation element\n - route_short_name: value of _name_ or _ref_ tag of the relation\n - route_long_name: a combination of _from_ and _to_ tags on the relation otherwise empty\n - route_type: we map OSM route types to GTFS\n - route_url: link to the relation on openstreetmaps.org\n - route_color: value of the _colour_ tag if present otherwise empty\n - agency_id: ID of the agency otherwise -1\n\n### OSM to GTFS Route Type Mapping\n Below is the mapping that we use, the left column is the OSM value and the right column is the\n corresponding value from GTFS specification (make sure the see the code for any changes):\n\n tram: \t\t0\n light_rail: 0\n subway: \t1\n rail: \t\t2\n railway: \t2\n train: \t\t2\n bus: \t\t3\n ex-bus: \t3\n ferry: \t\t4\n cableCar: \t5\n gondola: \t6\n funicular: \t7\n\n\n### namedtuples as the preferred data structure\nIn order to decrease the necessary memory, we use mostly namedtuples (which are basically tuples) to store data.\n\n\n## License\nMIT\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/hiposfer/o2g", "keywords": "osm gtfs", "license": "", "maintainer": "", "maintainer_email": "", "name": "o2g", "package_url": "https://pypi.org/project/o2g/", "platform": "", "project_url": "https://pypi.org/project/o2g/", "project_urls": { "Homepage": "https://github.com/hiposfer/o2g" }, "release_url": "https://pypi.org/project/o2g/0.6.0/", "requires_dist": [ "osmium", "pytest; extra == \"test\"", "bottle; extra == \"web\"" ], "requires_python": ">=3.5", "summary": "A simple tool to extract GTFS feed from OpenStreetMap.", "version": "0.6.0" }, "last_serial": 5671921, "releases": { "0.4.4": [ { "comment_text": "", "digests": { "md5": "03ddebc67b46c2381b48e49864563a82", "sha256": "a8ce5ddf0e3e2c8786d62f83e21cbef1613cd068a9dfe2ada3225de10bafaa29" }, "downloads": -1, "filename": "o2g-0.4.4-py3-none-any.whl", "has_sig": false, "md5_digest": "03ddebc67b46c2381b48e49864563a82", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 69743, "upload_time": "2018-10-21T17:32:02", "url": "https://files.pythonhosted.org/packages/b2/e3/7baa4b4bbaeeeee0f73b061465c5601a7d493ded0726bc17c66231fe3cbf/o2g-0.4.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4afb56cecefd7172f6d4804572b7b2cd", "sha256": "a56ce6da40bc8ac152a2e3cbd237e5e9c405b9b2ff8c4e651f98e25a151ee52b" }, "downloads": -1, "filename": "o2g-0.4.4.tar.gz", "has_sig": false, "md5_digest": "4afb56cecefd7172f6d4804572b7b2cd", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 1954925, "upload_time": "2018-10-21T17:32:30", "url": "https://files.pythonhosted.org/packages/9b/37/599a1c57c79f863e666471478320ffeaf9dd521e6a3e6f7b248bb071946a/o2g-0.4.4.tar.gz" } ], "0.5.1": [ { "comment_text": "", "digests": { "md5": "bac662305a8a5819ad1fece53689a68a", "sha256": "535b50096490f53996c71391e73e024705a7db18a60a07bd6f650b7fc8490f52" }, "downloads": -1, "filename": "o2g-0.5.1-py3-none-any.whl", "has_sig": false, "md5_digest": "bac662305a8a5819ad1fece53689a68a", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 69190, "upload_time": "2018-10-23T06:36:01", "url": "https://files.pythonhosted.org/packages/04/cb/3e5f3e5ef77d05b8f654f71e8536cb8b8feb34ae5ca3d97755d6ba3e9c61/o2g-0.5.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8e9b38e91c58925e0b2f0a342d0bde23", "sha256": "2315a1c54d8f5255839fa182ff9bc876f8dceb8674cb748278241ff67ad7b5bf" }, "downloads": -1, "filename": "o2g-0.5.1.tar.gz", "has_sig": false, "md5_digest": "8e9b38e91c58925e0b2f0a342d0bde23", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 1953768, "upload_time": "2018-10-23T06:36:02", "url": "https://files.pythonhosted.org/packages/b5/ce/0df7da2d0d5b3c63bb2c3051133be19dad1b87f984bf66943e210fd3b3ec/o2g-0.5.1.tar.gz" } ], "0.6.0": [ { "comment_text": "", "digests": { "md5": "8f0c0a88cf3999ed686e8cae3625f8f7", "sha256": "e755f8b28c9a765f9b8f2cef1e69bdcf0a4d7eebca67d953c7c40c8b807822d0" }, "downloads": -1, "filename": "o2g-0.6.0-py3-none-any.whl", "has_sig": false, "md5_digest": "8f0c0a88cf3999ed686e8cae3625f8f7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 79190, "upload_time": "2019-08-13T13:41:00", "url": "https://files.pythonhosted.org/packages/2c/b1/531f74180d6e2e3b388093182a02506c909570967c61579a5957ace3913c/o2g-0.6.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d675d1145992417661071b08cb6b715c", "sha256": "c73bbd3775c150d1d2ab260e1890a52fbfe77c23f8542ef877fc7952579126fa" }, "downloads": -1, "filename": "o2g-0.6.0.tar.gz", "has_sig": false, "md5_digest": "d675d1145992417661071b08cb6b715c", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 698724, "upload_time": "2019-08-13T13:41:02", "url": "https://files.pythonhosted.org/packages/ed/8d/3794eeb81ef401a8d37dc445308160d1898918cbf687b71695e13796a0c0/o2g-0.6.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "8f0c0a88cf3999ed686e8cae3625f8f7", "sha256": "e755f8b28c9a765f9b8f2cef1e69bdcf0a4d7eebca67d953c7c40c8b807822d0" }, "downloads": -1, "filename": "o2g-0.6.0-py3-none-any.whl", "has_sig": false, "md5_digest": "8f0c0a88cf3999ed686e8cae3625f8f7", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 79190, "upload_time": "2019-08-13T13:41:00", "url": "https://files.pythonhosted.org/packages/2c/b1/531f74180d6e2e3b388093182a02506c909570967c61579a5957ace3913c/o2g-0.6.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d675d1145992417661071b08cb6b715c", "sha256": "c73bbd3775c150d1d2ab260e1890a52fbfe77c23f8542ef877fc7952579126fa" }, "downloads": -1, "filename": "o2g-0.6.0.tar.gz", "has_sig": false, "md5_digest": "d675d1145992417661071b08cb6b715c", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 698724, "upload_time": "2019-08-13T13:41:02", "url": "https://files.pythonhosted.org/packages/ed/8d/3794eeb81ef401a8d37dc445308160d1898918cbf687b71695e13796a0c0/o2g-0.6.0.tar.gz" } ] }