Python wrapper for the OSM API
—
Complete CRUD operations for OpenStreetMap nodes including creation, retrieval, updating, deletion, history tracking, and relationship queries. Nodes represent point features in OpenStreetMap and are the fundamental building blocks for ways and relations.
Get individual nodes by ID with optional version specification.
def NodeGet(NodeId, NodeVersion=-1):
"""
Returns node with NodeId as a dict.
Parameters:
- NodeId (int): Unique identifier of the node
- NodeVersion (int, optional): Specific version to retrieve (-1 for latest)
Returns:
dict: Node data including id, lat, lon, tag, changeset, version,
user, uid, timestamp, visible
Raises:
- ElementDeletedApiError: If node has been deleted
- ElementNotFoundApiError: If node cannot be found
"""Usage Example:
import osmapi
api = osmapi.OsmApi()
# Get latest version of node
node = api.NodeGet(123)
print(f"Node {node['id']} at ({node['lat']}, {node['lon']})")
print(f"Tags: {node['tag']}")
# Get specific version
node_v2 = api.NodeGet(123, NodeVersion=2)
print(f"Version 2 coordinates: ({node_v2['lat']}, {node_v2['lon']})")Create new nodes with coordinates and optional tags.
def NodeCreate(NodeData):
"""
Creates a node based on the supplied NodeData dict.
Parameters:
- NodeData (dict): Node data with lat, lon, and optional tag
Required: lat (float), lon (float)
Optional: tag (dict)
Returns:
dict: Updated NodeData with assigned id, version, changeset,
user, uid, visible
Raises:
- UsernamePasswordMissingError: If no authentication provided
- NoChangesetOpenError: If no changeset is open
- OsmTypeAlreadyExistsError: If node data contains existing ID
- ChangesetClosedApiError: If changeset is closed
"""Usage Example:
import osmapi
api = osmapi.OsmApi(username="your_username", password="your_password")
# Create node with minimal data
with api.Changeset({"comment": "Adding new amenity"}) as changeset_id:
new_node = api.NodeCreate({
"lat": 47.6062,
"lon": -122.3321,
"tag": {
"name": "Seattle Center",
"amenity": "attraction",
"website": "https://www.seattlecenter.com"
}
})
print(f"Created node {new_node['id']} in changeset {changeset_id}")Modify existing nodes by updating coordinates, tags, or other attributes.
def NodeUpdate(NodeData):
"""
Updates node with the supplied NodeData dict.
Parameters:
- NodeData (dict): Node data with id, version, and updated fields
Required: id (int), lat (float), lon (float), version (int)
Optional: tag (dict)
Returns:
dict: Updated NodeData with new version, changeset, user, uid, visible
Raises:
- UsernamePasswordMissingError: If no authentication provided
- NoChangesetOpenError: If no changeset is open
- VersionMismatchApiError: If version doesn't match current
- ChangesetClosedApiError: If changeset is closed
"""Usage Example:
import osmapi
api = osmapi.OsmApi(username="your_username", password="your_password")
# Get current node data
node = api.NodeGet(12345)
# Update tags
with api.Changeset({"comment": "Updating amenity information"}) as changeset_id:
node["tag"]["opening_hours"] = "Mo-Su 09:00-21:00"
node["tag"]["phone"] = "+1-206-684-7200"
updated_node = api.NodeUpdate(node)
print(f"Updated node {updated_node['id']} to version {updated_node['version']}")Delete nodes from OpenStreetMap (marks as invisible).
def NodeDelete(NodeData):
"""
Delete node with NodeData.
Parameters:
- NodeData (dict): Node data with id, version, and current attributes
Required: id (int), lat (float), lon (float), version (int)
Optional: tag (dict)
Returns:
dict: Updated NodeData with visible=False and new version
Raises:
- UsernamePasswordMissingError: If no authentication provided
- NoChangesetOpenError: If no changeset is open
- VersionMismatchApiError: If version doesn't match current
- ChangesetClosedApiError: If changeset is closed
- ElementDeletedApiError: If node already deleted
- ElementNotFoundApiError: If node cannot be found
"""Usage Example:
import osmapi
api = osmapi.OsmApi(username="your_username", password="your_password")
# Get node to delete
node = api.NodeGet(12345)
# Delete the node
with api.Changeset({"comment": "Removing obsolete node"}) as changeset_id:
deleted_node = api.NodeDelete(node)
print(f"Deleted node {deleted_node['id']}, now version {deleted_node['version']}")
print(f"Visible: {deleted_node['visible']}") # FalseRetrieve complete version history for a node.
def NodeHistory(NodeId):
"""
Returns dict with version as key containing all node versions.
Parameters:
- NodeId (int): Unique identifier of the node
Returns:
dict: Version history with version numbers as keys and
NodeData dicts as values
"""Usage Example:
import osmapi
api = osmapi.OsmApi()
# Get complete history
history = api.NodeHistory(123)
for version, node_data in history.items():
print(f"Version {version}: {node_data['user']} at {node_data['timestamp']}")
print(f" Coordinates: ({node_data['lat']}, {node_data['lon']})")
print(f" Tags: {node_data['tag']}")Find ways and relations that reference a specific node.
def NodeWays(NodeId):
"""
Returns a list of ways containing the specified node.
Parameters:
- NodeId (int): Unique identifier of the node
Returns:
list[dict]: List of WayData dicts containing the node
"""
def NodeRelations(NodeId):
"""
Returns a list of relations containing the specified node.
Parameters:
- NodeId (int): Unique identifier of the node
Returns:
list[dict]: List of RelationData dicts containing the node
"""Usage Example:
import osmapi
api = osmapi.OsmApi()
node_id = 123
# Find ways using this node
ways = api.NodeWays(node_id)
print(f"Node {node_id} is used in {len(ways)} ways:")
for way in ways:
print(f" Way {way['id']}: {way['tag'].get('name', 'Unnamed')}")
# Find relations using this node
relations = api.NodeRelations(node_id)
print(f"Node {node_id} is used in {len(relations)} relations:")
for relation in relations:
print(f" Relation {relation['id']}: {relation['tag'].get('name', 'Unnamed')}")Retrieve multiple nodes in a single API call for efficiency.
def NodesGet(NodeIdList):
"""
Returns dict with node IDs as keys for multiple nodes.
Parameters:
- NodeIdList (list[int]): List of node IDs to retrieve
Returns:
dict: Node IDs as keys with NodeData dicts as values
"""Usage Example:
import osmapi
api = osmapi.OsmApi()
# Get multiple nodes efficiently
node_ids = [123, 456, 789, 101112]
nodes = api.NodesGet(node_ids)
for node_id, node_data in nodes.items():
print(f"Node {node_id}: ({node_data['lat']}, {node_data['lon']})")
print(f" Tags: {node_data['tag']}")
# Process nodes that were found
found_ids = set(nodes.keys())
missing_ids = set(node_ids) - found_ids
if missing_ids:
print(f"Missing nodes: {missing_ids}")NodeData = {
'id': int, # Node ID (assigned by OSM after creation)
'lat': float, # Latitude in decimal degrees (required)
'lon': float, # Longitude in decimal degrees (required)
'tag': dict, # Key-value pairs for attributes
'version': int, # Version number (starts at 1)
'changeset': int, # ID of changeset that last modified this node
'user': str, # Username of last editor
'uid': int, # User ID of last editor
'timestamp': str, # ISO timestamp of last modification
'visible': bool # True if visible, False if deleted
}# Point of Interest
{
"name": "Central Library",
"amenity": "library",
"opening_hours": "Mo-Fr 09:00-21:00; Sa 10:00-18:00",
"website": "https://library.example.com",
"wheelchair": "yes"
}
# Transportation
{
"name": "Main Street Station",
"public_transport": "stop_position",
"bus": "yes",
"ref": "123"
}
# Geographic feature
{
"name": "Mount Example",
"natural": "peak",
"ele": "1234",
"source": "GPS survey"
}Node operations can raise various exceptions based on different scenarios:
import osmapi
api = osmapi.OsmApi()
try:
node = api.NodeGet(999999)
except osmapi.ElementNotFoundApiError:
print("Node does not exist")
except osmapi.ElementDeletedApiError:
print("Node has been deleted")
try:
with api.Changeset({"comment": "Test"}) as changeset_id:
api.NodeCreate({"lat": 0, "lon": 0, "tag": {}})
except osmapi.UsernamePasswordMissingError:
print("Authentication required for creating nodes")
except osmapi.VersionMismatchApiError:
print("Version conflict - node was modified by another user")Install with Tessl CLI
npx tessl i tessl/pypi-osmapi