).
To credit the application that supplies changes to OSM, an `appid`
can be provided. This is a string identifying the application.
If this is omitted "osmapi" is used.
It is possible to configure the URL to connect to using the `api`
parameter. By default this is the SSL version of the production API
of OpenStreetMap, for testing purposes, one might prefer the official
test instance at "api06.dev.openstreetmap.org" or any other valid
OSM-API. To use an encrypted connection (HTTPS) simply add 'https://'
in front of the hostname of the `api` parameter (e.g.
https://api.openstreetmap.com).
There are several options to control the changeset behaviour. By
default, a programmer has to take care to open and close a changeset
prior to make changes to OSM.
By setting `changesetauto` to `True`, osmapi automatically opens
changesets.
The `changesetautotags` parameter takes a `dict`, where each key/value
pair is applied as tags to the changeset.
The option `changesetautosize` defines the size of each
upload (default: 500) and `changesetautomulti` defines how many
uploads should be made before closing a changeset and opening a new
one (default: 1).
The `debug` parameter can be used to generate a more verbose output.
"""
# debug
self._debug = debug
# Get username
if username:
self._username = username
elif passwordfile:
pass_line = open(passwordfile).readline()
self._username = pass_line.split(":")[0].strip()
# Get password
if password:
self._password = password
elif passwordfile:
for line in open(passwordfile).readlines():
line = line.strip().split(":")
if line[0] == self._username:
self._password = line[1]
# Changest informations
# auto create and close changesets
self._changesetauto = changesetauto
# tags for automatic created changesets
self._changesetautotags = changesetautotags
# change count for auto changeset
self._changesetautosize = changesetautosize
# change count for auto changeset
self._changesetautosize = changesetautosize
# close a changeset every # upload
self._changesetautomulti = changesetautomulti
self._changesetautocpt = 0
# data to upload for auto group
self._changesetautodata = []
# Get API
self._api = api.strip('/')
# Get created_by
if not appid:
self._created_by = created_by
else:
self._created_by = "%s (%s)" % (appid, created_by)
# Initialisation
self._CurrentChangesetId = 0
# Http connection
self._session = self._get_http_session()
def __del__(self):
try:
if self._changesetauto:
self._changesetautoflush(True)
except ResponseEmptyApiError:
pass
return None
##################################################
# Capabilities #
##################################################
def Capabilities(self):
"""
Returns the API capabilities as a dict:
#!python
{
'area': {
'maximum': area in square degrees that can be queried,
},
'changesets': {
'maximum_elements': number of elements per changeset,
},
'status': {
'api': online|readonly|offline,
'database': online|readonly|offline,
'gpx': online|readonly|offline,
},
'timeout': {
'seconds': timeout in seconds for API calls,
},
'tracepoints': {
'per_page': maximum number of points in a GPX track,
},
'version': {
'maximum': maximum version of API this server supports,
'minimum': minimum version of API this server supports,
},
'waynodes': {
'maximum': maximum number of nodes that a way may contain,
},
}
The capabilities can be used by a client to
gain insights of the server in use.
"""
uri = "/api/capabilities"
data = self._get(uri)
data = self._OsmResponseToDom(data, tag="api", single=True)
result = {}
for elem in data.childNodes:
if elem.nodeType != elem.ELEMENT_NODE:
continue
result[elem.nodeName] = {}
for k, v in elem.attributes.items():
try:
result[elem.nodeName][k] = float(v)
except Exception:
result[elem.nodeName][k] = v
return result
##################################################
# Node #
##################################################
def NodeGet(self, NodeId, NodeVersion=-1):
"""
Returns node with `NodeId` as a dict:
#!python
{
'id': id of node,
'lat': latitude of node,
'lon': longitude of node,
'tag': {},
'changeset': id of changeset of last change,
'version': version number of node,
'user': username of user that made the last change,
'uid': id of user that made the last change,
'timestamp': timestamp of last change,
'visible': True|False
}
If `NodeVersion` is supplied, this specific version is returned,
otherwise the latest version is returned.
If the requested element has been deleted,
`OsmApi.ElementDeletedApiError` is raised.
"""
uri = "/api/0.6/node/%s" % (NodeId)
if NodeVersion != -1:
uri += "/%s" % (NodeVersion)
data = self._get(uri)
data = self._OsmResponseToDom(data, tag="node", single=True)
return self._DomParseNode(data)
def NodeCreate(self, NodeData):
"""
Creates a node based on the supplied `NodeData` dict:
#!python
{
'lat': latitude of node,
'lon': longitude of node,
'tag': {},
}
Returns updated `NodeData` (without timestamp):
#!python
{
'id': id of node,
'lat': latitude of node,
'lon': longitude of node,
'tag': dict of tags,
'changeset': id of changeset of last change,
'version': version number of node,
'user': username of last change,
'uid': id of user of last change,
'visible': True|False
}
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
If there is no open changeset,
`OsmApi.NoChangesetOpenError` is raised.
If the supplied information contain an existing node,
`OsmApi.OsmTypeAlreadyExistsError` is raised.
"""
return self._do("create", "node", NodeData)
def NodeUpdate(self, NodeData):
"""
Updates node with the supplied `NodeData` dict:
#!python
{
'id': id of node,
'lat': latitude of node,
'lon': longitude of node,
'tag': {},
'version': version number of node,
}
Returns updated `NodeData` (without timestamp):
#!python
{
'id': id of node,
'lat': latitude of node,
'lon': longitude of node,
'tag': dict of tags,
'changeset': id of changeset of last change,
'version': version number of node,
'user': username of last change,
'uid': id of user of last change,
'visible': True|False
}
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
If there is no open changeset,
`OsmApi.NoChangesetOpenError` is raised.
If there is already an open changeset,
`OsmApi.ChangesetAlreadyOpenError` is raised.
"""
return self._do("modify", "node", NodeData)
def NodeDelete(self, NodeData):
"""
Delete node with `NodeData`:
#!python
{
'id': id of node,
'lat': latitude of node,
'lon': longitude of node,
'tag': dict of tags,
'version': version number of node,
}
Returns updated `NodeData` (without timestamp):
#!python
{
'id': id of node,
'lat': latitude of node,
'lon': longitude of node,
'tag': dict of tags,
'changeset': id of changeset of last change,
'version': version number of node,
'user': username of last change,
'uid': id of user of last change,
'visible': True|False
}
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
If there is no open changeset,
`OsmApi.NoChangesetOpenError` is raised.
If there is already an open changeset,
`OsmApi.ChangesetAlreadyOpenError` is raised.
If the requested element has already been deleted,
`OsmApi.ElementDeletedApiError` is raised.
"""
return self._do("delete", "node", NodeData)
def NodeHistory(self, NodeId):
"""
Returns dict with version as key:
#!python
{
'1': dict of NodeData,
'2': dict of NodeData,
...
}
`NodeId` is the unique identifier of a node.
"""
uri = "/api/0.6/node/%s/history" % NodeId
data = self._get(uri)
nodes = self._OsmResponseToDom(data, tag="node")
result = {}
for node in nodes:
data = self._DomParseNode(node)
result[data["version"]] = data
return result
def NodeWays(self, NodeId):
"""
Returns a list of dicts of `WayData` containing node `NodeId`:
#!python
[
{
'id': id of Way,
'nd': [] list of NodeIds in this way
'tag': {} dict of tags,
'changeset': id of changeset of last change,
'version': version number of Way,
'user': username of user that made the last change,
'uid': id of user that made the last change,
'visible': True|False
},
{
...
},
]
The `NodeId` is a unique identifier for a node.
"""
uri = "/api/0.6/node/%d/ways" % NodeId
data = self._get(uri)
ways = self._OsmResponseToDom(data, tag="way")
result = []
for way in ways:
data = self._DomParseWay(way)
result.append(data)
return result
def NodeRelations(self, NodeId):
"""
Returns a list of dicts of `RelationData` containing node `NodeId`:
#!python
[
{
'id': id of Relation,
'member': [
{
'ref': ID of referenced element,
'role': optional description of role in relation
'type': node|way|relation
},
{
...
}
]
'tag': {},
'changeset': id of changeset of last change,
'version': version number of Way,
'user': username of user that made the last change,
'uid': id of user that made the last change,
'visible': True|False
},
{
...
},
]
The `NodeId` is a unique identifier for a node.
"""
uri = "/api/0.6/node/%d/relations" % NodeId
data = self._get(uri)
relations = self._OsmResponseToDom(data, tag="relation")
result = []
for relation in relations:
data = self._DomParseRelation(relation)
result.append(data)
return result
def NodesGet(self, NodeIdList):
"""
Returns dict with the id of the Node as a key
for each node in `NodeIdList`:
#!python
{
'1234': dict of NodeData,
'5678': dict of NodeData,
...
}
`NodeIdList` is a list containing unique identifiers
for multiple nodes.
"""
node_list = ",".join([str(x) for x in NodeIdList])
uri = "/api/0.6/nodes?nodes=%s" % node_list
data = self._get(uri)
nodes = self._OsmResponseToDom(data, tag="node")
result = {}
for node in nodes:
data = self._DomParseNode(node)
result[data["id"]] = data
return result
##################################################
# Way #
##################################################
def WayGet(self, WayId, WayVersion=-1):
"""
Returns way with `WayId` as a dict:
#!python
{
'id': id of way,
'tag': {} tags of this way,
'nd': [] list of nodes belonging to this way
'changeset': id of changeset of last change,
'version': version number of way,
'user': username of user that made the last change,
'uid': id of user that made the last change,
'timestamp': timestamp of last change,
'visible': True|False
}
If `WayVersion` is supplied, this specific version is returned,
otherwise the latest version is returned.
If the requested element has been deleted,
`OsmApi.ElementDeletedApiError` is raised.
"""
uri = "/api/0.6/way/%s" % (WayId)
if WayVersion != -1:
uri += "/%s" % (WayVersion)
data = self._get(uri)
way = self._OsmResponseToDom(data, tag="way", single=True)
return self._DomParseWay(way)
def WayCreate(self, WayData):
"""
Creates a way based on the supplied `WayData` dict:
#!python
{
'nd': [] list of nodes,
'tag': {} dict of tags,
}
Returns updated `WayData` (without timestamp):
#!python
{
'id': id of node,
'nd': [] list of nodes,
'tag': {} dict of tags,
'changeset': id of changeset of last change,
'version': version number of way,
'user': username of last change,
'uid': id of user of last change,
'visible': True|False
}
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
If the supplied information contain an existing node,
`OsmApi.OsmTypeAlreadyExistsError` is raised.
If there is no open changeset,
`OsmApi.NoChangesetOpenError` is raised.
If there is already an open changeset,
`OsmApi.ChangesetAlreadyOpenError` is raised.
"""
return self._do("create", "way", WayData)
def WayUpdate(self, WayData):
"""
Updates way with the supplied `WayData` dict:
#!python
{
'id': id of way,
'nd': [] list of nodes,
'tag': {},
'version': version number of way,
}
Returns updated `WayData` (without timestamp):
#!python
{
'id': id of node,
'nd': [] list of nodes,
'tag': {} dict of tags,
'changeset': id of changeset of last change,
'version': version number of way,
'user': username of last change,
'uid': id of user of last change,
'visible': True|False
}
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
If there is no open changeset,
`OsmApi.NoChangesetOpenError` is raised.
If there is already an open changeset,
`OsmApi.ChangesetAlreadyOpenError` is raised.
"""
return self._do("modify", "way", WayData)
def WayDelete(self, WayData):
"""
Delete way with `WayData`:
#!python
{
'id': id of way,
'nd': [] list of nodes,
'tag': dict of tags,
'version': version number of way,
}
Returns updated `WayData` (without timestamp):
#!python
{
'id': id of node,
'nd': [] list of nodes,
'tag': {} dict of tags,
'changeset': id of changeset of last change,
'version': version number of way,
'user': username of last change,
'uid': id of user of last change,
'visible': True|False
}
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
If there is no open changeset,
`OsmApi.NoChangesetOpenError` is raised.
If there is already an open changeset,
`OsmApi.ChangesetAlreadyOpenError` is raised.
If the requested element has already been deleted,
`OsmApi.ElementDeletedApiError` is raised.
"""
return self._do("delete", "way", WayData)
def WayHistory(self, WayId):
"""
Returns dict with version as key:
#!python
{
'1': dict of WayData,
'2': dict of WayData,
...
}
`WayId` is the unique identifier of a way.
"""
uri = "/api/0.6/way/%s/history" % (WayId)
data = self._get(uri)
ways = self._OsmResponseToDom(data, tag="way")
result = {}
for way in ways:
data = self._DomParseWay(way)
result[data["version"]] = data
return result
def WayRelations(self, WayId):
"""
Returns a list of dicts of `RelationData` containing way `WayId`:
#!python
[
{
'id': id of Relation,
'member': [
{
'ref': ID of referenced element,
'role': optional description of role in relation
'type': node|way|relation
},
{
...
}
]
'tag': {} dict of tags,
'changeset': id of changeset of last change,
'version': version number of Way,
'user': username of user that made the last change,
'uid': id of user that made the last change,
'visible': True|False
},
{
...
},
]
The `WayId` is a unique identifier for a way.
"""
uri = "/api/0.6/way/%d/relations" % WayId
data = self._get(uri)
relations = self._OsmResponseToDom(data, tag="relation")
result = []
for relation in relations:
data = self._DomParseRelation(relation)
result.append(data)
return result
def WayFull(self, WayId):
"""
Returns the full data for way `WayId` as list of dicts:
#!python
[
{
'type': node|way|relation,
'data': {} data dict for node|way|relation
},
{ ... }
]
The `WayId` is a unique identifier for a way.
If the requested element has been deleted,
`OsmApi.ElementDeletedApiError` is raised.
"""
uri = "/api/0.6/way/%s/full" % (WayId)
data = self._get(uri)
return self.ParseOsm(data)
def WaysGet(self, WayIdList):
"""
Returns dict with the id of the way as a key for
each way in `WayIdList`:
#!python
{
'1234': dict of WayData,
'5678': dict of WayData,
...
}
`WayIdList` is a list containing unique identifiers for multiple ways.
"""
way_list = ",".join([str(x) for x in WayIdList])
uri = "/api/0.6/ways?ways=%s" % way_list
data = self._get(uri)
ways = self._OsmResponseToDom(data, tag="way")
result = {}
for way in ways:
data = self._DomParseWay(way)
result[data["id"]] = data
return result
##################################################
# Relation #
##################################################
def RelationGet(self, RelationId, RelationVersion=-1):
"""
Returns relation with `RelationId` as a dict:
#!python
{
'id': id of Relation,
'member': [
{
'ref': ID of referenced element,
'role': optional description of role in relation
'type': node|way|relation
},
{
...
}
]
'tag': {} dict of tags,
'changeset': id of changeset of last change,
'version': version number of Relation,
'user': username of user that made the last change,
'uid': id of user that made the last change,
'timestamp': timestamp of last change,
'visible': True|False
}
If `RelationVersion` is supplied, this specific version is returned,
otherwise the latest version is returned.
If the requested element has been deleted,
`OsmApi.ElementDeletedApiError` is raised.
"""
uri = "/api/0.6/relation/%s" % (RelationId)
if RelationVersion != -1:
uri += "/%s" % (RelationVersion)
data = self._get(uri)
relation = self._OsmResponseToDom(data, tag="relation", single=True)
return self._DomParseRelation(relation)
def RelationCreate(self, RelationData):
"""
Creates a relation based on the supplied `RelationData` dict:
#!python
{
'member': [] list of members,
'tag': {} dict of tags,
}
Returns updated `RelationData` (without timestamp):
#!python
{
'id': id of Relation,
'member': [
{
'ref': ID of referenced element,
'role': optional description of role in relation
'type': node|way|relation
},
{
...
}
]
'tag': {} dict of tags,
'changeset': id of changeset of last change,
'version': version number of Relation,
'user': username of user that made the last change,
'uid': id of user that made the last change,
'visible': True|False
}
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
If the supplied information contain an existing node,
`OsmApi.OsmTypeAlreadyExistsError` is raised.
If there is no open changeset,
`OsmApi.NoChangesetOpenError` is raised.
If there is already an open changeset,
`OsmApi.ChangesetAlreadyOpenError` is raised.
"""
return self._do("create", "relation", RelationData)
def RelationUpdate(self, RelationData):
"""
Updates relation with the supplied `RelationData` dict:
#!python
{
'id': id of relation,
'member': [] list of member dicts,
'tag': {},
'version': version number of relation,
}
Returns updated `RelationData` (without timestamp):
#!python
{
'id': id of Relation,
'member': [
{
'ref': ID of referenced element,
'role': optional description of role in relation
'type': node|way|relation
},
{
...
}
]
'tag': {} dict of tags
'changeset': id of changeset of last change,
'version': version number of Relation,
'user': username of user that made the last change,
'uid': id of user that made the last change,
'visible': True|False
}
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
If there is no open changeset,
`OsmApi.NoChangesetOpenError` is raised.
If there is already an open changeset,
`OsmApi.ChangesetAlreadyOpenError` is raised.
"""
return self._do("modify", "relation", RelationData)
def RelationDelete(self, RelationData):
"""
Delete relation with `RelationData` dict:
#!python
{
'id': id of relation,
'member': [] list of member dicts,
'tag': {},
'version': version number of relation,
}
Returns updated `RelationData` (without timestamp):
#!python
{
'id': id of Relation,
'member': [
{
'ref': ID of referenced element,
'role': optional description of role in relation
'type': node|way|relation
},
{
...
}
]
'tag': {} dict of tags,
'changeset': id of changeset of last change,
'version': version number of Relation,
'user': username of user that made the last change,
'uid': id of user that made the last change,
'visible': True|False
}
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
If there is no open changeset,
`OsmApi.NoChangesetOpenError` is raised.
If there is already an open changeset,
`OsmApi.ChangesetAlreadyOpenError` is raised.
If the requested element has already been deleted,
`OsmApi.ElementDeletedApiError` is raised.
"""
return self._do("delete", "relation", RelationData)
def RelationHistory(self, RelationId):
"""
Returns dict with version as key:
#!python
{
'1': dict of RelationData,
'2': dict of RelationData,
...
}
`RelationId` is the unique identifier of a relation.
"""
uri = "/api/0.6/relation/%s/history" % (RelationId)
data = self._get(uri)
relations = self._OsmResponseToDom(data, tag="relation")
result = {}
for relation in relations:
data = self._DomParseRelation(relation)
result[data["version"]] = data
return result
def RelationRelations(self, RelationId):
"""
Returns a list of dicts of `RelationData`
containing relation `RelationId`:
#!python
[
{
'id': id of Relation,
'member': [
{
'ref': ID of referenced element,
'role': optional description of role in relation
'type': node|way|relation
},
{
...
}
]
'tag': {} dict of tags,
'changeset': id of changeset of last change,
'version': version number of Way,
'user': username of user that made the last change,
'uid': id of user that made the last change,
'visible': True|False
},
{
...
},
]
The `RelationId` is a unique identifier for a relation.
"""
uri = "/api/0.6/relation/%d/relations" % RelationId
data = self._get(uri)
relations = self._OsmResponseToDom(data, tag="relation")
result = []
for relation in relations:
data = self._DomParseRelation(relation)
result.append(data)
return result
def RelationFullRecur(self, RelationId):
"""
Returns the full data (all levels) for relation
`RelationId` as list of dicts:
#!python
[
{
'type': node|way|relation,
'data': {} data dict for node|way|relation
},
{ ... }
]
The `RelationId` is a unique identifier for a way.
This function is useful for relations containing other relations.
If you don't need all levels, use `OsmApi.RelationFull`
instead, which return only 2 levels.
If any relation (on any level) has been deleted,
`OsmApi.ElementDeletedApiError` is raised.
"""
data = []
todo = [RelationId]
done = []
while todo:
rid = todo.pop(0)
done.append(rid)
temp = self.RelationFull(rid)
for item in temp:
if item["type"] != "relation":
continue
if item["data"]["id"] in done:
continue
todo.append(item["data"]["id"])
data += temp
return data
def RelationFull(self, RelationId):
"""
Returns the full data (two levels) for relation
`RelationId` as list of dicts:
#!python
[
{
'type': node|way|relation,
'data': {} data dict for node|way|relation
},
{ ... }
]
The `RelationId` is a unique identifier for a way.
If you need all levels, use `OsmApi.RelationFullRecur`.
If the requested element has been deleted,
`OsmApi.ElementDeletedApiError` is raised.
"""
uri = "/api/0.6/relation/%s/full" % (RelationId)
data = self._get(uri)
return self.ParseOsm(data)
def RelationsGet(self, RelationIdList):
"""
Returns dict with the id of the relation as a key
for each relation in `RelationIdList`:
#!python
{
'1234': dict of RelationData,
'5678': dict of RelationData,
...
}
`RelationIdList` is a list containing unique identifiers
for multiple relations.
"""
relation_list = ",".join([str(x) for x in RelationIdList])
uri = "/api/0.6/relations?relations=%s" % relation_list
data = self._get(uri)
relations = self._OsmResponseToDom(data, tag="relation")
result = {}
for relation in relations:
data = self._DomParseRelation(relation)
result[data["id"]] = data
return result
##################################################
# Changeset #
##################################################
def ChangesetGet(self, ChangesetId, include_discussion=False):
"""
Returns changeset with `ChangesetId` as a dict:
#!python
{
'id': id of Changeset,
'open': True|False, wheter or not this changeset is open
'tag': {} dict of tags,
'created_at': timestamp of creation of this changeset
'closed_at': timestamp when changeset was closed
'comments_count': amount of comments
'discussion': [] list of comment dict (-> `include_discussion`)
'max_lon': maximum longitude of changes in this changeset
'max_lat': maximum latitude of changes in this changeset
'min_lon': minimum longitude of changes in this changeset
'min_lat': minimum longitude of changes in this changeset
'user': username of user that created this changeset,
'uid': id of user that created this changeset,
}
`ChangesetId` is the unique identifier of a changeset.
If `include_discussion` is set to `True` the changeset discussion
will be available in the result.
"""
path = "/api/0.6/changeset/%s" % (ChangesetId)
if (include_discussion):
path += "?include_discussion=true"
data = self._get(path)
changeset = self._OsmResponseToDom(data, tag="changeset", single=True)
return self._DomParseChangeset(changeset)
def ChangesetUpdate(self, ChangesetTags={}):
"""
Updates current changeset with `ChangesetTags`.
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
If there is no open changeset,
`OsmApi.NoChangesetOpenError` is raised.
"""
if not self._CurrentChangesetId:
raise NoChangesetOpenError("No changeset currently opened")
if "created_by" not in ChangesetTags:
ChangesetTags["created_by"] = self._created_by
self._put(
"/api/0.6/changeset/%s" % (self._CurrentChangesetId),
self._XmlBuild("changeset", {"tag": ChangesetTags}),
return_value=False
)
return self._CurrentChangesetId
def ChangesetCreate(self, ChangesetTags={}):
"""
Opens a changeset.
If `ChangesetTags` are given, this tags are applied (key/value).
Returns `ChangesetId`
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
If there is already an open changeset,
`OsmApi.ChangesetAlreadyOpenError` is raised.
"""
if self._CurrentChangesetId:
raise ChangesetAlreadyOpenError("Changeset already opened")
if "created_by" not in ChangesetTags:
ChangesetTags["created_by"] = self._created_by
result = self._put(
"/api/0.6/changeset/create",
self._XmlBuild("changeset", {"tag": ChangesetTags})
)
self._CurrentChangesetId = int(result)
return self._CurrentChangesetId
def ChangesetClose(self):
"""
Closes current changeset.
Returns `ChangesetId`.
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
If there is no open changeset,
`OsmApi.NoChangesetOpenError` is raised.
"""
if not self._CurrentChangesetId:
raise NoChangesetOpenError("No changeset currently opened")
self._put(
"/api/0.6/changeset/%s/close" % (self._CurrentChangesetId),
"",
return_value=False
)
CurrentChangesetId = self._CurrentChangesetId
self._CurrentChangesetId = 0
return CurrentChangesetId
def ChangesetUpload(self, ChangesData):
"""
Upload data with the `ChangesData` list of dicts:
#!python
{
type: node|way|relation,
action: create|delete|modify,
data: {}
}
Returns list with updated ids.
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
"""
data = ""
data += "\n"
data += "\n"
for change in ChangesData:
data += "<" + change["action"] + ">\n"
change["data"]["changeset"] = self._CurrentChangesetId
data += self._XmlBuild(
change["type"],
change["data"],
False
).decode("utf-8")
data += "" + change["action"] + ">\n"
data += ""
data = self._post(
"/api/0.6/changeset/%s/upload" % (self._CurrentChangesetId),
data.encode("utf-8")
)
try:
data = xml.dom.minidom.parseString(data)
data = data.getElementsByTagName("diffResult")[0]
data = [x for x in data.childNodes if x.nodeType == x.ELEMENT_NODE]
except (xml.parsers.expat.ExpatError, IndexError) as e:
raise XmlResponseInvalidError(
"The XML response from the OSM API is invalid: %r" % e
)
for i in range(len(ChangesData)):
if ChangesData[i]["action"] == "delete":
ChangesData[i]["data"].pop("version")
else:
new_id = int(data[i].getAttribute("new_id"))
ChangesData[i]["data"]["id"] = new_id
new_version = int(data[i].getAttribute("new_version"))
ChangesData[i]["data"]["version"] = new_version
return ChangesData
def ChangesetDownload(self, ChangesetId):
"""
Download data from changeset `ChangesetId`.
Returns list of dict:
#!python
{
'type': node|way|relation,
'action': create|delete|modify,
'data': {}
}
"""
uri = "/api/0.6/changeset/%s/download" % (ChangesetId)
data = self._get(uri)
return self.ParseOsc(data)
def ChangesetsGet( # noqa
self,
min_lon=None,
min_lat=None,
max_lon=None,
max_lat=None,
userid=None,
username=None,
closed_after=None,
created_before=None,
only_open=False,
only_closed=False):
"""
Returns a dict with the id of the changeset as key
matching all criteria:
#!python
{
'1234': dict of ChangesetData,
'5678': dict of ChangesetData,
...
}
All parameters are optional.
"""
uri = "/api/0.6/changesets"
params = {}
if min_lon or min_lat or max_lon or max_lat:
params["bbox"] = ",".join(
[
str(min_lon),
str(min_lat),
str(max_lon),
str(max_lat)
]
)
if userid:
params["user"] = userid
if username:
params["display_name"] = username
if closed_after and not created_before:
params["time"] = closed_after
if created_before:
if not closed_after:
closed_after = "1970-01-01T00:00:00Z"
params["time"] = "%s,%s" % (closed_after, created_before)
if only_open:
params["open"] = 1
if only_closed:
params["closed"] = 1
if params:
uri += "?" + urllib.urlencode(params)
data = self._get(uri)
changesets = self._OsmResponseToDom(data, tag="changeset")
result = {}
for curChangeset in changesets:
tmpCS = self._DomParseChangeset(curChangeset)
result[tmpCS["id"]] = tmpCS
return result
def ChangesetComment(self, ChangesetId, comment):
"""
Adds a comment to the changeset `ChangesetId`
`comment` should be a string.
Returns the updated `ChangesetData` dict:
#!python
{
'id': id of Changeset,
'open': True|False, wheter or not this changeset is open
'tag': {} dict of tags,
'created_at': timestamp of creation of this changeset
'closed_at': timestamp when changeset was closed
'comments_count': amount of comments
'max_lon': maximum longitude of changes in this changeset
'max_lat': maximum latitude of changes in this changeset
'min_lon': minimum longitude of changes in this changeset
'min_lat': minimum longitude of changes in this changeset
'user': username of user that created this changeset,
'uid': id of user that created this changeset,
}
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
"""
params = urllib.urlencode({'text': comment})
data = self._post(
"/api/0.6/changeset/%s/comment" % (ChangesetId),
params
)
changeset = self._OsmResponseToDom(data, tag="changeset", single=True)
return self._DomParseChangeset(changeset)
def ChangesetSubscribe(self, ChangesetId):
"""
Subcribe to the changeset discussion of changeset `ChangesetId`.
The user will be informed about new comments (i.e. receive an email).
Returns the updated `ChangesetData` dict:
#!python
{
'id': id of Changeset,
'open': True|False, wheter or not this changeset is open
'tag': {} dict of tags,
'created_at': timestamp of creation of this changeset
'closed_at': timestamp when changeset was closed
'comments_count': amount of comments
'max_lon': maximum longitude of changes in this changeset
'max_lat': maximum latitude of changes in this changeset
'min_lon': minimum longitude of changes in this changeset
'min_lat': minimum longitude of changes in this changeset
'user': username of user that created this changeset,
'uid': id of user that created this changeset,
}
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
"""
try:
data = self._post(
"/api/0.6/changeset/%s/subscribe" % (ChangesetId),
None
)
except ApiError as e:
if e.status == 409:
raise AlreadySubscribedApiError(e.status, e.reason, e.payload)
else:
raise
changeset = self._OsmResponseToDom(data, tag="changeset", single=True)
return self._DomParseChangeset(changeset)
def ChangesetUnsubscribe(self, ChangesetId):
"""
Subcribe to the changeset discussion of changeset `ChangesetId`.
The user will be informed about new comments (i.e. receive an email).
Returns the updated `ChangesetData` dict:
#!python
{
'id': id of Changeset,
'open': True|False, wheter or not this changeset is open
'tag': {} dict of tags,
'created_at': timestamp of creation of this changeset
'closed_at': timestamp when changeset was closed
'comments_count': amount of comments
'max_lon': maximum longitude of changes in this changeset
'max_lat': maximum latitude of changes in this changeset
'min_lon': minimum longitude of changes in this changeset
'min_lat': minimum longitude of changes in this changeset
'user': username of user that created this changeset,
'uid': id of user that created this changeset,
}
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
"""
try:
data = self._post(
"/api/0.6/changeset/%s/unsubscribe" % (ChangesetId),
None
)
except ApiError as e:
if e.status == 404:
raise NotSubscribedApiError(e.status, e.reason, e.payload)
else:
raise
changeset = self._OsmResponseToDom(data, tag="changeset", single=True)
return self._DomParseChangeset(changeset)
##################################################
# Notes #
##################################################
def NotesGet(
self,
min_lon,
min_lat,
max_lon,
max_lat,
limit=100,
closed=7):
"""
Returns a list of dicts of notes in the specified bounding box:
#!python
[
{
'id': integer,
'action': opened|commented|closed,
'status': open|closed
'date_created': creation date
'date_closed': closing data|None
'uid': User ID|None
'user': User name|None
'comments': {}
},
{ ... }
]
The limit parameter defines how many results should be returned.
closed specifies the number of days a bug needs to be closed
to no longer be returned.
The value 0 means only open bugs are returned,
-1 means all bugs are returned.
All parameters are optional.
"""
uri = (
"/api/0.6/notes?bbox=%f,%f,%f,%f&limit=%d&closed=%d"
% (min_lon, min_lat, max_lon, max_lat, limit, closed)
)
data = self._get(uri)
return self.ParseNotes(data)
def NoteGet(self, id):
"""
Returns a note as dict:
#!python
{
'id': integer,
'action': opened|commented|closed,
'status': open|closed
'date_created': creation date
'date_closed': closing data|None
'uid': User ID|None
'user': User name|None
'comments': {}
}
`id` is the unique identifier of the note.
"""
uri = "/api/0.6/notes/%s" % (id)
data = self._get(uri)
noteElement = self._OsmResponseToDom(data, tag="note", single=True)
return self._DomParseNote(noteElement)
def NoteCreate(self, NoteData):
"""
Creates a note.
Returns updated NoteData (without timestamp).
"""
uri = "/api/0.6/notes"
uri += "?" + urllib.urlencode(NoteData)
return self._NoteAction(uri)
def NoteComment(self, NoteId, comment):
"""
Adds a new comment to a note.
Returns the updated note.
"""
path = "/api/0.6/notes/%s/comment" % NoteId
return self._NoteAction(path, comment)
def NoteClose(self, NoteId, comment):
"""
Closes a note.
Returns the updated note.
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
"""
path = "/api/0.6/notes/%s/close" % NoteId
return self._NoteAction(path, comment, optionalAuth=False)
def NoteReopen(self, NoteId, comment):
"""
Reopens a note.
Returns the updated note.
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
If the requested element has been deleted,
`OsmApi.ElementDeletedApiError` is raised.
"""
path = "/api/0.6/notes/%s/reopen" % NoteId
return self._NoteAction(path, comment, optionalAuth=False)
def NotesSearch(self, query, limit=100, closed=7):
"""
Returns a list of dicts of notes that match the given search query.
The limit parameter defines how many results should be returned.
closed specifies the number of days a bug needs to be closed
to no longer be returned.
The value 0 means only open bugs are returned,
-1 means all bugs are returned.
"""
uri = "/api/0.6/notes/search"
params = {}
params['q'] = query
params['limit'] = limit
params['closed'] = closed
uri += "?" + urllib.urlencode(params)
data = self._get(uri)
return self.ParseNotes(data)
def _NoteAction(self, path, comment=None, optionalAuth=True):
"""
Performs an action on a Note with a comment
Return the updated note
"""
uri = path
if comment is not None:
params = {}
params['text'] = comment
uri += "?" + urllib.urlencode(params)
result = self._post(uri, None, optionalAuth=optionalAuth)
# parse the result
noteElement = self._OsmResponseToDom(result, tag="note", single=True)
return self._DomParseNote(noteElement)
##################################################
# Other #
##################################################
def Map(self, min_lon, min_lat, max_lon, max_lat):
"""
Download data in bounding box.
Returns list of dict:
#!python
{
type: node|way|relation,
data: {}
}
"""
uri = (
"/api/0.6/map?bbox=%f,%f,%f,%f"
% (min_lon, min_lat, max_lon, max_lat)
)
data = self._get(uri)
return self.ParseOsm(data)
##################################################
# Data parser #
##################################################
def ParseOsm(self, data):
"""
Parse osm data.
Returns list of dict:
#!python
{
type: node|way|relation,
data: {}
}
"""
try:
data = xml.dom.minidom.parseString(data)
data = data.getElementsByTagName("osm")[0]
except (xml.parsers.expat.ExpatError, IndexError) as e:
raise XmlResponseInvalidError(
"The XML response from the OSM API is invalid: %r" % e
)
result = []
for elem in data.childNodes:
if elem.nodeName == "node":
result.append({
"type": elem.nodeName,
"data": self._DomParseNode(elem)
})
elif elem.nodeName == "way":
result.append({
"type": elem.nodeName,
"data": self._DomParseWay(elem)
})
elif elem.nodeName == "relation":
result.append({
"type": elem.nodeName,
"data": self._DomParseRelation(elem)
})
return result
def ParseOsc(self, data):
"""
Parse osc data.
Returns list of dict:
#!python
{
type: node|way|relation,
action: create|delete|modify,
data: {}
}
"""
try:
data = xml.dom.minidom.parseString(data)
data = data.getElementsByTagName("osmChange")[0]
except (xml.parsers.expat.ExpatError, IndexError) as e:
raise XmlResponseInvalidError(
"The XML response from the OSM API is invalid: %r" % e
)
result = []
for action in data.childNodes:
if action.nodeName == "#text":
continue
for elem in action.childNodes:
if elem.nodeName == "node":
result.append({
"action": action.nodeName,
"type": elem.nodeName,
"data": self._DomParseNode(elem)
})
elif elem.nodeName == "way":
result.append({
"action": action.nodeName,
"type": elem.nodeName,
"data": self._DomParseWay(elem)
})
elif elem.nodeName == "relation":
result.append({
"action": action.nodeName,
"type": elem.nodeName,
"data": self._DomParseRelation(elem)
})
return result
def ParseNotes(self, data):
"""
Parse notes data.
Returns a list of dict:
#!python
[
{
'id': integer,
'action': opened|commented|closed,
'status': open|closed
'date_created': creation date
'date_closed': closing data|None
'uid': User ID|None
'user': User name|None
'comments': {}
},
{ ... }
]
"""
noteElements = self._OsmResponseToDom(data, tag="note")
result = []
for noteElement in noteElements:
note = self._DomParseNote(noteElement)
result.append(note)
return result
##################################################
# Internal http function #
##################################################
def _do(self, action, OsmType, OsmData):
if self._changesetauto:
self._changesetautodata.append({
"action": action,
"type": OsmType,
"data": OsmData
})
self._changesetautoflush()
return None
else:
return self._do_manu(action, OsmType, OsmData)
def _do_manu(self, action, OsmType, OsmData):
if not self._CurrentChangesetId:
raise NoChangesetOpenError(
"You need to open a changeset before uploading data"
)
if "timestamp" in OsmData:
OsmData.pop("timestamp")
OsmData["changeset"] = self._CurrentChangesetId
if action == "create":
if OsmData.get("id", -1) > 0:
raise OsmTypeAlreadyExistsError(
"This %s already exists" % OsmType
)
result = self._put(
"/api/0.6/%s/create" % OsmType,
self._XmlBuild(OsmType, OsmData)
)
OsmData["id"] = int(result.strip())
OsmData["version"] = 1
return OsmData
elif action == "modify":
result = self._put(
"/api/0.6/%s/%s" % (OsmType, OsmData["id"]),
self._XmlBuild(OsmType, OsmData)
)
OsmData["version"] = int(result.strip())
return OsmData
elif action == "delete":
result = self._delete(
"/api/0.6/%s/%s" % (OsmType, OsmData["id"]),
self._XmlBuild(OsmType, OsmData)
)
OsmData["version"] = int(result.strip())
OsmData["visible"] = False
return OsmData
def flush(self):
"""
Force the changes to be uploaded to OSM and the changeset to be closed
If no authentication information are provided,
`OsmApi.UsernamePasswordMissingError` is raised.
If there is no open changeset,
`OsmApi.NoChangesetOpenError` is raised.
If there is already an open changeset,
`OsmApi.ChangesetAlreadyOpenError` is raised.
"""
return self._changesetautoflush(True)
def _changesetautoflush(self, force=False):
autosize = self._changesetautosize
while ((len(self._changesetautodata) >= autosize) or
(force and self._changesetautodata)):
if self._changesetautocpt == 0:
self.ChangesetCreate(self._changesetautotags)
self.ChangesetUpload(
self._changesetautodata[:autosize]
)
self._changesetautodata = self._changesetautodata[autosize:]
self._changesetautocpt += 1
if self._changesetautocpt == self._changesetautomulti:
self.ChangesetClose()
self._changesetautocpt = 0
if self._changesetautocpt and force:
self.ChangesetClose()
self._changesetautocpt = 0
return None
def _http_request(self, method, path, auth, send, return_value=True): # noqa
"""
Returns the response generated by an HTTP request.
`method` is a HTTP method to be executed
with the request data. For example: 'GET' or 'POST'.
`path` is the path to the requested resource relative to the
base API address stored in self._api. Should start with a
slash character to separate the URL.
`auth` is a boolean indicating whether authentication should
be preformed on this request.
`send` contains additional data that might be sent in a
request.
`return_value` indicates wheter this request should return
any data or not.
If the username or password is missing,
`OsmApi.UsernamePasswordMissingError` is raised.
If the requested element has been deleted,
`OsmApi.ElementDeletedApiError` is raised.
If the response status code indicates an error,
`OsmApi.ApiError` is raised.
"""
if self._debug:
error_msg = (
"%s %s %s"
% (time.strftime("%Y-%m-%d %H:%M:%S"), method, path)
)
print(error_msg, file=sys.stderr)
# Add API base URL to path
path = self._api + path
user_pass = None
if auth:
try:
user_pass = (self._username, self._password)
except AttributeError:
raise UsernamePasswordMissingError("Username/Password missing")
response = self._session.request(method, path, auth=user_pass,
data=send)
if response.status_code != 200:
payload = response.content.strip()
if response.status_code == 410:
raise ElementDeletedApiError(
response.status_code,
response.reason,
payload
)
raise ApiError(response.status_code, response.reason, payload)
if return_value and not response.content:
raise ResponseEmptyApiError(
response.status_code,
response.reason,
''
)
if self._debug:
error_msg = (
"%s %s %s"
% (time.strftime("%Y-%m-%d %H:%M:%S"), method, path)
)
print(error_msg, file=sys.stderr)
return response.content
def _http(self, cmd, path, auth, send, return_value=True): # noqa
i = 0
while True:
i += 1
try:
return self._http_request(
cmd,
path,
auth,
send,
return_value=return_value
)
except ApiError as e:
if e.status >= 500:
if i == self.MAX_RETRY_LIMIT:
raise
if i != 1:
self._sleep()
self._session = self._get_http_session()
else:
raise
except Exception as e:
print(e)
if i == self.MAX_RETRY_LIMIT:
if isinstance(e, OsmApiError):
raise
raise MaximumRetryLimitReachedError(
"Give up after %s retries" % i
)
if i != 1:
self._sleep()
self._session = self._get_http_session()
def _get_http_session(self):
"""
Creates a requests session for connection pooling.
"""
session = requests.Session()
session.headers.update({
'user-agent': self._created_by
})
return session
def _sleep(self):
time.sleep(5)
def _get(self, path):
return self._http('GET', path, False, None)
def _put(self, path, data, return_value=True):
return self._http('PUT', path, True, data, return_value=return_value)
def _post(self, path, data, optionalAuth=False):
auth = True
# the Notes API allows certain POSTs by non-authenticated users
if optionalAuth:
auth = hasattr(self, '_username')
return self._http('POST', path, auth, data)
def _delete(self, path, data):
return self._http('DELETE', path, True, data)
##################################################
# Internal dom function #
##################################################
def _OsmResponseToDom(self, response, tag, single=False):
"""
Returns the (sub-) DOM parsed from an OSM response
"""
try:
dom = xml.dom.minidom.parseString(response)
osm_dom = dom.getElementsByTagName("osm")[0]
all_data = osm_dom.getElementsByTagName(tag)
first_element = all_data[0]
except (xml.parsers.expat.ExpatError, IndexError) as e:
raise XmlResponseInvalidError(
"The XML response from the OSM API is invalid: %r" % e
)
if single:
return first_element
return all_data
def _DomGetAttributes(self, DomElement): # noqa
"""
Returns a formated dictionnary of attributes of a DomElement.
"""
result = {}
for k, v in DomElement.attributes.items():
if k == "uid":
v = int(v)
elif k == "changeset":
v = int(v)
elif k == "version":
v = int(v)
elif k == "id":
v = int(v)
elif k == "lat":
v = float(v)
elif k == "lon":
v = float(v)
elif k == "open":
v = (v == "true")
elif k == "visible":
v = (v == "true")
elif k == "ref":
v = int(v)
elif k == "comments_count":
v = int(v)
elif k == "timestamp":
v = self._ParseDate(v)
elif k == "created_at":
v = self._ParseDate(v)
elif k == "closed_at":
v = self._ParseDate(v)
elif k == "date":
v = self._ParseDate(v)
result[k] = v
return result
def _DomGetTag(self, DomElement):
"""
Returns the dictionnary of tags of a DomElement.
"""
result = {}
for t in DomElement.getElementsByTagName("tag"):
k = t.attributes["k"].value
v = t.attributes["v"].value
result[k] = v
return result
def _DomGetNd(self, DomElement):
"""
Returns the list of nodes of a DomElement.
"""
result = []
for t in DomElement.getElementsByTagName("nd"):
result.append(int(int(t.attributes["ref"].value)))
return result
def _DomGetDiscussion(self, DomElement):
"""
Returns the dictionnary of comments of a DomElement.
"""
result = []
try:
discussion = DomElement.getElementsByTagName("discussion")[0]
for t in discussion.getElementsByTagName("comment"):
comment = self._DomGetAttributes(t)
comment['text'] = self._GetXmlValue(t, "text")
result.append(comment)
except IndexError:
pass
return result
def _DomGetComments(self, DomElement):
"""
Returns the list of comments of a DomElement.
"""
result = []
for t in DomElement.getElementsByTagName("comment"):
comment = {}
comment['date'] = self._ParseDate(self._GetXmlValue(t, "date"))
comment['action'] = self._GetXmlValue(t, "action")
comment['text'] = self._GetXmlValue(t, "text")
comment['html'] = self._GetXmlValue(t, "html")
comment['uid'] = self._GetXmlValue(t, "uid")
comment['user'] = self._GetXmlValue(t, "user")
result.append(comment)
return result
def _DomGetMember(self, DomElement):
"""
Returns a list of relation members.
"""
result = []
for m in DomElement.getElementsByTagName("member"):
result.append(self._DomGetAttributes(m))
return result
def _DomParseNode(self, DomElement):
"""
Returns NodeData for the node.
"""
result = self._DomGetAttributes(DomElement)
result["tag"] = self._DomGetTag(DomElement)
return result
def _DomParseWay(self, DomElement):
"""
Returns WayData for the way.
"""
result = self._DomGetAttributes(DomElement)
result["tag"] = self._DomGetTag(DomElement)
result["nd"] = self._DomGetNd(DomElement)
return result
def _DomParseRelation(self, DomElement):
"""
Returns RelationData for the relation.
"""
result = self._DomGetAttributes(DomElement)
result["tag"] = self._DomGetTag(DomElement)
result["member"] = self._DomGetMember(DomElement)
return result
def _DomParseChangeset(self, DomElement):
"""
Returns ChangesetData for the changeset.
"""
result = self._DomGetAttributes(DomElement)
result["tag"] = self._DomGetTag(DomElement)
result["discussion"] = self._DomGetDiscussion(DomElement)
return result
def _DomParseNote(self, DomElement):
"""
Returns NoteData for the note.
"""
result = self._DomGetAttributes(DomElement)
result["id"] = self._GetXmlValue(DomElement, "id")
result["status"] = self._GetXmlValue(DomElement, "status")
result["date_created"] = self._ParseDate(
self._GetXmlValue(DomElement, "date_created")
)
result["date_closed"] = self._ParseDate(
self._GetXmlValue(DomElement, "date_closed")
)
result["comments"] = self._DomGetComments(DomElement)
return result
def _ParseDate(self, DateString):
result = DateString
try:
result = datetime.strptime(DateString, "%Y-%m-%d %H:%M:%S UTC")
except Exception:
try:
result = datetime.strptime(DateString, "%Y-%m-%dT%H:%M:%SZ")
except Exception:
pass
return result
##################################################
# Internal xml builder #
##################################################
def _XmlBuild(self, ElementType, ElementData, WithHeaders=True): # noqa
xml = ""
if WithHeaders:
xml += "\n"
xml += "\n"
#
xml += " <" + ElementType
if "id" in ElementData:
xml += " id=\"" + str(ElementData["id"]) + "\""
if "lat" in ElementData:
xml += " lat=\"" + str(ElementData["lat"]) + "\""
if "lon" in ElementData:
xml += " lon=\"" + str(ElementData["lon"]) + "\""
if "version" in ElementData:
xml += " version=\"" + str(ElementData["version"]) + "\""
visible_str = str(ElementData.get("visible", True)).lower()
xml += " visible=\"" + visible_str + "\""
if ElementType in ["node", "way", "relation"]:
xml += " changeset=\"" + str(self._CurrentChangesetId) + "\""
xml += ">\n"
#
for k, v in ElementData.get("tag", {}).items():
xml += " \n"
#
for member in ElementData.get("member", []):
xml += " \n"
#
for ref in ElementData.get("nd", []):
xml += " \n"
#
xml += " " + ElementType + ">\n"
if WithHeaders:
xml += "\n"
return xml.encode("utf8")
def _XmlEncode(self, text):
return (
text
.replace("&", "&")
.replace("\"", """)
.replace("<", "<")
.replace(">", ">")
)
def _GetXmlValue(self, DomElement, tag):
try:
elem = DomElement.getElementsByTagName(tag)[0]
return elem.firstChild.nodeValue
except Exception:
return None
osmapi-1.2.2/osmapi/__init__.py 0000664 0000000 0000000 00000000201 13370515543 0016404 0 ustar 00root root 0000000 0000000 from __future__ import (absolute_import, print_function, unicode_literals)
__version__ = '1.2.2'
from .OsmApi import * # noqa
osmapi-1.2.2/requirements.txt 0000664 0000000 0000000 00000000306 13370515543 0016275 0 ustar 00root root 0000000 0000000 # This file lists the dependencies of this extension.
# Install with a command like: pip install -r pip-requirements.txt
pdoc==0.3.2
Pygments==2.2.0
pypandoc==1.4
requests==2.20.0
Unidecode==1.0.22
osmapi-1.2.2/setup.cfg 0000664 0000000 0000000 00000000106 13370515543 0014630 0 ustar 00root root 0000000 0000000 [metadata]
description-file = README.md
[flake8]
max-complexity = 10
osmapi-1.2.2/setup.py 0000664 0000000 0000000 00000003502 13370515543 0014524 0 ustar 00root root 0000000 0000000 # -*- coding: utf-8 -*-
from codecs import open
from setuptools import setup
import re
with open('osmapi/__init__.py', 'r') as fd:
version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]',
fd.read(), re.MULTILINE).group(1)
if not version:
raise RuntimeError('Cannot find version information')
try:
import pypandoc
from unidecode import unidecode
description = open('README.md', encoding='utf-8').read()
description = unidecode(description)
description = pypandoc.convert(description, 'rst', format='md')
except (IOError, OSError, ImportError):
description = 'Python wrapper for the OSM API'
setup(
name='osmapi',
packages=['osmapi'],
version=version,
install_requires=['requests'],
description='Python wrapper for the OSM API',
long_description=description,
author='Etienne Chové',
author_email='chove@crans.org',
maintainer='Stefan Oderbolz',
maintainer_email='odi@metaodi.ch',
url='https://github.com/metaodi/osmapi',
download_url='https://github.com/metaodi/osmapi/archive/v%s.zip' % version,
keywords=['openstreetmap', 'osm', 'api'],
license='GPLv3',
classifiers=[
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
'Intended Audience :: Developers',
'Topic :: Scientific/Engineering :: GIS',
'Topic :: Software Development :: Libraries',
'Development Status :: 4 - Beta',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
],
)
osmapi-1.2.2/test-requirements.txt 0000664 0000000 0000000 00000000360 13370515543 0017252 0 ustar 00root root 0000000 0000000 # This file lists the dependencies of this extension.
# Install with a command like: pip install -r pip-requirements.txt
coverage==4.5.1
coveralls==1.5.1
flake8==3.6.0
mock==2.0.0
nose==1.3.7
tox==3.5.3
virtualenv==16.1.0
xmltodict==0.11.0
osmapi-1.2.2/tests/ 0000775 0000000 0000000 00000000000 13370515543 0014154 5 ustar 00root root 0000000 0000000 osmapi-1.2.2/tests/__init__.py 0000664 0000000 0000000 00000000000 13370515543 0016253 0 ustar 00root root 0000000 0000000 osmapi-1.2.2/tests/capabilities_test.py 0000664 0000000 0000000 00000001315 13370515543 0020216 0 ustar 00root root 0000000 0000000 from __future__ import (unicode_literals, absolute_import)
from . import osmapi_tests
class TestOsmApiNode(osmapi_tests.TestOsmApi):
def test_Capabilities(self):
self._session_mock()
result = self.api.Capabilities()
self.assertEquals(result, {
'area': {'maximum': 0.25},
'changesets': {'maximum_elements': 50000.0},
'status': {
'api': 'mocked',
'database': 'online',
'gpx': 'online'
},
'timeout': {'seconds': 300.0},
'tracepoints': {'per_page': 5000.0},
'version': {'maximum': 0.6, 'minimum': 0.6},
'waynodes': {'maximum': 2000.0}
})
osmapi-1.2.2/tests/changeset_tests.py 0000664 0000000 0000000 00000062614 13370515543 0017722 0 ustar 00root root 0000000 0000000 from __future__ import (unicode_literals, absolute_import)
from . import osmapi_tests
import osmapi
import mock
import xmltodict
import datetime
try:
import urlparse
except Exception:
import urllib
urlparse = urllib.parse
def recursive_sort(col): # noqa
"""
Function to recursive sort a collection
that might contain lists, dicts etc.
In Python 3.x a list of dicts is sorted by it's hash
"""
if hasattr(col, '__iter__'):
if isinstance(col, list):
try:
col = sorted(col)
except TypeError: # in Python 3.x: lists of dicts are not sortable
col = sorted(col, key=lambda k: hash(frozenset(k.items())))
except Exception:
pass
for idx, elem in enumerate(col):
col[idx] = recursive_sort(elem)
elif isinstance(col, dict):
for elem in col:
try:
col[elem] = recursive_sort(col[elem])
except IndexError:
pass
return col
def xmltosorteddict(xml):
xml_dict = xmltodict.parse(xml, dict_constructor=dict)
return recursive_sort(xml_dict)
class TestOsmApiChangeset(osmapi_tests.TestOsmApi):
def test_ChangesetGet(self):
self._session_mock()
result = self.api.ChangesetGet(123)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1], self.api_base + '/api/0.6/changeset/123')
self.assertEquals(result, {
'id': 123,
'closed_at': datetime.datetime(2009, 9, 7, 22, 57, 37),
'created_at': datetime.datetime(2009, 9, 7, 21, 57, 36),
'discussion': [],
'max_lat': '52.4710193',
'max_lon': '-1.4831815',
'min_lat': '45.9667901',
'min_lon': '-1.4998534',
'open': False,
'user': 'randomjunk',
'uid': 3,
'tag': {
'comment': 'correct node bug',
'created_by': 'Potlatch 1.2a',
},
})
def test_ChangesetUpdate(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=4444
)
self.api._CurrentChangesetId = 4444
result = self.api.ChangesetUpdate(
{
'test': 'foobar'
}
)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'PUT')
self.assertEquals(args[1], self.api_base + '/api/0.6/changeset/4444')
self.assertEquals(
xmltosorteddict(kwargs['data']),
xmltosorteddict(
b'\n'
b'\n'
b' \n'
b' \n'
b' \n'
b' \n'
b'\n'
)
)
self.assertEquals(result, 4444)
def test_ChangesetUpdate_with_created_by(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=4444
)
self.api._CurrentChangesetId = 4444
result = self.api.ChangesetUpdate(
{
'test': 'foobar',
'created_by': 'MyTestOSMApp'
}
)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'PUT')
self.assertEquals(args[1], self.api_base + '/api/0.6/changeset/4444')
self.assertEquals(
xmltosorteddict(kwargs['data']),
xmltosorteddict(
b'\n'
b'\n'
b' \n'
b' \n'
b' \n'
b' \n'
b'\n'
)
)
self.assertEquals(result, 4444)
def test_ChangesetUpdate_wo_changeset(self):
self._session_mock()
with self.assertRaisesRegexp(
osmapi.NoChangesetOpenError,
'No changeset currently opened'):
self.api.ChangesetUpdate(
{
'test': 'foobar'
}
)
def test_ChangesetCreate(self):
self._session_mock(auth=True)
result = self.api.ChangesetCreate(
{
'foobar': 'A new test changeset'
}
)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'PUT')
self.assertEquals(args[1], self.api_base + '/api/0.6/changeset/create')
self.assertEquals(
xmltosorteddict(kwargs['data']),
xmltosorteddict(
b'\n'
b'\n'
b' \n'
b' \n'
b' \n'
b' \n'
b'\n'
)
)
self.assertEquals(result, 4321)
def test_ChangesetCreate_with_created_by(self):
self._session_mock(auth=True)
result = self.api.ChangesetCreate(
{
'foobar': 'A new test changeset',
'created_by': 'CoolTestApp',
}
)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'PUT')
self.assertEquals(args[1], self.api_base + '/api/0.6/changeset/create')
self.assertEquals(
xmltosorteddict(kwargs['data']),
xmltosorteddict(
b'\n'
b'\n'
b' \n'
b' \n'
b' \n'
b' \n'
b'\n'
)
)
self.assertEquals(result, 1234)
def test_ChangesetCreate_with_open_changeset(self):
self._session_mock(auth=True)
self.api.ChangesetCreate(
{
'test': 'an already open changeset',
}
)
with self.assertRaisesRegexp(
osmapi.ChangesetAlreadyOpenError,
'Changeset already opened'):
self.api.ChangesetCreate(
{
'test': 'foobar'
}
)
def test_ChangesetClose(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=4444
)
self.api._CurrentChangesetId = 4444
self.api.ChangesetClose()
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'PUT')
self.assertEquals(args[1],
self.api_base + '/api/0.6/changeset/4444/close')
def test_ChangesetClose_with_no_changeset(self):
self._session_mock()
with self.assertRaisesRegexp(
osmapi.NoChangesetOpenError,
'No changeset currently opened'):
self.api.ChangesetClose()
def test_ChangesetUpload_create_node(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=4444
)
self.api._CurrentChangesetId = 4444
changesdata = [
{
'type': 'node',
'action': 'create',
'data': {
'lat': 47.123,
'lon': 8.555,
'tag': {
'amenity': 'place_of_worship',
'religion': 'pastafarian'
}
}
}
]
result = self.api.ChangesetUpload(changesdata)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'POST')
self.assertEquals(args[1],
self.api_base + '/api/0.6/changeset/4444/upload')
self.assertEquals(
xmltosorteddict(kwargs['data']),
xmltosorteddict(
b'\n'
b'\n'
b'\n'
b' \n'
b' \n'
b' \n'
b' \n'
b'\n'
b''
)
)
self.assertEquals(result[0]['type'], changesdata[0]['type'])
self.assertEquals(result[0]['action'], changesdata[0]['action'])
data = result[0]['data']
self.assertEquals(data['lat'], changesdata[0]['data']['lat'])
self.assertEquals(data['lon'], changesdata[0]['data']['lon'])
self.assertEquals(data['tag'], changesdata[0]['data']['tag'])
self.assertEquals(data['id'], 4295832900)
self.assertEquals(result[0]['data']['version'], 1)
def test_ChangesetUpload_modify_way(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=4444
)
self.api._CurrentChangesetId = 4444
changesdata = [
{
'type': 'way',
'action': 'modify',
'data': {
'id': 4294967296,
'version': 2,
'nd': [
4295832773,
4295832773,
4294967304,
4294967303,
4294967300,
4608751,
4294967305,
4294967302,
8548430,
4294967296,
4294967301,
4294967298,
4294967306,
7855737,
4294967297,
4294967299
],
'tag': {
'highway': 'secondary',
'name': 'Stansted Road'
}
}
}
]
result = self.api.ChangesetUpload(changesdata)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'POST')
self.assertEquals(args[1],
self.api_base + '/api/0.6/changeset/4444/upload')
self.assertEquals(
xmltosorteddict(kwargs['data']),
xmltosorteddict(
b'\n'
b'\n'
b'\n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b'\n'
b''
)
)
self.assertEquals(result[0]['type'], changesdata[0]['type'])
self.assertEquals(result[0]['action'], changesdata[0]['action'])
data = result[0]['data']
self.assertEquals(data['nd'], changesdata[0]['data']['nd'])
self.assertEquals(data['tag'], changesdata[0]['data']['tag'])
self.assertEquals(data['id'], 4294967296)
self.assertEquals(data['version'], 3)
def test_ChangesetUpload_delete_relation(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=4444
)
self.api._CurrentChangesetId = 4444
changesdata = [
{
'type': 'relation',
'action': 'delete',
'data': {
'id': 676,
'version': 2,
'member': [
{
'ref': 4799,
'role': 'outer',
'type': 'way'
},
{
'ref': 9391,
'role': 'outer',
'type': 'way'
},
],
'tag': {
'admin_level': '9',
'boundary': 'administrative',
'type': 'multipolygon'
}
}
}
]
result = self.api.ChangesetUpload(changesdata)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'POST')
self.assertEquals(args[1],
self.api_base + '/api/0.6/changeset/4444/upload')
self.assertEquals(
xmltosorteddict(kwargs['data']),
xmltosorteddict(
b'\n'
b'\n'
b'\n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b' \n'
b'\n'
b''
)
)
self.assertEquals(result[0]['type'], changesdata[0]['type'])
self.assertEquals(result[0]['action'], changesdata[0]['action'])
data = result[0]['data']
self.assertEquals(data['member'], changesdata[0]['data']['member'])
self.assertEquals(data['tag'], changesdata[0]['data']['tag'])
self.assertEquals(data['id'], 676)
self.assertNotIn('version', data)
def test_ChangesetUpload_invalid_response(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=4444
)
self.api._CurrentChangesetId = 4444
changesdata = [
{
'type': 'relation',
'action': 'delete',
'data': {
'id': 676,
'version': 2,
'member': [
{
'ref': 4799,
'role': 'outer',
'type': 'way'
},
{
'ref': 9391,
'role': 'outer',
'type': 'way'
},
],
'tag': {
'admin_level': '9',
'boundary': 'administrative',
'type': 'multipolygon'
}
}
}
]
with self.assertRaises(osmapi.XmlResponseInvalidError):
self.api.ChangesetUpload(changesdata)
def test_ChangesetDownload(self):
self._session_mock()
result = self.api.ChangesetDownload(23123)
args, _ = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1],
self.api_base + '/api/0.6/changeset/23123/download')
self.assertEquals(len(result), 16)
self.assertEquals(
result[1],
{
'action': 'create',
'type': 'node',
'data': {
'changeset': 23123,
'id': 4295668171,
'lat': 46.4909781,
'lon': 11.2743295,
'tag': {
'highway': 'traffic_signals'
},
'timestamp': datetime.datetime(2013, 5, 14, 10, 33, 4),
'uid': 1178,
'user': 'tyrTester06',
'version': 1,
'visible': True
}
}
)
def test_ChangesetDownload_invalid_response(self):
self._session_mock()
with self.assertRaises(osmapi.XmlResponseInvalidError):
self.api.ChangesetDownload(23123)
def test_ChangesetDownloadContainingUnicode(self):
self._session_mock()
# This changeset contains unicode tag values
# Note that the fixture data has been reduced from the
# original from openstreetmap.org
result = self.api.ChangesetDownload(37393499)
self.assertEquals(len(result), 2)
self.assertEquals(
result[1],
{
'action': 'create',
'type': 'way',
'data': {
'changeset': 37393499,
'id': 399491497,
'nd': [4022271571, 4022271567, 4022271565],
'tag': {'highway': 'service',
# UTF-8 encoded 'LATIN SMALL LETTER O WITH STROKE'
# Aka. 0xf8 in latin-1/ISO 8859-1
'name': b'S\xc3\xb8nderskovvej'.decode('utf-8'),
'service': 'driveway'},
'timestamp': datetime.datetime(2016, 2, 23, 16, 55, 35),
'uid': 328556,
'user': 'InternationalUser',
'version': 1,
'visible': True
}
}
)
def test_ChangesetsGet(self):
self._session_mock()
result = self.api.ChangesetsGet(
only_closed=True,
username='metaodi'
)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(
dict(urlparse.parse_qsl(urlparse.urlparse(args[1])[4])),
{
'display_name': 'metaodi',
'closed': '1'
}
)
self.assertEquals(len(result), 10)
self.assertEquals(result[41417], {
'closed_at': datetime.datetime(2014, 4, 29, 20, 25, 1),
'created_at': datetime.datetime(2014, 4, 29, 20, 25, 1),
'id': 41417,
'discussion': [],
'max_lat': '58.8997467',
'max_lon': '22.7364427',
'min_lat': '58.8501594',
'min_lon': '22.6984333',
'open': False,
'tag': {
'comment': 'Test delete of relation',
'created_by': 'iD 1.3.9',
'imagery_used': 'Bing'
},
'uid': 1841,
'user': 'metaodi'
})
def test_ChangesetGetWithComment(self):
self._session_mock()
result = self.api.ChangesetGet(52924, include_discussion=True)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(
args[1],
self.api_base + '/api/0.6/changeset/52924?include_discussion=true'
)
self.assertEquals(result, {
'id': 52924,
'closed_at': datetime.datetime(2015, 1, 1, 14, 54, 2),
'created_at': datetime.datetime(2015, 1, 1, 14, 54, 1),
'comments_count': 3,
'max_lat': '58.3369242',
'max_lon': '25.8829107',
'min_lat': '58.336813',
'min_lon': '25.8823273',
'discussion': [
{
'date': datetime.datetime(2015, 1, 1, 18, 56, 48),
'text': 'test',
'uid': 1841,
'user': 'metaodi',
},
{
'date': datetime.datetime(2015, 1, 1, 18, 58, 3),
'text': 'another comment',
'uid': 1841,
'user': 'metaodi',
},
{
'date': datetime.datetime(2015, 1, 1, 19, 16, 5),
'text': 'hello',
'uid': 1841,
'user': 'metaodi',
},
],
'open': False,
'user': 'metaodi',
'uid': 1841,
'tag': {
'comment': 'My test',
'created_by': 'osmapi/0.4.1',
},
})
def test_ChangesetComment(self):
self._session_mock(auth=True)
result = self.api.ChangesetComment(
123,
comment="test comment"
)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'POST')
self.assertEquals(args[1],
self.api_base + '/api/0.6/changeset/123/comment')
self.assertEquals(
kwargs['data'],
"text=test+comment"
)
self.assertEquals(result, {
'id': 123,
'closed_at': datetime.datetime(2009, 9, 7, 22, 57, 37),
'created_at': datetime.datetime(2009, 9, 7, 21, 57, 36),
'discussion': [],
'max_lat': '52.4710193',
'max_lon': '-1.4831815',
'min_lat': '45.9667901',
'min_lon': '-1.4998534',
'open': False,
'user': 'randomjunk',
'uid': 3,
'tag': {
'comment': 'correct node bug',
'created_by': 'Potlatch 1.2a',
},
})
def test_ChangesetSubscribe(self):
self._session_mock(auth=True)
result = self.api.ChangesetSubscribe(123)
args, _ = self.api._session.request.call_args
self.assertEquals(args[0], 'POST')
self.assertEquals(args[1],
self.api_base + '/api/0.6/changeset/123/subscribe')
self.assertEquals(result, {
'id': 123,
'closed_at': datetime.datetime(2009, 9, 7, 22, 57, 37),
'created_at': datetime.datetime(2009, 9, 7, 21, 57, 36),
'discussion': [],
'max_lat': '52.4710193',
'max_lon': '-1.4831815',
'min_lat': '45.9667901',
'min_lon': '-1.4998534',
'open': False,
'user': 'randomjunk',
'uid': 3,
'tag': {
'comment': 'correct node bug',
'created_by': 'Potlatch 1.2a',
},
})
def test_ChangesetSubscribeWhenAlreadySubscribed(self):
self._session_mock(auth=True, status=409)
with self.assertRaises(osmapi.AlreadySubscribedApiError) as cm:
self.api.ChangesetSubscribe(52924)
self.assertEquals(cm.exception.status, 409)
self.assertEquals(
cm.exception.payload,
"You are already subscribed to changeset 52924."
)
def test_ChangesetUnsubscribe(self):
self._session_mock(auth=True)
result = self.api.ChangesetUnsubscribe(123)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'POST')
self.assertEquals(args[1],
self.api_base + '/api/0.6/changeset/123/unsubscribe')
self.assertEquals(result, {
'id': 123,
'closed_at': datetime.datetime(2009, 9, 7, 22, 57, 37),
'created_at': datetime.datetime(2009, 9, 7, 21, 57, 36),
'discussion': [],
'max_lat': '52.4710193',
'max_lon': '-1.4831815',
'min_lat': '45.9667901',
'min_lon': '-1.4998534',
'open': False,
'user': 'randomjunk',
'uid': 3,
'tag': {
'comment': 'correct node bug',
'created_by': 'Potlatch 1.2a',
},
})
def test_ChangesetUnsubscribeWhenNotSubscribed(self):
self._session_mock(auth=True, status=404)
with self.assertRaises(osmapi.NotSubscribedApiError) as cm:
self.api.ChangesetUnsubscribe(52924)
self.assertEquals(cm.exception.status, 404)
self.assertEquals(
cm.exception.payload,
"You are not subscribed to changeset 52924."
)
osmapi-1.2.2/tests/fixtures/ 0000775 0000000 0000000 00000000000 13370515543 0016025 5 ustar 00root root 0000000 0000000 osmapi-1.2.2/tests/fixtures/passwordfile.txt 0000664 0000000 0000000 00000000047 13370515543 0021271 0 ustar 00root root 0000000 0000000 testosm:testpass
testuser:testuserpass
osmapi-1.2.2/tests/fixtures/test_Capabilities.xml 0000664 0000000 0000000 00000001026 13370515543 0022176 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_ChangesetClose.xml 0000664 0000000 0000000 00000000000 13370515543 0022463 0 ustar 00root root 0000000 0000000 osmapi-1.2.2/tests/fixtures/test_ChangesetComment.xml 0000664 0000000 0000000 00000001067 13370515543 0023036 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_ChangesetCreate.xml 0000664 0000000 0000000 00000000005 13370515543 0022626 0 ustar 00root root 0000000 0000000 4321
osmapi-1.2.2/tests/fixtures/test_ChangesetCreate_with_created_by.xml 0000664 0000000 0000000 00000000005 13370515543 0026042 0 ustar 00root root 0000000 0000000 1234
osmapi-1.2.2/tests/fixtures/test_ChangesetCreate_with_open_changeset.xml 0000664 0000000 0000000 00000000005 13370515543 0026723 0 ustar 00root root 0000000 0000000 4444
osmapi-1.2.2/tests/fixtures/test_ChangesetDownload.xml 0000664 0000000 0000000 00000010363 13370515543 0023202 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_ChangesetDownloadContainingUnicode.xml 0000664 0000000 0000000 00000001723 13370515543 0026523 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_ChangesetDownload_invalid_response.xml 0000664 0000000 0000000 00000000047 13370515543 0026624 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_ChangesetGet.xml 0000664 0000000 0000000 00000001067 13370515543 0022153 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_ChangesetGetWithComment.xml 0000664 0000000 0000000 00000001703 13370515543 0024327 0 ustar 00root root 0000000 0000000
test
another comment
hello
osmapi-1.2.2/tests/fixtures/test_ChangesetSubscribe.xml 0000664 0000000 0000000 00000001067 13370515543 0023355 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_ChangesetSubscribeWhenAlreadySubscribed.xml 0000664 0000000 0000000 00000000057 13370515543 0027505 0 ustar 00root root 0000000 0000000 You are already subscribed to changeset 52924.
osmapi-1.2.2/tests/fixtures/test_ChangesetUnsubscribe.xml 0000664 0000000 0000000 00000001067 13370515543 0023720 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_ChangesetUnsubscribeWhenNotSubscribed.xml 0000664 0000000 0000000 00000000053 13370515543 0027223 0 ustar 00root root 0000000 0000000 You are not subscribed to changeset 52924.
osmapi-1.2.2/tests/fixtures/test_ChangesetUpdate.xml 0000664 0000000 0000000 00000000005 13370515543 0022645 0 ustar 00root root 0000000 0000000 4444
osmapi-1.2.2/tests/fixtures/test_ChangesetUpdate_with_created_by.xml 0000664 0000000 0000000 00000000005 13370515543 0026061 0 ustar 00root root 0000000 0000000 4444
osmapi-1.2.2/tests/fixtures/test_ChangesetUpdate_wo_changeset.xml 0000664 0000000 0000000 00000000000 13370515543 0025366 0 ustar 00root root 0000000 0000000 osmapi-1.2.2/tests/fixtures/test_ChangesetUpload_create_node.xml 0000664 0000000 0000000 00000000505 13370515543 0025204 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_ChangesetUpload_delete_relation.xml 0000664 0000000 0000000 00000000446 13370515543 0026077 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_ChangesetUpload_invalid_response.xml 0000664 0000000 0000000 00000000047 13370515543 0026301 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_ChangesetUpload_modify_way.xml 0000664 0000000 0000000 00000000514 13370515543 0025103 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_ChangesetsGet.xml 0000664 0000000 0000000 00000005370 13370515543 0022337 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_NodeCreate.xml 0000664 0000000 0000000 00000000005 13370515543 0021612 0 ustar 00root root 0000000 0000000 9876
osmapi-1.2.2/tests/fixtures/test_NodeCreate_changesetauto.xml 0000664 0000000 0000000 00000000005 13370515543 0024524 0 ustar 00root root 0000000 0000000 7676
osmapi-1.2.2/tests/fixtures/test_NodeDelete.xml 0000664 0000000 0000000 00000000002 13370515543 0021606 0 ustar 00root root 0000000 0000000 4
osmapi-1.2.2/tests/fixtures/test_NodeGet.xml 0000664 0000000 0000000 00000001016 13370515543 0021131 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_NodeGet_invalid_response.xml 0000664 0000000 0000000 00000000143 13370515543 0024555 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_NodeGet_with_version.xml 0000664 0000000 0000000 00000000704 13370515543 0023734 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_NodeHistory.xml 0000664 0000000 0000000 00000003630 13370515543 0022057 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_NodeRelations.xml 0000664 0000000 0000000 00000001441 13370515543 0022354 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_NodeUpdate.xml 0000664 0000000 0000000 00000000002 13370515543 0021626 0 ustar 00root root 0000000 0000000 3
osmapi-1.2.2/tests/fixtures/test_NodeWays.xml 0000664 0000000 0000000 00000001070 13370515543 0021335 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_NodesGet.xml 0000664 0000000 0000000 00000001204 13370515543 0021313 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_NoteClose.xml 0000664 0000000 0000000 00000002126 13370515543 0021502 0 ustar 00root root 0000000 0000000
815
http://api06.dev.openstreetmap.org/api/0.6/notes/815
http://api06.dev.openstreetmap.org/api/0.6/notes/815/reopen
2014-10-03 15:20:57 UTC
closed
2014-10-05 16:35:13 UTC
2014-10-03 15:20:57 UTC
1841
metaodi
http://master.apis.dev.openstreetmap.org/user/metaodi
opened
This is a test
<p>This is a test</p>
2014-10-05 16:35:13 UTC
1841
metaodi
http://master.apis.dev.openstreetmap.org/user/metaodi
closed
Close this note!
<p>Close this note!</p>
osmapi-1.2.2/tests/fixtures/test_NoteComment.xml 0000664 0000000 0000000 00000002173 13370515543 0022041 0 ustar 00root root 0000000 0000000
812
http://api06.dev.openstreetmap.org/api/0.6/notes/812
http://api06.dev.openstreetmap.org/api/0.6/notes/812/comment
http://api06.dev.openstreetmap.org/api/0.6/notes/812/close
2014-10-03 15:11:05 UTC
open
2014-10-03 15:11:05 UTC
1841
metaodi
http://master.apis.dev.openstreetmap.org/user/metaodi
opened
This is a test
<p>This is a test</p>
2014-10-04 22:36:35 UTC
1841
metaodi
http://master.apis.dev.openstreetmap.org/user/metaodi
commented
This is a comment
<p>This is a comment</p>
osmapi-1.2.2/tests/fixtures/test_NoteCommentAnonymous.xml 0000664 0000000 0000000 00000001534 13370515543 0023752 0 ustar 00root root 0000000 0000000
842
http://api06.dev.openstreetmap.org/api/0.6/notes/842
http://api06.dev.openstreetmap.org/api/0.6/notes/842/comment
http://api06.dev.openstreetmap.org/api/0.6/notes/842/close
2015-01-03 10:49:39 UTC
open
2015-01-03 10:49:39 UTC
opened
test 123
<p>test 123</p>
2015-01-03 11:06:00 UTC
commented
blubb
<p>blubb</p>
osmapi-1.2.2/tests/fixtures/test_NoteCreate.xml 0000664 0000000 0000000 00000001463 13370515543 0021643 0 ustar 00root root 0000000 0000000
816
http://api06.dev.openstreetmap.org/api/0.6/notes/816
http://api06.dev.openstreetmap.org/api/0.6/notes/816/comment
http://api06.dev.openstreetmap.org/api/0.6/notes/816/close
2014-10-03 15:21:21 UTC
open
2014-10-03 15:21:22 UTC
1841
metaodi
http://master.apis.dev.openstreetmap.org/user/metaodi
opened
This is a test
<p>This is a test</p>
osmapi-1.2.2/tests/fixtures/test_NoteCreateAnonymous.xml 0000664 0000000 0000000 00000001256 13370515543 0023554 0 ustar 00root root 0000000 0000000
842
http://api06.dev.openstreetmap.org/api/0.6/notes/842
http://api06.dev.openstreetmap.org/api/0.6/notes/842/comment
http://api06.dev.openstreetmap.org/api/0.6/notes/842/close
2015-01-03 10:49:39 UTC
open
2015-01-03 10:49:39 UTC
opened
test 123
<p>test 123</p>
osmapi-1.2.2/tests/fixtures/test_NoteCreate_wo_auth.xml 0000664 0000000 0000000 00000002172 13370515543 0023367 0 ustar 00root root 0000000 0000000
824
http://api06.dev.openstreetmap.org/api/0.6/notes/824
http://api06.dev.openstreetmap.org/api/0.6/notes/824/comment
http://api06.dev.openstreetmap.org/api/0.6/notes/824/close
2014-10-03 16:09:11 UTC
open
2014-10-03 16:09:12 UTC
opened
This is an unauthenticated test
<p>This is an unauthenticated test</p>
{u'comments': [{u'action': u'opened',
u'date': u'2014-10-03 16:09:12 UTC',
u'html': u'This is an unauthenticated test
',
u'text': u'This is an unauthenticated test',
u'uid': None,
u'user': None}],
u'date_closed': None,
u'date_created': u'2014-10-03 16:09:11 UTC',
u'id': u'824',
u'lat': 47.123,
u'lon': 8.432,
u'status': u'open'}
osmapi-1.2.2/tests/fixtures/test_NoteGet.xml 0000664 0000000 0000000 00000002164 13370515543 0021156 0 ustar 00root root 0000000 0000000
1111
http://api.openstreetmap.org/api/0.6/notes/1111
http://api.openstreetmap.org/api/0.6/notes/1111/reopen
2013-05-01 20:58:21 UTC
closed
2013-08-21 16:43:26 UTC
2013-05-01 20:58:21 UTC
1363438
giuseppemari
http://www.openstreetmap.org/user/giuseppemari
opened
It does not exist this path
<p>It does not exist this path</p>
2013-08-21 16:43:26 UTC
1714220
luschi
http://www.openstreetmap.org/user/luschi
closed
there is no path signed
<p>there is no path signed</p>
osmapi-1.2.2/tests/fixtures/test_NoteGet_invalid_xml.xml 0000664 0000000 0000000 00000000724 13370515543 0023544 0 ustar 00root root 0000000 0000000
1111
http://api.openstreetmap.org/api/0.6/notes/1111
http://api.openstreetmap.org/api/0.6/notes/1111/reopen
2013-05-01 20:58:21 UTC
closed
2013-08-21 16:43:26 UTC
osmapi-1.2.2/tests/fixtures/test_NoteReopen.xml 0000664 0000000 0000000 00000002675 13370515543 0021676 0 ustar 00root root 0000000 0000000
815
http://api06.dev.openstreetmap.org/api/0.6/notes/815
http://api06.dev.openstreetmap.org/api/0.6/notes/815/comment
http://api06.dev.openstreetmap.org/api/0.6/notes/815/close
2014-10-03 15:20:57 UTC
open
2014-10-03 15:20:57 UTC
1841
metaodi
http://master.apis.dev.openstreetmap.org/user/metaodi
opened
This is a test
<p>This is a test</p>
2014-10-05 16:35:13 UTC
1841
metaodi
http://master.apis.dev.openstreetmap.org/user/metaodi
closed
Close this note!
<p>Close this note!</p>
2014-10-05 16:44:56 UTC
1841
metaodi
http://master.apis.dev.openstreetmap.org/user/metaodi
reopened
Reopen this note!
<p>Reopen this note!</p>
osmapi-1.2.2/tests/fixtures/test_NotesGet.xml 0000664 0000000 0000000 00000042217 13370515543 0021344 0 ustar 00root root 0000000 0000000
231776
http://www.openstreetmap.org/api/0.6/notes/231776
http://www.openstreetmap.org/api/0.6/notes/231776/reopen
2014-08-28 19:27:13 UTC
closed
2014-09-27 09:27:48 UTC
2014-08-28 19:27:13 UTC
1486336
Wyken Seagrave
http://www.openstreetmap.org/user/Wyken%20Seagrave
opened
Is it Pinners or Pinner's ?
<p>Is it Pinners or Pinner's ?</p>
2014-09-26 13:10:36 UTC
commented
Royal Mail's postcode finder has PINNERS CROFT.
<p>Royal Mail's postcode finder has PINNERS CROFT.</p>
2014-09-27 09:27:48 UTC
1486336
Wyken Seagrave
http://www.openstreetmap.org/user/Wyken%20Seagrave
closed
Pinners without apostrophe is correct, based on survey
<p>Pinners without apostrophe is correct, based on survey</p>
231733
http://www.openstreetmap.org/api/0.6/notes/231733
http://www.openstreetmap.org/api/0.6/notes/231733/reopen
2014-08-28 18:39:05 UTC
closed
2014-09-27 09:24:55 UTC
2014-08-28 18:39:05 UTC
1486336
Wyken Seagrave
http://www.openstreetmap.org/user/Wyken%20Seagrave
opened
Should be Finbarr?
<p>Should be Finbarr? </p>
2014-09-26 13:09:14 UTC
commented
You're right. Royal Mail's postcode finder has FINBARR CLOSE.
<p>You're right. Royal Mail's postcode finder has FINBARR CLOSE.</p>
2014-09-27 09:24:55 UTC
1486336
Wyken Seagrave
http://www.openstreetmap.org/user/Wyken%20Seagrave
closed
Finbar is name on street plate, verified by survey
<p>Finbar is name on street plate, verified by survey</p>
231775
http://www.openstreetmap.org/api/0.6/notes/231775
http://www.openstreetmap.org/api/0.6/notes/231775/reopen
2014-08-28 19:25:37 UTC
closed
2014-09-27 09:21:41 UTC
2014-08-28 19:25:37 UTC
1486336
Wyken Seagrave
http://www.openstreetmap.org/user/Wyken%20Seagrave
opened
Is it Paynes or Payne's
<p>Is it Paynes or Payne's</p>
2014-09-26 13:05:33 UTC
commented
Royal Mail's postcode finder has PAYNES LANE
<p>Royal Mail's postcode finder has PAYNES LANE</p>
231728
http://www.openstreetmap.org/api/0.6/notes/231728
http://www.openstreetmap.org/api/0.6/notes/231728/reopen
2014-08-28 18:29:16 UTC
closed
2014-09-27 09:15:46 UTC
2014-08-28 18:29:16 UTC
1486336
Wyken Seagrave
http://www.openstreetmap.org/user/Wyken%20Seagrave
opened
Should it be Craner's Road?
<p>Should it be Craner's Road? </p>
2014-09-26 13:04:15 UTC
commented
Royal Mail's Postcode finder has CRANERS ROAD
<p>Royal Mail's Postcode finder has CRANERS ROAD</p>
2014-09-27 09:15:46 UTC
1486336
Wyken Seagrave
http://www.openstreetmap.org/user/Wyken%20Seagrave
closed
Craners without apostrophe based on survey
<p>Craners without apostrophe based on survey</p>
231734
http://www.openstreetmap.org/api/0.6/notes/231734
http://www.openstreetmap.org/api/0.6/notes/231734/reopen
2014-08-28 18:40:33 UTC
closed
2014-09-27 09:03:23 UTC
2014-08-28 18:40:33 UTC
1486336
Wyken Seagrave
http://www.openstreetmap.org/user/Wyken%20Seagrave
opened
Should be Forester's?
<p>Should be Forester's? </p>
2014-09-26 13:21:59 UTC
commented
Royal Mail's postcode finder has FORESTERS ROAD
<p>Royal Mail's postcode finder has FORESTERS ROAD</p>
2014-09-27 09:03:23 UTC
1486336
Wyken Seagrave
http://www.openstreetmap.org/user/Wyken%20Seagrave
closed
Foresters without apostrophe is correct. Verified by survey.
<p>Foresters without apostrophe is correct. Verified by survey.</p>
226232
http://www.openstreetmap.org/api/0.6/notes/226232
http://www.openstreetmap.org/api/0.6/notes/226232/comment
http://www.openstreetmap.org/api/0.6/notes/226232/close
2014-08-21 18:28:35 UTC
open
2014-08-21 18:28:35 UTC
1486336
Wyken Seagrave
http://www.openstreetmap.org/user/Wyken%20Seagrave
opened
Is this really called Classic Drive?
<p>Is this really called Classic Drive? </p>
141481
http://www.openstreetmap.org/api/0.6/notes/141481
http://www.openstreetmap.org/api/0.6/notes/141481/comment
http://www.openstreetmap.org/api/0.6/notes/141481/close
2014-03-29 00:40:00 UTC
open
2014-03-29 00:40:00 UTC
opened
Shared use footpath(s)
<p>Shared use footpath(s)</p>
104971
http://www.openstreetmap.org/api/0.6/notes/104971
http://www.openstreetmap.org/api/0.6/notes/104971/comment
http://www.openstreetmap.org/api/0.6/notes/104971/close
2014-01-20 11:14:35 UTC
open
2014-01-20 11:14:35 UTC
1894030
david halliday
http://www.openstreetmap.org/user/david%20halliday
opened
Casino. DeVere Hotel. Primary Wine Bar
<p>Casino. DeVere Hotel. Primary Wine Bar</p>
98185
http://www.openstreetmap.org/api/0.6/notes/98185
http://www.openstreetmap.org/api/0.6/notes/98185/comment
http://www.openstreetmap.org/api/0.6/notes/98185/close
2014-01-08 20:51:59 UTC
open
2014-01-08 20:51:59 UTC
1874292
CarlRose
http://www.openstreetmap.org/user/CarlRose
opened
tressler
<p>tressler
</p>
2014-01-08 20:52:05 UTC
1874292
CarlRose
http://www.openstreetmap.org/user/CarlRose
closed
<p></p>
2014-01-08 20:52:19 UTC
1874292
CarlRose
http://www.openstreetmap.org/user/CarlRose
reopened
<p></p>
98183
http://www.openstreetmap.org/api/0.6/notes/98183
http://www.openstreetmap.org/api/0.6/notes/98183/comment
http://www.openstreetmap.org/api/0.6/notes/98183/close
2014-01-08 20:46:29 UTC
open
2014-01-08 20:46:29 UTC
opened
9 Humber Rd
<p>9 Humber Rd</p>
2014-01-08 20:51:13 UTC
1874292
CarlRose
http://www.openstreetmap.org/user/CarlRose
closed
<p></p>
2014-01-08 20:51:21 UTC
1874292
CarlRose
http://www.openstreetmap.org/user/CarlRose
reopened
<p></p>
97502
http://www.openstreetmap.org/api/0.6/notes/97502
http://www.openstreetmap.org/api/0.6/notes/97502/comment
http://www.openstreetmap.org/api/0.6/notes/97502/close
2014-01-07 14:02:05 UTC
open
2014-01-07 14:02:05 UTC
opened
onosm.org submitted note from a business:
name: Britannick Engineering
phone: 01608 810332
website:
twitter:
hours:
category: Factories
address: Market Street, Charlbury
<p>onosm.org submitted note from a business:
<br />name: Britannick Engineering
<br />phone: 01608 810332
<br />website:
<br />twitter:
<br />hours:
<br />category: Factories
<br />address: Market Street, Charlbury</p>
11430
http://www.openstreetmap.org/api/0.6/notes/11430
http://www.openstreetmap.org/api/0.6/notes/11430/comment
http://www.openstreetmap.org/api/0.6/notes/11430/close
2013-07-04 12:08:26 UTC
open
2013-07-04 12:08:26 UTC
218616
djakk
http://www.openstreetmap.org/user/djakk
opened
l'échangeur de Janzé-est sera ouvert en septembre 2013 : un rond-point sera construit au nord de l'échangeur -> à mapper
<p>l'échangeur de Janzé-est sera ouvert en septembre 2013 : un rond-point sera construit au nord de l'échangeur -> à mapper</p>
2013-11-20 09:48:18 UTC
439947
StephaneP
http://www.openstreetmap.org/user/StephaneP
commented
Qu'en est-il ? La note est toujours valide ou bien les modifs ont été entrées dans Osm ?
<p>Qu'en est-il ? La note est toujours valide ou bien les modifs ont été entrées dans Osm ?</p>
2013-11-23 11:22:18 UTC
218616
djakk
http://www.openstreetmap.org/user/djakk
commented
Coucou, quelqu'un d'autre que moi a mappé et ça semble correct.
Reste une aire de covoiturage, qui est sans doute toujours en construction. (Son ouverture n'était pas synchronisée avec celle de l'échangeur).
<p>Coucou, quelqu'un d'autre que moi a mappé et ça semble correct.
<br />Reste une aire de covoiturage, qui est sans doute toujours en construction. (Son ouverture n'était pas synchronisée avec celle de l'échangeur). </p>
2013-12-05 09:13:34 UTC
704348
JBacc1
http://www.openstreetmap.org/user/JBacc1
closed
Ok, alors on peut fermer.
<p>Ok, alors on peut fermer.</p>
2013-12-06 19:28:20 UTC
218616
djakk
http://www.openstreetmap.org/user/djakk
reopened
<p></p>
2013-12-06 19:28:51 UTC
218616
djakk
http://www.openstreetmap.org/user/djakk
commented
Non, on va laisser parce qu'il reste l'aire de covoiturage Ă mapper ;)
<p>Non, on va laisser parce qu'il reste l'aire de covoiturage Ă mapper ;)</p>
81429
http://www.openstreetmap.org/api/0.6/notes/81429
http://www.openstreetmap.org/api/0.6/notes/81429/comment
http://www.openstreetmap.org/api/0.6/notes/81429/close
2013-12-01 13:02:25 UTC
open
2013-12-01 13:02:25 UTC
opened
right of way around/through farm poorly marked and needs a re-survey
<p>right of way around/through farm poorly marked and needs a re-survey</p>
4918
http://www.openstreetmap.org/api/0.6/notes/4918
http://www.openstreetmap.org/api/0.6/notes/4918/comment
http://www.openstreetmap.org/api/0.6/notes/4918/close
2013-05-28 20:31:36 UTC
open
2013-05-28 20:31:36 UTC
2098
Andy Street
http://www.openstreetmap.org/user/Andy%20Street
opened
Overlapping landuse
<p>Overlapping landuse</p>
2013-06-05 09:24:52 UTC
30587
IknowJoseph
http://www.openstreetmap.org/user/IknowJoseph
commented
I've created a multipolygon that should take care of the overlapping clearings
<p>I've created a multipolygon that should take care of the overlapping clearings</p>
2013-06-05 09:26:30 UTC
30587
IknowJoseph
http://www.openstreetmap.org/user/IknowJoseph
commented
(still more to do though)
<p>(still more to do though)</p>
osmapi-1.2.2/tests/fixtures/test_NotesSearch.xml 0000664 0000000 0000000 00000004256 13370515543 0022033 0 ustar 00root root 0000000 0000000
796
http://api06.dev.openstreetmap.org/api/0.6/notes/796
http://api06.dev.openstreetmap.org/api/0.6/notes/796/comment
http://api06.dev.openstreetmap.org/api/0.6/notes/796/close
2014-07-16 16:42:46 UTC
open
2014-07-16 16:42:46 UTC
2132
kalaset
http://master.apis.dev.openstreetmap.org/user/kalaset
opened
One way street:
jjhghkklll
<p>One way street:
<br />jjhghkklll</p>
788
http://api06.dev.openstreetmap.org/api/0.6/notes/788
http://api06.dev.openstreetmap.org/api/0.6/notes/788/comment
http://api06.dev.openstreetmap.org/api/0.6/notes/788/close
2014-07-16 16:12:41 UTC
open
2014-07-16 16:12:41 UTC
opened
One way street:
comment
<p>One way street:
<br />comment</p>
738
http://api06.dev.openstreetmap.org/api/0.6/notes/738
http://api06.dev.openstreetmap.org/api/0.6/notes/738/comment
http://api06.dev.openstreetmap.org/api/0.6/notes/738/close
2014-07-03 12:09:05 UTC
open
2014-07-03 12:09:05 UTC
2132
kalaset
http://master.apis.dev.openstreetmap.org/user/kalaset
opened
One way street tyuui
<p>One way street tyuui</p>
osmapi-1.2.2/tests/fixtures/test_RelationCreate.xml 0000664 0000000 0000000 00000000005 13370515543 0022502 0 ustar 00root root 0000000 0000000 8989
osmapi-1.2.2/tests/fixtures/test_RelationDelete.xml 0000664 0000000 0000000 00000000003 13370515543 0022477 0 ustar 00root root 0000000 0000000 43
osmapi-1.2.2/tests/fixtures/test_RelationFull.xml 0000664 0000000 0000000 00000005470 13370515543 0022214 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_RelationGet.xml 0000664 0000000 0000000 00000001656 13370515543 0022033 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_RelationGet_with_version.xml 0000664 0000000 0000000 00000002205 13370515543 0024622 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_RelationHistory.xml 0000664 0000000 0000000 00000002000 13370515543 0022735 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_RelationRelations.xml 0000664 0000000 0000000 00000015530 13370515543 0023250 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_RelationUpdate.xml 0000664 0000000 0000000 00000000003 13370515543 0022517 0 ustar 00root root 0000000 0000000 42
osmapi-1.2.2/tests/fixtures/test_RelationsGet.xml 0000664 0000000 0000000 00000017426 13370515543 0022220 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_WayCreate.xml 0000664 0000000 0000000 00000000005 13370515543 0021465 0 ustar 00root root 0000000 0000000 5454
osmapi-1.2.2/tests/fixtures/test_WayDelete.xml 0000664 0000000 0000000 00000000002 13370515543 0021461 0 ustar 00root root 0000000 0000000 8
osmapi-1.2.2/tests/fixtures/test_WayFull.xml 0000664 0000000 0000000 00000006446 13370515543 0021203 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_WayFull_invalid_response.xml 0000664 0000000 0000000 00000000047 13370515543 0024616 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_WayGet.xml 0000664 0000000 0000000 00000001474 13370515543 0021014 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_WayGet_nodata.xml 0000664 0000000 0000000 00000000000 13370515543 0022322 0 ustar 00root root 0000000 0000000 osmapi-1.2.2/tests/fixtures/test_WayGet_with_version.xml 0000664 0000000 0000000 00000001536 13370515543 0023613 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_WayHistory.xml 0000664 0000000 0000000 00000002641 13370515543 0021733 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_WayRelations.xml 0000664 0000000 0000000 00000001441 13370515543 0022227 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/fixtures/test_WayUpdate.xml 0000664 0000000 0000000 00000000002 13370515543 0021501 0 ustar 00root root 0000000 0000000 7
osmapi-1.2.2/tests/fixtures/test_WaysGet.xml 0000664 0000000 0000000 00000002171 13370515543 0021172 0 ustar 00root root 0000000 0000000
osmapi-1.2.2/tests/helper_tests.py 0000664 0000000 0000000 00000010077 13370515543 0017234 0 ustar 00root root 0000000 0000000 from __future__ import (unicode_literals, absolute_import)
from . import osmapi_tests
import osmapi
import mock
import os
__location__ = os.path.realpath(
os.path.join(
os.getcwd(),
os.path.dirname(__file__)
)
)
class TestOsmApiHelper(osmapi_tests.TestOsmApi):
def setUp(self):
super(TestOsmApiHelper, self).setUp()
self.setupMock()
def setupMock(self, status=200):
mock_response = mock.Mock()
mock_response.status_code = status
mock_response.reason = "test reason"
mock_response.content = 'test response'
self.api._session.request = mock.Mock(return_value=mock_response)
self.api._username = 'testuser'
self.api._password = 'testpassword'
def test_passwordfile_only(self):
path = os.path.join(
__location__,
'fixtures',
'passwordfile.txt'
)
my_api = osmapi.OsmApi(passwordfile=path)
self.assertEquals('testosm', my_api._username)
self.assertEquals('testpass', my_api._password)
def test_passwordfile_with_user(self):
path = os.path.join(
__location__,
'fixtures',
'passwordfile.txt'
)
my_api = osmapi.OsmApi(username='testuser', passwordfile=path)
self.assertEquals('testuser', my_api._username)
self.assertEquals('testuserpass', my_api._password)
def test_http_request_get(self):
response = self.api._http_request(
'GET',
'/api/0.6/test',
False,
None
)
self.api._session.request.assert_called_with(
'GET',
self.api_base + '/api/0.6/test',
auth=None,
data=None
)
self.assertEquals(response, "test response")
self.assertEquals(self.api._session.request.call_count, 1)
def test_http_request_put(self):
data = "data"
response = self.api._http_request(
'PUT',
'/api/0.6/testput',
False,
data
)
self.api._session.request.assert_called_with(
'PUT',
self.api_base + '/api/0.6/testput',
data="data",
auth=None
)
self.assertEquals(response, "test response")
def test_http_request_delete(self):
data = "delete data"
response = self.api._http_request(
'PUT',
'/api/0.6/testdelete',
False,
data
)
self.api._session.request.assert_called_with(
'PUT',
self.api_base + '/api/0.6/testdelete',
data="delete data",
auth=None
)
self.assertEquals(response, "test response")
def test_http_request_auth(self):
response = self.api._http_request(
'PUT',
'/api/0.6/testauth',
True,
None
)
self.api._session.request.assert_called_with(
'PUT',
self.api_base + '/api/0.6/testauth',
auth=('testuser', 'testpassword'),
data=None
)
self.assertEquals(response, "test response")
def test_http_request_410_response(self):
self.setupMock(410)
with self.assertRaises(osmapi.ElementDeletedApiError) as cm:
self.api._http_request(
'GET',
'/api/0.6/test410',
False,
None
)
self.assertEquals(cm.exception.status, 410)
self.assertEquals(cm.exception.reason, "test reason")
self.assertEquals(cm.exception.payload, "test response")
def test_http_request_500_response(self):
self.setupMock(500)
with self.assertRaises(osmapi.ApiError) as cm:
self.api._http_request(
'GET',
self.api_base + '/api/0.6/test500',
False,
None
)
self.assertEquals(cm.exception.status, 500)
self.assertEquals(cm.exception.reason, "test reason")
self.assertEquals(cm.exception.payload, "test response")
osmapi-1.2.2/tests/node_tests.py 0000664 0000000 0000000 00000025376 13370515543 0016712 0 ustar 00root root 0000000 0000000 from __future__ import (unicode_literals, absolute_import)
from . import osmapi_tests
import osmapi
import mock
import datetime
class TestOsmApiNode(osmapi_tests.TestOsmApi):
def test_NodeGet(self):
self._session_mock()
result = self.api.NodeGet(123)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1], self.api_base + '/api/0.6/node/123')
self.assertEquals(result, {
'id': 123,
'changeset': 15293,
'uid': 605,
'timestamp': datetime.datetime(2012, 4, 18, 11, 14, 26),
'lat': 51.8753146,
'lon': -1.4857118,
'visible': True,
'version': 8,
'user': 'freundchen',
'tag': {
'amenity': 'school',
'foo': 'bar',
'name': 'Berolina & Schule'
},
})
def test_NodeGet_with_version(self):
self._session_mock()
result = self.api.NodeGet(123, NodeVersion=2)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1], self.api_base + '/api/0.6/node/123/2')
self.assertEquals(result, {
'id': 123,
'changeset': 4152,
'uid': 605,
'timestamp': datetime.datetime(2011, 4, 18, 11, 14, 26),
'lat': 51.8753146,
'lon': -1.4857118,
'visible': True,
'version': 2,
'user': 'freundchen',
'tag': {
'amenity': 'school',
},
})
def test_NodeGet_invalid_response(self):
self._session_mock()
with self.assertRaises(osmapi.XmlResponseInvalidError):
self.api.NodeGet(987)
def test_NodeCreate_changesetauto(self):
# setup mock
self.api = osmapi.OsmApi(
api="api06.dev.openstreetmap.org",
changesetauto=True
)
for filename in ['test_NodeCreate_changesetauto.xml',
'test_ChangesetUpload_create_node.xml',
'test_ChangesetClose.xml']:
self._session_mock(auth=True, filenames=[filename])
test_node = {
'lat': 47.123,
'lon': 8.555,
'tag': {
'amenity': 'place_of_worship',
'religion': 'pastafarian'
}
}
self.assertIsNone(self.api.NodeCreate(test_node))
def test_NodeCreate(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=1111
)
self.api._CurrentChangesetId = 1111
test_node = {
'lat': 47.287,
'lon': 8.765,
'tag': {
'amenity': 'place_of_worship',
'religion': 'pastafarian'
}
}
cs = self.api.ChangesetCreate({
'comment': 'This is a test dataset'
})
self.assertEquals(cs, 1111)
result = self.api.NodeCreate(test_node)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'PUT')
self.assertEquals(args[1], self.api_base + '/api/0.6/node/create')
self.assertEquals(result['id'], 9876)
self.assertEquals(result['lat'], test_node['lat'])
self.assertEquals(result['lon'], test_node['lon'])
self.assertEquals(result['tag'], test_node['tag'])
def test_NodeCreate_wo_changeset(self):
test_node = {
'lat': 47.287,
'lon': 8.765,
'tag': {
'amenity': 'place_of_worship',
'religion': 'pastafarian'
}
}
with self.assertRaisesRegexp(
osmapi.NoChangesetOpenError,
'need to open a changeset'):
self.api.NodeCreate(test_node)
def test_NodeCreate_existing_node(self):
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=1111
)
self.api._CurrentChangesetId = 1111
test_node = {
'id': 123,
'lat': 47.287,
'lon': 8.765,
'tag': {
'amenity': 'place_of_worship',
'religion': 'pastafarian'
}
}
with self.assertRaisesRegexp(
osmapi.OsmTypeAlreadyExistsError,
'This node already exists'):
self.api.NodeCreate(test_node)
def test_NodeCreate_wo_auth(self):
self._session_mock()
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=1111
)
self.api._CurrentChangesetId = 1111
test_node = {
'lat': 47.287,
'lon': 8.765,
'tag': {
'amenity': 'place_of_worship',
'religion': 'pastafarian'
}
}
with self.assertRaisesRegexp(
osmapi.UsernamePasswordMissingError,
'Username/Password missing'):
self.api.NodeCreate(test_node)
def test_NodeCreate_with_exception(self):
self._session_mock(auth=True)
self.api._http_request = mock.Mock(side_effect=Exception)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=1111
)
self.api._CurrentChangesetId = 1111
test_node = {
'lat': 47.287,
'lon': 8.765,
'tag': {
'amenity': 'place_of_worship',
'religion': 'pastafarian'
}
}
with self.assertRaisesRegexp(
osmapi.MaximumRetryLimitReachedError,
'Give up after 5 retries'):
self.api.NodeCreate(test_node)
def test_NodeUpdate(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=1111
)
self.api._CurrentChangesetId = 1111
test_node = {
'id': 7676,
'lat': 47.287,
'lon': 8.765,
'tag': {
'amenity': 'place_of_worship',
'name': 'christian'
}
}
cs = self.api.ChangesetCreate({
'comment': 'This is a test dataset'
})
self.assertEquals(cs, 1111)
result = self.api.NodeUpdate(test_node)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'PUT')
self.assertEquals(args[1], self.api_base + '/api/0.6/node/7676')
self.assertEquals(result['id'], 7676)
self.assertEquals(result['version'], 3)
self.assertEquals(result['lat'], test_node['lat'])
self.assertEquals(result['lon'], test_node['lon'])
self.assertEquals(result['tag'], test_node['tag'])
def test_NodeDelete(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=1111
)
self.api._CurrentChangesetId = 1111
test_node = {
'id': 7676
}
cs = self.api.ChangesetCreate({
'comment': 'This is a test dataset'
})
self.assertEquals(cs, 1111)
result = self.api.NodeDelete(test_node)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'DELETE')
self.assertEquals(args[1], self.api_base + '/api/0.6/node/7676')
self.assertEquals(result['id'], 7676)
self.assertEquals(result['version'], 4)
def test_NodeHistory(self):
self._session_mock()
result = self.api.NodeHistory(123)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1], self.api_base + '/api/0.6/node/123/history')
self.assertEquals(len(result), 8)
self.assertEquals(result[4]['id'], 123)
self.assertEquals(result[4]['version'], 4)
self.assertEquals(result[4]['lat'], 51.8753146)
self.assertEquals(result[4]['lon'], -1.4857118)
self.assertEquals(
result[4]['tag'], {
'empty': '',
'foo': 'bar',
}
)
def test_NodeWays(self):
self._session_mock()
result = self.api.NodeWays(234)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1], self.api_base + '/api/0.6/node/234/ways')
self.assertEquals(len(result), 1)
self.assertEquals(result[0]['id'], 60)
self.assertEquals(result[0]['changeset'], 61)
self.assertEquals(
result[0]['tag'],
{
'highway': 'path',
'name': 'Dog walking path',
}
)
def test_NodeRelations(self):
self._session_mock()
result = self.api.NodeRelations(4295668179)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1],
self.api_base + '/api/0.6/node/4295668179/relations')
self.assertEquals(len(result), 1)
self.assertEquals(result[0]['id'], 4294968148)
self.assertEquals(result[0]['changeset'], 23123)
self.assertEquals(
result[0]['member'][1],
{
'role': 'point',
'ref': 4295668179,
'type': 'node',
}
)
self.assertEquals(
result[0]['tag'],
{
'type': 'fancy',
}
)
def test_NodesGet(self):
self._session_mock()
result = self.api.NodesGet([123, 345])
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1],
self.api_base + '/api/0.6/nodes?nodes=123,345')
self.assertEquals(len(result), 2)
self.assertEquals(result[123], {
'id': 123,
'changeset': 15293,
'uid': 605,
'timestamp': datetime.datetime(2012, 4, 18, 11, 14, 26),
'lat': 51.8753146,
'lon': -1.4857118,
'visible': True,
'version': 8,
'user': 'freundchen',
'tag': {
'amenity': 'school',
'foo': 'bar',
'name': 'Berolina & Schule'
},
})
self.assertEquals(result[345], {
'id': 345,
'changeset': 244,
'timestamp': datetime.datetime(2009, 9, 12, 3, 22, 59),
'uid': 1,
'visible': False,
'version': 2,
'user': 'guggis',
'tag': {},
})
osmapi-1.2.2/tests/notes_tests.py 0000664 0000000 0000000 00000030366 13370515543 0017110 0 ustar 00root root 0000000 0000000 from __future__ import (unicode_literals, absolute_import)
from . import osmapi_tests
from datetime import datetime
import osmapi
try:
import urlparse
except ImportError:
from urllib import parse as urlparse
class TestOsmApiNotes(osmapi_tests.TestOsmApi):
def test_NotesGet(self):
self._session_mock()
result = self.api.NotesGet(
-1.4998534,
45.9667901,
-1.4831815,
52.4710193
)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
urlParts = urlparse.urlparse(args[1])
params = urlparse.parse_qs(urlParts.query)
self.assertEquals(
params['bbox'][0],
'-1.499853,45.966790,-1.483181,52.471019'
)
self.assertEquals(params['limit'][0], '100')
self.assertEquals(params['closed'][0], '7')
self.assertEquals(len(result), 14)
self.assertEquals(result[2], {
'id': '231775',
'lon': -1.4929605,
'lat': 52.4107312,
'date_created': datetime(2014, 8, 28, 19, 25, 37),
'date_closed': datetime(2014, 9, 27, 9, 21, 41),
'status': 'closed',
'comments': [
{
'date': datetime(2014, 8, 28, 19, 25, 37),
'action': 'opened',
'text': "Is it Paynes or Payne's",
'html': "Is it Paynes or Payne's
",
'uid': '1486336',
'user': 'Wyken Seagrave'
},
{
'date': datetime(2014, 9, 26, 13, 5, 33),
'action': 'commented',
'text': "Royal Mail's postcode finder has PAYNES LANE",
'html':
(
"Royal Mail's postcode finder "
"has PAYNES LANE
"
),
'uid': None,
'user': None
}
]
})
def test_NoteGet(self):
self._session_mock()
result = self.api.NoteGet(1111)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1], self.api_base + '/api/0.6/notes/1111')
self.assertEquals(result, {
'id': '1111',
'lon': 12.3133135,
'lat': 37.9305489,
'date_created': datetime(2013, 5, 1, 20, 58, 21),
'date_closed': datetime(2013, 8, 21, 16, 43, 26),
'status': 'closed',
'comments': [
{
'date': datetime(2013, 5, 1, 20, 58, 21),
'action': 'opened',
'text': "It does not exist this path",
'html': "It does not exist this path
",
'uid': '1363438',
'user': 'giuseppemari'
},
{
'date': datetime(2013, 8, 21, 16, 43, 26),
'action': 'closed',
'text': "there is no path signed",
'html': "there is no path signed
",
'uid': '1714220',
'user': 'luschi'
}
]
})
def test_NoteGet_invalid_xml(self):
self._session_mock()
with self.assertRaises(osmapi.XmlResponseInvalidError):
self.api.NoteGet(1111)
def test_NoteCreate(self):
self._session_mock(auth=True)
note = {
'lat': 47.123,
'lon': 8.432,
'text': 'This is a test'
}
result = self.api.NoteCreate(note)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'POST')
urlParts = urlparse.urlparse(args[1])
params = urlparse.parse_qs(urlParts.query)
self.assertEquals(params['lat'][0], '47.123')
self.assertEquals(params['lon'][0], '8.432')
self.assertEquals(params['text'][0], 'This is a test')
self.assertEquals(result, {
'id': '816',
'lat': 47.123,
'lon': 8.432,
'date_created': datetime(2014, 10, 3, 15, 21, 21),
'date_closed': None,
'status': 'open',
'comments': [
{
'date': datetime(2014, 10, 3, 15, 21, 22),
'action': 'opened',
'text': "This is a test",
'html': "This is a test
",
'uid': '1841',
'user': 'metaodi'
}
]
})
def test_NoteCreateAnonymous(self):
self._session_mock()
note = {
'lat': 47.123,
'lon': 8.432,
'text': 'test 123'
}
result = self.api.NoteCreate(note)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'POST')
urlParts = urlparse.urlparse(args[1])
params = urlparse.parse_qs(urlParts.query)
self.assertEquals(params['lat'][0], '47.123')
self.assertEquals(params['lon'][0], '8.432')
self.assertEquals(params['text'][0], 'test 123')
self.assertEquals(result, {
'id': '842',
'lat': 58.3368222,
'lon': 25.8826183,
'date_created': datetime(2015, 1, 3, 10, 49, 39),
'date_closed': None,
'status': 'open',
'comments': [
{
'date': datetime(2015, 1, 3, 10, 49, 39),
'action': 'opened',
'text': "test 123",
'html': "test 123
",
'uid': None,
'user': None,
}
]
})
def test_NoteComment(self):
self._session_mock(auth=True)
result = self.api.NoteComment(812, 'This is a comment')
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'POST')
self.assertEquals(
args[1],
self.api_base + '/api/0.6/notes/812/comment?text=This+is+a+comment'
)
self.assertEquals(result, {
'id': '812',
'lat': 47.123,
'lon': 8.432,
'date_created': datetime(2014, 10, 3, 15, 11, 5),
'date_closed': None,
'status': 'open',
'comments': [
{
'date': datetime(2014, 10, 3, 15, 11, 5),
'action': 'opened',
'text': "This is a test",
'html': "This is a test
",
'uid': '1841',
'user': 'metaodi'
},
{
'date': datetime(2014, 10, 4, 22, 36, 35),
'action': 'commented',
'text': "This is a comment",
'html': "This is a comment
",
'uid': '1841',
'user': 'metaodi'
}
]
})
def test_NoteCommentAnonymous(self):
self._session_mock()
result = self.api.NoteComment(842, 'blubb')
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'POST')
self.assertEquals(
args[1],
self.api_base + '/api/0.6/notes/842/comment?text=blubb'
)
self.assertEquals(result, {
'id': '842',
'lat': 58.3368222,
'lon': 25.8826183,
'date_created': datetime(2015, 1, 3, 10, 49, 39),
'date_closed': None,
'status': 'open',
'comments': [
{
'date': datetime(2015, 1, 3, 10, 49, 39),
'action': 'opened',
'text': "test 123",
'html': "test 123
",
'uid': None,
'user': None,
},
{
'date': datetime(2015, 1, 3, 11, 6, 0),
'action': 'commented',
'text': "blubb",
'html': "blubb
",
'uid': None,
'user': None,
}
]
})
def test_NoteClose(self):
self._session_mock(auth=True)
result = self.api.NoteClose(814, 'Close this note!')
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'POST')
self.assertEquals(
args[1],
self.api_base + '/api/0.6/notes/814/close?text=Close+this+note%21'
)
self.assertEquals(result, {
'id': '815',
'lat': 47.123,
'lon': 8.432,
'date_created': datetime(2014, 10, 3, 15, 20, 57),
'date_closed': datetime(2014, 10, 5, 16, 35, 13),
'status': 'closed',
'comments': [
{
'date': datetime(2014, 10, 3, 15, 20, 57),
'action': 'opened',
'text': "This is a test",
'html': "This is a test
",
'uid': '1841',
'user': 'metaodi'
},
{
'date': datetime(2014, 10, 5, 16, 35, 13),
'action': 'closed',
'text': "Close this note!",
'html': "Close this note!
",
'uid': '1841',
'user': 'metaodi'
}
]
})
def test_NoteReopen(self):
self._session_mock(auth=True)
result = self.api.NoteReopen(815, 'Reopen this note!')
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'POST')
self.assertEquals(
args[1],
(self.api_base +
'/api/0.6/notes/815/reopen?text=Reopen+this+note%21')
)
self.assertEquals(result, {
'id': '815',
'lat': 47.123,
'lon': 8.432,
'date_created': datetime(2014, 10, 3, 15, 20, 57),
'date_closed': None,
'status': 'open',
'comments': [
{
'date': datetime(2014, 10, 3, 15, 20, 57),
'action': 'opened',
'text': "This is a test",
'html': "This is a test
",
'uid': '1841',
'user': 'metaodi'
},
{
'date': datetime(2014, 10, 5, 16, 35, 13),
'action': 'closed',
'text': "Close this note!",
'html': "Close this note!
",
'uid': '1841',
'user': 'metaodi'
},
{
'date': datetime(2014, 10, 5, 16, 44, 56),
'action': 'reopened',
'text': "Reopen this note!",
'html': "Reopen this note!
",
'uid': '1841',
'user': 'metaodi'
}
]
})
def test_NotesSearch(self):
self._session_mock()
result = self.api.NotesSearch('street')
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
urlParts = urlparse.urlparse(args[1])
params = urlparse.parse_qs(urlParts.query)
self.assertEquals(params['q'][0], 'street')
self.assertEquals(params['limit'][0], '100')
self.assertEquals(params['closed'][0], '7')
self.assertEquals(len(result), 3)
self.assertEquals(result[1], {
'id': '788',
'lon': 11.96395,
'lat': 57.70301,
'date_created': datetime(2014, 7, 16, 16, 12, 41),
'date_closed': None,
'status': 'open',
'comments': [
{
'date': datetime(2014, 7, 16, 16, 12, 41),
'action': 'opened',
'text': "One way street:\ncomment",
'html': "One way street:\n
comment
",
'uid': None,
'user': None
}
]
})
osmapi-1.2.2/tests/osmapi_tests.py 0000664 0000000 0000000 00000003716 13370515543 0017247 0 ustar 00root root 0000000 0000000 from __future__ import unicode_literals
from osmapi import OsmApi
import mock
import os
import sys
if sys.version_info < (2, 7):
import unittest2 as unittest
else:
import unittest
__location__ = os.path.realpath(
os.path.join(
os.getcwd(),
os.path.dirname(__file__)
)
)
class TestOsmApi(unittest.TestCase):
def setUp(self):
self.api_base = "http://api06.dev.openstreetmap.org"
self.api = OsmApi(
api=self.api_base
)
self.maxDiff = None
print(self._testMethodName)
print(self.api)
def _session_mock(self, auth=False, filenames=None, status=200,
reason=None):
if auth:
self.api._username = 'testuser'
self.api._password = 'testpassword'
response_mock = mock.Mock()
response_mock.status_code = status
return_values = self._return_values(filenames)
print(filenames)
print(return_values)
assert len(return_values) < 2
if return_values:
response_mock.content = return_values[0]
session_mock = mock.Mock()
session_mock.request = mock.Mock(return_value=response_mock)
self.api._get_http_session = mock.Mock(return_value=session_mock)
self.api._session = session_mock
self.api._sleep = mock.Mock()
def _return_values(self, filenames):
if filenames is None:
filenames = [self._testMethodName + ".xml"]
return_values = []
for filename in filenames:
path = os.path.join(
__location__,
'fixtures',
filename
)
try:
with open(path) as file:
return_values.append(file.read())
except Exception:
pass
return return_values
def teardown(self):
pass
def test_constructor(self):
self.assertTrue(isinstance(self.api, OsmApi))
osmapi-1.2.2/tests/relation_tests.py 0000664 0000000 0000000 00000023332 13370515543 0017570 0 ustar 00root root 0000000 0000000 from __future__ import (unicode_literals, absolute_import)
from . import osmapi_tests
import osmapi
import mock
import datetime
class TestOsmApiRelation(osmapi_tests.TestOsmApi):
def test_RelationGet(self):
self._session_mock()
result = self.api.RelationGet(321)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1], self.api_base + '/api/0.6/relation/321')
self.assertEquals(result, {
'id': 321,
'changeset': 434,
'uid': 12,
'timestamp': datetime.datetime(2009, 9, 15, 22, 24, 25),
'visible': True,
'version': 1,
'user': 'green525',
'tag': {
'admin_level': '9',
'boundary': 'administrative',
'type': 'multipolygon',
},
'member': [
{
'ref': 6908,
'role': 'outer',
'type': 'way'
},
{
'ref': 6352,
'role': 'outer',
'type': 'way'
},
{
'ref': 5669,
'role': 'outer',
'type': 'way'
},
{
'ref': 5682,
'role': 'outer',
'type': 'way'
},
{
'ref': 6909,
'role': 'outer',
'type': 'way'
},
{
'ref': 6355,
'role': 'outer',
'type': 'way'
},
{
'ref': 6910,
'role': 'outer',
'type': 'way'
},
{
'ref': 6911,
'role': 'outer',
'type': 'way'
},
{
'ref': 6912,
'role': 'outer',
'type': 'way'
}
]
})
def test_RelationGet_with_version(self):
self._session_mock()
result = self.api.RelationGet(765, 2)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1], self.api_base + '/api/0.6/relation/765/2')
self.assertEquals(result['id'], 765)
self.assertEquals(result['changeset'], 41378)
self.assertEquals(result['user'], 'metaodi')
self.assertEquals(result['tag']['source'], 'test')
def test_RelationCreate(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=3333
)
self.api._CurrentChangesetId = 3333
test_relation = {
'tag': {
'type': 'test',
},
'member': [
{
'ref': 6908,
'role': 'outer',
'type': 'way'
},
{
'ref': 6352,
'role': 'point',
'type': 'node'
},
]
}
cs = self.api.ChangesetCreate({
'comment': 'This is a test relation'
})
self.assertEquals(cs, 3333)
result = self.api.RelationCreate(test_relation)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'PUT')
self.assertEquals(args[1], self.api_base + '/api/0.6/relation/create')
self.assertEquals(result['id'], 8989)
self.assertEquals(result['version'], 1)
self.assertEquals(result['member'], test_relation['member'])
self.assertEquals(result['tag'], test_relation['tag'])
def test_RelationCreate_existing_node(self):
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=1111
)
self.api._CurrentChangesetId = 1111
test_relation = {
'id': 456,
'tag': {
'type': 'test',
},
'member': [
{
'ref': 6908,
'role': 'outer',
'type': 'way'
},
{
'ref': 6352,
'role': 'point',
'type': 'node'
},
]
}
with self.assertRaisesRegexp(
osmapi.OsmTypeAlreadyExistsError,
'This relation already exists'):
self.api.RelationCreate(test_relation)
def test_RelationUpdate(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=3333
)
self.api._CurrentChangesetId = 3333
test_relation = {
'id': 8989,
'tag': {
'type': 'test update',
},
'member': [
{
'ref': 6908,
'role': 'outer',
'type': 'way'
}
]
}
cs = self.api.ChangesetCreate({
'comment': 'This is a test relation'
})
self.assertEquals(cs, 3333)
result = self.api.RelationUpdate(test_relation)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'PUT')
self.assertEquals(args[1], self.api_base + '/api/0.6/relation/8989')
self.assertEquals(result['id'], 8989)
self.assertEquals(result['version'], 42)
self.assertEquals(result['member'], test_relation['member'])
self.assertEquals(result['tag'], test_relation['tag'])
def test_RelationDelete(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=3333
)
self.api._CurrentChangesetId = 3333
test_relation = {
'id': 8989
}
cs = self.api.ChangesetCreate({
'comment': 'This is a test relation'
})
self.assertEquals(cs, 3333)
result = self.api.RelationDelete(test_relation)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'DELETE')
self.assertEquals(args[1], self.api_base + '/api/0.6/relation/8989')
self.assertEquals(result['id'], 8989)
self.assertEquals(result['version'], 43)
def test_RelationHistory(self):
self._session_mock()
result = self.api.RelationHistory(2470397)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1],
self.api_base + '/api/0.6/relation/2470397/history')
self.assertEquals(len(result), 2)
self.assertEquals(result[1]['id'], 2470397)
self.assertEquals(result[1]['version'], 1)
self.assertEquals(
result[1]['tag'], {
'restriction': 'only_straight_on',
'type': 'restriction',
}
)
self.assertEquals(result[2]['version'], 2)
def test_RelationRelations(self):
self._session_mock()
result = self.api.RelationRelations(1532552)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1],
(self.api_base +
'/api/0.6/relation/1532552/relations'))
self.assertEquals(len(result), 1)
self.assertEquals(result[0]['id'], 1532553)
self.assertEquals(result[0]['version'], 85)
self.assertEquals(len(result[0]['member']), 120)
self.assertEquals(result[0]['tag']['type'], 'network')
self.assertEquals(
result[0]['tag']['name'],
'Aargauischer Radroutennetz'
)
def test_RelationFull(self):
self._session_mock()
result = self.api.RelationFull(2470397)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1],
self.api_base + '/api/0.6/relation/2470397/full')
self.assertEquals(len(result), 11)
self.assertEquals(result[1]['data']['id'], 101142277)
self.assertEquals(result[1]['data']['version'], 8)
self.assertEquals(result[1]['type'], 'node')
self.assertEquals(result[10]['data']['id'], 2470397)
self.assertEquals(result[10]['data']['version'], 2)
self.assertEquals(result[10]['type'], 'relation')
def test_RelationsGet(self):
self._session_mock()
result = self.api.RelationsGet([1532552, 1532553])
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(
args[1],
self.api_base + '/api/0.6/relations?relations=1532552,1532553'
)
self.assertEquals(len(result), 2)
self.assertEquals(result[1532553]['id'], 1532553)
self.assertEquals(result[1532553]['version'], 85)
self.assertEquals(result[1532553]['user'], 'SimonPoole')
self.assertEquals(result[1532552]['id'], 1532552)
self.assertEquals(result[1532552]['visible'], True)
self.assertEquals(result[1532552]['tag']['route'], 'bicycle')
def test_RelationFull_with_deleted_relation(self):
self._session_mock(filenames=[], status=410)
with self.assertRaises(osmapi.ElementDeletedApiError) as context:
self.api.RelationFull(2911456)
self.assertEquals(410, context.exception.status)
osmapi-1.2.2/tests/way_tests.py 0000664 0000000 0000000 00000017444 13370515543 0016562 0 ustar 00root root 0000000 0000000 from __future__ import (unicode_literals, absolute_import)
from . import osmapi_tests
import osmapi
import mock
import datetime
class TestOsmApiWay(osmapi_tests.TestOsmApi):
def test_WayGet(self):
self._session_mock()
result = self.api.WayGet(321)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1], self.api_base + '/api/0.6/way/321')
self.assertEquals(result, {
'id': 321,
'changeset': 298,
'uid': 12,
'timestamp': datetime.datetime(2009, 9, 14, 23, 23, 18),
'visible': True,
'version': 1,
'user': 'green525',
'tag': {
'admin_level': '9',
'boundary': 'administrative',
},
'nd': [
11949,
11950,
11951,
11952,
11953,
11954,
11955,
11956,
11957,
11958,
11959,
11960,
11961,
11962,
11963,
11964,
11949
]
})
def test_WayGet_with_version(self):
self._session_mock()
result = self.api.WayGet(4294967296, 2)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1],
self.api_base + '/api/0.6/way/4294967296/2')
self.assertEquals(result['id'], 4294967296)
self.assertEquals(result['changeset'], 41303)
self.assertEquals(result['user'], 'metaodi')
def test_WayGet_nodata(self):
self._session_mock()
with self.assertRaises(osmapi.ResponseEmptyApiError):
self.api.WayGet(321)
def test_WayCreate(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=2222
)
self.api._CurrentChangesetId = 2222
test_way = {
'nd': [11949, 11950],
'tag': {
'highway': 'unclassified',
'name': 'Osmapi Street'
}
}
cs = self.api.ChangesetCreate({
'comment': 'This is a test way'
})
self.assertEquals(cs, 2222)
result = self.api.WayCreate(test_way)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'PUT')
self.assertEquals(args[1], self.api_base + '/api/0.6/way/create')
self.assertEquals(result['id'], 5454)
self.assertEquals(result['nd'], test_way['nd'])
self.assertEquals(result['tag'], test_way['tag'])
def test_WayCreate_existing_node(self):
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=1111
)
self.api._CurrentChangesetId = 1111
test_way = {
'id': 456,
'nd': [11949, 11950],
'tag': {
'highway': 'unclassified',
'name': 'Osmapi Street'
}
}
with self.assertRaisesRegexp(
osmapi.OsmTypeAlreadyExistsError,
'This way already exists'):
self.api.WayCreate(test_way)
def test_WayUpdate(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=2222
)
self.api._CurrentChangesetId = 2222
test_way = {
'id': 876,
'nd': [11949, 11950],
'tag': {
'highway': 'unclassified',
'name': 'Osmapi Street Update'
}
}
cs = self.api.ChangesetCreate({
'comment': 'This is a test way'
})
self.assertEquals(cs, 2222)
result = self.api.WayUpdate(test_way)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'PUT')
self.assertEquals(args[1], self.api_base + '/api/0.6/way/876')
self.assertEquals(result['id'], 876)
self.assertEquals(result['version'], 7)
self.assertEquals(result['nd'], test_way['nd'])
self.assertEquals(result['tag'], test_way['tag'])
def test_WayDelete(self):
self._session_mock(auth=True)
# setup mock
self.api.ChangesetCreate = mock.Mock(
return_value=2222
)
self.api._CurrentChangesetId = 2222
test_way = {
'id': 876
}
cs = self.api.ChangesetCreate({
'comment': 'This is a test way delete'
})
self.assertEquals(cs, 2222)
result = self.api.WayDelete(test_way)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'DELETE')
self.assertEquals(args[1], self.api_base + '/api/0.6/way/876')
self.assertEquals(result['id'], 876)
self.assertEquals(result['version'], 8)
def test_WayHistory(self):
self._session_mock()
result = self.api.WayHistory(4294967296)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1],
self.api_base + '/api/0.6/way/4294967296/history')
self.assertEquals(len(result), 2)
self.assertEquals(result[1]['id'], 4294967296)
self.assertEquals(result[1]['version'], 1)
self.assertEquals(
result[1]['tag'], {
'highway': 'unclassified',
'name': 'Stansted Road',
}
)
def test_WayRelations(self):
self._session_mock()
result = self.api.WayRelations(4295032193)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1],
self.api_base + '/api/0.6/way/4295032193/relations')
self.assertEquals(len(result), 1)
self.assertEquals(result[0]['id'], 4294968148)
self.assertEquals(result[0]['changeset'], 23123)
self.assertEquals(
result[0]['member'][4],
{
'role': '',
'ref': 4295032193,
'type': 'way',
}
)
self.assertEquals(
result[0]['tag'],
{
'type': 'fancy',
}
)
def test_WayFull(self):
self._session_mock()
result = self.api.WayFull(321)
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1], self.api_base + '/api/0.6/way/321/full')
self.assertEquals(len(result), 17)
self.assertEquals(result[0]['data']['id'], 11949)
self.assertEquals(result[0]['data']['changeset'], 298)
self.assertEquals(result[0]['type'], 'node')
self.assertEquals(result[16]['data']['id'], 321)
self.assertEquals(result[16]['data']['changeset'], 298)
self.assertEquals(result[16]['type'], 'way')
def test_WayFull_invalid_response(self):
self._session_mock()
with self.assertRaises(osmapi.XmlResponseInvalidError):
self.api.WayFull(321)
def test_WaysGet(self):
self._session_mock()
result = self.api.WaysGet([456, 678])
args, kwargs = self.api._session.request.call_args
self.assertEquals(args[0], 'GET')
self.assertEquals(args[1],
self.api_base + '/api/0.6/ways?ways=456,678')
self.assertEquals(len(result), 2)
self.assertIs(type(result[456]), dict)
self.assertIs(type(result[678]), dict)
with self.assertRaises(KeyError):
self.assertIs(type(result[123]), dict)
osmapi-1.2.2/tox.ini 0000664 0000000 0000000 00000000242 13370515543 0014323 0 ustar 00root root 0000000 0000000 [tox]
envlist = py27,py34,py35,py36,py37
[testenv]
commands=nosetests --verbose
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt