Python wrapper for the OSM API
—
Full Notes API support including creation, commenting, status management, and search functionality. Notes enable community interaction and issue reporting for OpenStreetMap, allowing users to highlight problems, suggest improvements, and collaborate on data quality.
Get notes within a specified bounding box with filtering options.
def NotesGet(min_lon, min_lat, max_lon, max_lat, limit=100, closed=7):
"""
Returns a list of notes in the specified bounding box.
Parameters:
- min_lon (float): Western boundary
- min_lat (float): Southern boundary
- max_lon (float): Eastern boundary
- max_lat (float): Northern boundary
- limit (int, optional): Maximum number of results (default: 100)
- closed (int, optional): Days closed notes remain visible (default: 7)
0 = only open notes, -1 = all notes
Returns:
list[dict]: List of note dictionaries with id, coordinates, status,
dates, user info, and comments
"""Usage Example:
import osmapi
api = osmapi.OsmApi()
# Get notes in downtown Seattle area
notes = api.NotesGet(
min_lon=-122.35,
min_lat=47.60,
max_lon=-122.30,
max_lat=47.63,
limit=50,
closed=14 # Include notes closed in last 14 days
)
print(f"Found {len(notes)} notes in the area:")
for note in notes:
status_icon = "🟢" if note['status'] == 'open' else "🔴"
print(f"{status_icon} Note {note['id']}: {note['status']}")
print(f" Location: ({note['lat']}, {note['lon']})")
print(f" Created: {note['date_created']}")
# Show first comment (original note text)
if note['comments']:
first_comment = note['comments'][0]
print(f" Text: {first_comment['text'][:100]}...")Get detailed information about a specific note.
def NoteGet(id):
"""
Returns a note as dict.
Parameters:
- id (int): Unique identifier of the note
Returns:
dict: Note data including id, coordinates, status, dates,
user info, and complete comment thread
"""Usage Example:
import osmapi
api = osmapi.OsmApi()
# Get specific note with full details
note = api.NoteGet(12345)
print(f"Note {note['id']}: {note['status']}")
print(f"Location: ({note['lat']}, {note['lon']})")
print(f"Created: {note['date_created']}")
if note['date_closed']:
print(f"Closed: {note['date_closed']}")
print(f"\nComment thread ({len(note['comments'])} comments):")
for i, comment in enumerate(note['comments']):
user = comment['user'] or "Anonymous"
action_text = {
'opened': 'opened this note',
'commented': 'commented',
'closed': 'closed this note'
}.get(comment['action'], comment['action'])
print(f"{i+1}. {user} {action_text} on {comment['date']}")
print(f" {comment['text']}")Create new notes to report issues or suggest improvements.
def NoteCreate(NoteData):
"""
Creates a note based on the supplied NoteData dict.
Parameters:
- NoteData (dict): Note data with coordinates and text
Required: lat (float), lon (float), text (str)
Returns:
dict: Complete note data including assigned id, status, dates,
and initial comment
"""Usage Example:
import osmapi
api = osmapi.OsmApi()
# Create a new note (no authentication required)
new_note = api.NoteCreate({
"lat": 47.6062,
"lon": -122.3321,
"text": "This intersection needs a traffic light. Heavy pedestrian traffic from the nearby school makes crossing dangerous during rush hours."
})
print(f"Created note {new_note['id']}")
print(f"Status: {new_note['status']}")
print(f"Location: ({new_note['lat']}, {new_note['lon']})")
print(f"Created: {new_note['date_created']}")
# The text becomes the first comment
first_comment = new_note['comments'][0]
print(f"Initial comment: {first_comment['text']}")Add comments to existing notes to provide additional information or updates.
def NoteComment(NoteId, comment):
"""
Adds a new comment to a note.
Parameters:
- NoteId (int): ID of the note to comment on
- comment (str): Comment text
Returns:
dict: Updated note data with new comment added
"""Usage Example:
import osmapi
api = osmapi.OsmApi()
note_id = 12345
# Add a comment (no authentication required)
updated_note = api.NoteComment(
note_id,
"I've contacted the city traffic department about this intersection. They've added it to their review queue for next quarter."
)
print(f"Added comment to note {note_id}")
print(f"Note now has {len(updated_note['comments'])} comments")
# Show the new comment
latest_comment = updated_note['comments'][-1]
print(f"Latest comment by {latest_comment['user'] or 'Anonymous'}:")
print(f" {latest_comment['text']}")Close or reopen notes based on resolution status.
def NoteClose(NoteId, comment):
"""
Closes a note.
Parameters:
- NoteId (int): ID of the note to close
- comment (str): Closing comment explaining resolution
Returns:
dict: Updated note data with closed status
Raises:
- UsernamePasswordMissingError: If no authentication provided
"""
def NoteReopen(NoteId, comment):
"""
Reopens a closed note.
Parameters:
- NoteId (int): ID of the note to reopen
- comment (str): Comment explaining why note is reopened
Returns:
dict: Updated note data with open status
Raises:
- UsernamePasswordMissingError: If no authentication provided
- ElementDeletedApiError: If note was deleted
- ElementNotFoundApiError: If note cannot be found
"""Usage Example:
import osmapi
# Authentication required for closing/reopening notes
api = osmapi.OsmApi(username="your_username", password="your_password")
note_id = 12345
# Close a note when issue is resolved
closed_note = api.NoteClose(
note_id,
"Traffic light has been installed at this intersection. Issue resolved."
)
print(f"Closed note {note_id}")
print(f"Status: {closed_note['status']}")
print(f"Closed date: {closed_note['date_closed']}")
# Reopen if issue returns or closure was premature
if closed_note['status'] == 'closed':
reopened_note = api.NoteReopen(
note_id,
"Traffic light was removed during road construction. Issue has returned."
)
print(f"Reopened note {note_id}")
print(f"Status: {reopened_note['status']}")Search for notes by text content.
def NotesSearch(query, limit=100, closed=7):
"""
Returns a list of notes that match the given search query.
Parameters:
- query (str): Search query text
- limit (int, optional): Maximum number of results (default: 100)
- closed (int, optional): Days closed notes remain searchable (default: 7)
0 = only open notes, -1 = all notes
Returns:
list[dict]: List of note dictionaries matching the search criteria
"""Usage Example:
import osmapi
api = osmapi.OsmApi()
# Search for notes about traffic lights
traffic_notes = api.NotesSearch(
query="traffic light",
limit=25,
closed=30 # Include notes closed in last 30 days
)
print(f"Found {len(traffic_notes)} notes about traffic lights:")
for note in traffic_notes:
print(f"Note {note['id']} ({note['status']})")
print(f" Location: ({note['lat']:.4f}, {note['lon']:.4f})")
# Show matching text from comments
for comment in note['comments']:
if 'traffic light' in comment['text'].lower():
text_snippet = comment['text'][:100]
print(f" Match: {text_snippet}...")
break
# Search for notes about specific amenities
shop_notes = api.NotesSearch("shop closed permanently", limit=10)
print(f"\nFound {len(shop_notes)} notes about permanently closed shops")NoteData = {
'id': int, # Note ID (assigned by OSM)
'lat': float, # Latitude in decimal degrees
'lon': float, # Longitude in decimal degrees
'status': str, # 'open' or 'closed'
'date_created': str, # ISO timestamp of creation
'date_closed': str, # ISO timestamp of closure (or None)
'uid': int, # User ID of creator (or None for anonymous)
'user': str, # Username of creator (or None for anonymous)
'comments': list[dict] # List of comment objects
}
NoteComment = {
'date': str, # ISO timestamp of comment
'action': str, # 'opened', 'commented', or 'closed'
'text': str, # Comment text content
'html': str, # HTML version of comment (with links)
'uid': int, # User ID of commenter (or None)
'user': str # Username of commenter (or None)
}import osmapi
api = osmapi.OsmApi()
# Report a mapping error
api.NoteCreate({
"lat": 47.6205,
"lon": -122.3493,
"text": "This building is labeled as 'City Hall' but it's actually a library. The real City Hall is two blocks south."
})
# Report missing information
api.NoteCreate({
"lat": 47.6097,
"lon": -122.3331,
"text": "New restaurant opened here: 'Pasta Palace'. Italian cuisine, opens 11 AM - 10 PM daily."
})import osmapi
api = osmapi.OsmApi()
# Follow up on existing notes
note_id = 54321
api.NoteComment(
note_id,
"I can confirm this business has moved. The new location is at 456 Oak Street. Should we update the map?"
)
# Provide additional context
api.NoteComment(
note_id,
"According to the business website, they moved on March 15th. The old location is now vacant."
)import osmapi
api = osmapi.OsmApi()
# Search for validation-related notes
validation_notes = api.NotesSearch("validation error", limit=50, closed=-1)
print("Data quality issues found:")
for note in validation_notes:
# Analyze note patterns
age_days = (datetime.now() - note['date_created']).days
print(f"Note {note['id']}: {age_days} days old, {note['status']}")
# Check if issue was addressed
if note['status'] == 'closed':
resolution_time = (note['date_closed'] - note['date_created']).days
print(f" Resolved in {resolution_time} days")Notes operations can raise exceptions in certain scenarios:
import osmapi
api = osmapi.OsmApi()
try:
note = api.NoteGet(999999)
except osmapi.ElementNotFoundApiError:
print("Note does not exist")
# Authentication required for closing/reopening
try:
api.NoteClose(12345, "Issue resolved")
except osmapi.UsernamePasswordMissingError:
print("Authentication required to close notes")
try:
api.NoteReopen(12345, "Issue returned")
except osmapi.ElementDeletedApiError:
print("Note has been deleted")
except osmapi.NoteAlreadyClosedApiError:
print("Note is already closed")import osmapi
api = osmapi.OsmApi()
# Focused area search with temporal filtering
recent_notes = api.NotesGet(
min_lon=-122.32,
min_lat=47.61,
max_lon=-122.31,
max_lat=47.62,
limit=20,
closed=3 # Only notes closed in last 3 days
)
# Multi-language search for international areas
multilingual_search_terms = ["shop closed", "magasin fermé", "tienda cerrada"]
all_closure_notes = []
for term in multilingual_search_terms:
notes = api.NotesSearch(term, limit=25)
all_closure_notes.extend(notes)
# Remove duplicates based on note ID
unique_notes = {note['id']: note for note in all_closure_notes}
print(f"Found {len(unique_notes)} unique notes about closures")Install with Tessl CLI
npx tessl i tessl/pypi-osmapi