Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Created a CLI for the package, made 'area_keys' and 'polygon_features' variable #32

Merged
merged 9 commits into from
Mar 22, 2022
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@ If you want to convert OSM xml or Overpass json/xml to Geojson you can import th
Additional parameters for all functions:

- `filter_used_refs` - (default: `True`) defines geometry filtration strategy (will return all geometry if set as `False`)
- `log_level` - (default: `'ERROR'`) controlls logging level (will print all logs if set as `'INFO'`). More details [here](https://docs.python.org/3/library/logging.html#logging-levels)
- `log_level` - (default: `'ERROR'`) controls logging level (will print all logs if set as `'INFO'`). More details [here](https://docs.python.org/3/library/logging.html#logging-levels)
- `area_keys` - (default: `None`) defines which keys and values of an area should be saved from the list of OSM tags, see `areaKeys.json` for the defaults
- `polygon_features` - (default: `None`) defines a whitelist/blacklist of features to be included in resulting polygons, see `polygon-features.json` for the defaults

Other handy methods:

- `overpass_call(str query)` - runs query to overpass-api.de server (retries 5 times in case of error).
- `shape_to_feature(Shape shape, dict properties)` - Converts Shape-object to GeoJSON with passed properties.

**\*Shape-object - for convinience created simple dict to save Shapely object (geometry) and OSM-properties. Structure of this object:**
**\*Shape-object - for convenience created simple dict to save Shapely object (geometry) and OSM-properties. Structure of this object:**
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you for this)


```py
shape_obj = {
Expand All @@ -43,6 +45,17 @@ shape_obj = {
}
```

After installing via `pip`, the module may also be used as a `argparse`-based command-line script.
Either use the script name directly or call Python with the `-m` option and the package name:

```sh
osm2geojson --help
```

```sh
python3 -m osm2geojson --help
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be possible to use this cli tool without python3 -m.
I found good article about this here https://pybit.es/articles/how-to-package-and-deploy-cli-apps/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed! I've used the entry_points feature in the setup.py for this

```

### Examples

Convert OSM-xml to Geojson:
Expand Down
154 changes: 154 additions & 0 deletions osm2geojson/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
#!/usr/bin/env python3

import os
import sys
import json
import argparse

from .main import json2geojson, xml2geojson


def setup_parser() -> argparse.ArgumentParser:
def file(v: str) -> str:
if not os.path.exists(v):
raise ValueError(v)
return v

parser = argparse.ArgumentParser(prog=__package__)
parser.add_argument(
"infile",
type=file,
help="OSM or Overpass JSON file to convert to GeoJSON"
)
parser.add_argument(
"outfile",
help="write output of the processing to the specified file (uses stdout for '-')"
)
parser.add_argument(
"-f",
"--force",
action="store_true",
help="allow overwriting of existing file"
)
logging = parser.add_mutually_exclusive_group()
logging.add_argument(
"-q",
"--quiet",
action="store_true",
help="suppress logging output"
)
logging.add_argument(
"-v",
"--verbose",
action="store_true",
help="enable verbose logging output"
)
parser.add_argument(
"-i",
"--indent",
type=int,
metavar="N",
default=None,
help="indentation using N spaces for the output file (defaults to none)"
)
parser.add_argument(
"--reader",
choices=("json", "xml", "auto"),
default="auto",
help="specify the input file format (either OSM XML or Overpass JSON/XML), defaults to auto-detect"
)
parser.add_argument(
"--no-unused-filter",
action="store_false",
dest="filter_used_refs",
help="don't filter unused references (only in shape JSON)"
)
parser.add_argument(
"--areas",
type=file,
default=None,
metavar="file",
help="JSON file defining the keys that should be included from areas (uses defaults if omitted)"
)
parser.add_argument(
"--polygons",
type=file,
default=None,
metavar="file",
help="JSON file defining the allowed/restricted polygon features (uses defaults if omitted)"
)
return parser


def main(args=None) -> int:
args = args or sys.argv[1:]
parser = setup_parser()
args = parser.parse_args(args)

if args.reader == "xml" or args.reader == "auto" and args.infile.endswith((".osm", ".xml")):
parser_function = xml2geojson
elif args.reader == "json" or args.reader == "auto" and args.infile.endswith(".json"):
parser_function = json2geojson
else:
print("Auto-detecting input file format failed. Consider using --reader.", file=sys.stderr)
return 1

if args.outfile != "-" and os.path.exists(args.outfile) and not args.force:
print(
"Output file '{}' already exists. Consider using -f to force overwriting.".format(args.outfile),
file=sys.stderr
)
return 1

with open(args.infile) as f:
data = f.read()

log_level = "WARNING"
if args.quiet:
log_level = "CRITICAL"
elif args.verbose:
log_level = "DEBUG"

area_keys = None
if args.areas:
with open(args.areas) as f:
area_keys = json.load(f)
if "areaKeys" in area_keys and len(area_keys) == 1:
area_keys = area_keys["areaKeys"]
polygon_features = None
if args.polygons:
with open(args.polygons) as f:
polygon_features = json.load(f)

result = parser_function(
data,
filter_used_refs=args.filter_used_refs,
log_level=log_level,
area_keys=area_keys,
polygon_features=polygon_features
)

indent = args.indent
if indent and indent < 0:
indent = None
if args.outfile == "-":
target = sys.stdout
else:
target = open(args.outfile, "w")

code = 0
try:
print(json.dumps(result, indent=indent), file=target)
except (TypeError, ValueError) as exc:
print(exc, file=sys.stderr)
print("Falling back to raw dumping the object...", file=sys.stderr)
print(result, file=target)
code = 1

if args.outfile != "-":
target.flush()
target.close()
return code


exit(main(sys.argv[1:]))
Loading