or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdchangesets.mderrors.mdindex.mdnodes.mdnotes.mdrelations.mdways.md

changesets.mddocs/

0

# Changeset Management

1

2

Complete changeset lifecycle including creation, modification, closure, and discussion management. Changesets group related edits together and provide context for modifications to OpenStreetMap data through metadata, comments, and discussion threads.

3

4

## Capabilities

5

6

### Changeset Context Manager

7

8

Automatic changeset management using Python context managers for streamlined editing workflows.

9

10

```python { .api }

11

@contextmanager

12

def Changeset(ChangesetTags={}):

13

"""

14

Context manager for a Changeset that automatically handles opening and closing.

15

16

Parameters:

17

- ChangesetTags (dict, optional): Tags to apply to the changeset

18

19

Returns:

20

int: Changeset ID

21

22

Raises:

23

- UsernamePasswordMissingError: If no authentication provided

24

- ChangesetAlreadyOpenError: If changeset already open

25

"""

26

```

27

28

**Usage Example:**

29

30

```python

31

import osmapi

32

33

api = osmapi.OsmApi(username="your_username", password="your_password")

34

35

# Automatic changeset management

36

with api.Changeset({"comment": "Adding new POIs", "source": "GPS survey"}) as changeset_id:

37

print(f"Working in changeset {changeset_id}")

38

39

# All operations within this block use the same changeset

40

node1 = api.NodeCreate({"lat": 47.6, "lon": -122.3, "tag": {"amenity": "cafe"}})

41

node2 = api.NodeCreate({"lat": 47.61, "lon": -122.31, "tag": {"amenity": "bank"}})

42

43

# Changeset automatically closed when leaving context

44

print("Changeset has been closed")

45

```

46

47

### Changeset Retrieval

48

49

Get changeset information with optional discussion data.

50

51

```python { .api }

52

def ChangesetGet(ChangesetId, include_discussion=False):

53

"""

54

Returns changeset with ChangesetId as a dict.

55

56

Parameters:

57

- ChangesetId (int): Unique identifier of the changeset

58

- include_discussion (bool, optional): Include discussion thread

59

60

Returns:

61

dict: Changeset data including id, open status, tag, timestamps,

62

bounds, user info, and optionally discussion

63

"""

64

```

65

66

**Usage Example:**

67

68

```python

69

import osmapi

70

71

api = osmapi.OsmApi()

72

73

# Get basic changeset info

74

changeset = api.ChangesetGet(12345)

75

print(f"Changeset {changeset['id']}: {changeset['tag'].get('comment', 'No comment')}")

76

print(f"User: {changeset['user']} (ID: {changeset['uid']})")

77

print(f"Created: {changeset['created_at']}")

78

print(f"Open: {changeset['open']}")

79

80

if not changeset['open']:

81

print(f"Closed: {changeset['closed_at']}")

82

83

# Get changeset with discussion

84

changeset_with_discussion = api.ChangesetGet(12345, include_discussion=True)

85

if changeset_with_discussion['discussion']:

86

print(f"\nDiscussion ({len(changeset_with_discussion['discussion'])} comments):")

87

for comment in changeset_with_discussion['discussion']:

88

print(f" {comment['user']}: {comment['text']}")

89

```

90

91

### Manual Changeset Creation

92

93

Create and manage changesets manually for fine-grained control.

94

95

```python { .api }

96

def ChangesetCreate(ChangesetTags={}):

97

"""

98

Opens a changeset.

99

100

Parameters:

101

- ChangesetTags (dict, optional): Tags to apply to the changeset

102

103

Returns:

104

int: Changeset ID

105

106

Raises:

107

- UsernamePasswordMissingError: If no authentication provided

108

- ChangesetAlreadyOpenError: If changeset already open

109

- OsmApiError: If trying to create test changeset on production

110

"""

111

```

112

113

**Usage Example:**

114

115

```python

116

import osmapi

117

118

api = osmapi.OsmApi(username="your_username", password="your_password")

119

120

# Create changeset manually

121

changeset_id = api.ChangesetCreate({

122

"comment": "Manual data cleanup",

123

"source": "Local knowledge",

124

"created_by": "MyEditingApp/1.0"

125

})

126

127

print(f"Created changeset {changeset_id}")

128

129

try:

130

# Perform operations

131

node = api.NodeCreate({"lat": 47.6, "lon": -122.3, "tag": {"amenity": "shop"}})

132

print(f"Created node {node['id']}")

133

134

finally:

135

# Always close changeset

136

closed_id = api.ChangesetClose()

137

print(f"Closed changeset {closed_id}")

138

```

139

140

### Changeset Updates

141

142

Update changeset tags and metadata.

143

144

```python { .api }

145

def ChangesetUpdate(ChangesetTags={}):

146

"""

147

Updates current changeset with ChangesetTags.

148

149

Parameters:

150

- ChangesetTags (dict): Tags to update on the changeset

151

152

Returns:

153

int: Changeset ID

154

155

Raises:

156

- UsernamePasswordMissingError: If no authentication provided

157

- NoChangesetOpenError: If no changeset is open

158

- ChangesetClosedApiError: If changeset is closed

159

"""

160

```

161

162

**Usage Example:**

163

164

```python

165

import osmapi

166

167

api = osmapi.OsmApi(username="your_username", password="your_password")

168

169

changeset_id = api.ChangesetCreate({"comment": "Work in progress"})

170

171

# Update changeset with more detailed information

172

api.ChangesetUpdate({

173

"comment": "Updated building addresses from field survey",

174

"source": "GPS survey + local knowledge",

175

"survey:date": "2024-01-15"

176

})

177

178

# Continue with operations

179

node = api.NodeCreate({"lat": 47.6, "lon": -122.3, "tag": {"addr:housenumber": "123"}})

180

181

api.ChangesetClose()

182

```

183

184

### Changeset Closure

185

186

Explicitly close an open changeset.

187

188

```python { .api }

189

def ChangesetClose():

190

"""

191

Closes current changeset.

192

193

Returns:

194

int: Changeset ID that was closed

195

196

Raises:

197

- UsernamePasswordMissingError: If no authentication provided

198

- NoChangesetOpenError: If no changeset is open

199

- ChangesetClosedApiError: If changeset already closed

200

"""

201

```

202

203

### Batch Upload Operations

204

205

Upload multiple changes to a changeset in a single operation.

206

207

```python { .api }

208

def ChangesetUpload(ChangesData):

209

"""

210

Upload data with the ChangesData list of change operations.

211

212

Parameters:

213

- ChangesData (list[dict]): List of change operations with

214

type, action, and data keys

215

216

Returns:

217

list[dict]: Updated ChangesData with assigned IDs and versions

218

219

Raises:

220

- UsernamePasswordMissingError: If no authentication provided

221

- ChangesetClosedApiError: If changeset is closed

222

"""

223

```

224

225

**Usage Example:**

226

227

```python

228

import osmapi

229

230

api = osmapi.OsmApi(username="your_username", password="your_password")

231

232

changeset_id = api.ChangesetCreate({"comment": "Batch operations example"})

233

234

# Prepare batch changes

235

changes_data = [

236

{

237

"type": "node",

238

"action": "create",

239

"data": {"lat": 47.6, "lon": -122.3, "tag": {"amenity": "cafe"}}

240

},

241

{

242

"type": "node",

243

"action": "create",

244

"data": {"lat": 47.61, "lon": -122.31, "tag": {"amenity": "bank"}}

245

}

246

]

247

248

# Upload all changes at once

249

result = api.ChangesetUpload(changes_data)

250

251

for change in result:

252

if change["action"] == "create":

253

print(f"Created {change['type']} {change['data']['id']}")

254

255

api.ChangesetClose()

256

```

257

258

### Changeset Download

259

260

Download all changes made in a specific changeset.

261

262

```python { .api }

263

def ChangesetDownload(ChangesetId):

264

"""

265

Download data from changeset ChangesetId.

266

267

Parameters:

268

- ChangesetId (int): Unique identifier of the changeset

269

270

Returns:

271

list[dict]: List of change operations with type, action, and data keys

272

"""

273

```

274

275

**Usage Example:**

276

277

```python

278

import osmapi

279

280

api = osmapi.OsmApi()

281

282

# Download changeset data

283

changes = api.ChangesetDownload(12345)

284

285

print(f"Changeset contains {len(changes)} changes:")

286

287

# Analyze changes by type and action

288

summary = {}

289

for change in changes:

290

key = f"{change['action']} {change['type']}"

291

summary[key] = summary.get(key, 0) + 1

292

293

for change_type, count in summary.items():

294

print(f" {count} {change_type} operations")

295

296

# Show details of first few changes

297

for i, change in enumerate(changes[:3]):

298

element = change['data']

299

print(f"\nChange {i+1}: {change['action']} {change['type']} {element['id']}")

300

if 'tag' in element and element['tag']:

301

print(f" Tags: {element['tag']}")

302

```

303

304

### Changeset Queries

305

306

Search for changesets based on various criteria.

307

308

```python { .api }

309

def ChangesetsGet(

310

min_lon=None,

311

min_lat=None,

312

max_lon=None,

313

max_lat=None,

314

userid=None,

315

username=None,

316

closed_after=None,

317

created_before=None,

318

only_open=False,

319

only_closed=False

320

):

321

"""

322

Returns changesets matching criteria as a dict.

323

324

Parameters:

325

- min_lon, min_lat, max_lon, max_lat (float, optional): Bounding box

326

- userid (int, optional): User ID filter

327

- username (str, optional): Username filter

328

- closed_after (str, optional): ISO timestamp filter

329

- created_before (str, optional): ISO timestamp filter

330

- only_open (bool, optional): Only open changesets

331

- only_closed (bool, optional): Only closed changesets

332

333

Returns:

334

dict: Changeset IDs as keys with ChangesetData dicts as values

335

"""

336

```

337

338

**Usage Example:**

339

340

```python

341

import osmapi

342

343

api = osmapi.OsmApi()

344

345

# Find changesets in a bounding box

346

changesets = api.ChangesetsGet(

347

min_lon=-122.4,

348

min_lat=47.5,

349

max_lon=-122.2,

350

max_lat=47.7

351

)

352

353

print(f"Found {len(changesets)} changesets in the area:")

354

for cs_id, cs_data in changesets.items():

355

print(f" {cs_id}: {cs_data['tag'].get('comment', 'No comment')}")

356

print(f" by {cs_data['user']} at {cs_data['created_at']}")

357

358

# Find recent changesets by a specific user

359

recent_changesets = api.ChangesetsGet(

360

username="specific_user",

361

closed_after="2024-01-01T00:00:00Z"

362

)

363

364

print(f"\nRecent changesets by user: {len(recent_changesets)}")

365

```

366

367

### Changeset Discussion

368

369

Add comments and manage discussions on changesets.

370

371

```python { .api }

372

def ChangesetComment(ChangesetId, comment):

373

"""

374

Adds a comment to the changeset ChangesetId.

375

376

Parameters:

377

- ChangesetId (int): Changeset to comment on

378

- comment (str): Comment text

379

380

Returns:

381

dict: Updated ChangesetData with new comment

382

383

Raises:

384

- UsernamePasswordMissingError: If no authentication provided

385

- ChangesetClosedApiError: If changeset is closed

386

"""

387

388

def ChangesetSubscribe(ChangesetId):

389

"""

390

Subscribe to changeset discussion to receive notifications.

391

392

Parameters:

393

- ChangesetId (int): Changeset to subscribe to

394

395

Returns:

396

dict: Updated ChangesetData

397

398

Raises:

399

- UsernamePasswordMissingError: If no authentication provided

400

- AlreadySubscribedApiError: If already subscribed

401

"""

402

403

def ChangesetUnsubscribe(ChangesetId):

404

"""

405

Unsubscribe from changeset discussion notifications.

406

407

Parameters:

408

- ChangesetId (int): Changeset to unsubscribe from

409

410

Returns:

411

dict: Updated ChangesetData

412

413

Raises:

414

- UsernamePasswordMissingError: If no authentication provided

415

- NotSubscribedApiError: If not subscribed

416

"""

417

```

418

419

**Usage Example:**

420

421

```python

422

import osmapi

423

424

api = osmapi.OsmApi(username="your_username", password="your_password")

425

426

changeset_id = 12345

427

428

# Subscribe to discussion

429

try:

430

api.ChangesetSubscribe(changeset_id)

431

print(f"Subscribed to changeset {changeset_id} discussion")

432

except osmapi.AlreadySubscribedApiError:

433

print("Already subscribed to this changeset")

434

435

# Add a comment

436

updated_changeset = api.ChangesetComment(

437

changeset_id,

438

"Thanks for the improvements to the road network!"

439

)

440

441

print(f"Added comment to changeset {changeset_id}")

442

print(f"Comments count: {updated_changeset['comments_count']}")

443

444

# Later, unsubscribe if needed

445

try:

446

api.ChangesetUnsubscribe(changeset_id)

447

print("Unsubscribed from changeset discussion")

448

except osmapi.NotSubscribedApiError:

449

print("Was not subscribed to this changeset")

450

```

451

452

### Automatic Changeset Management

453

454

Force flush of pending changes in automatic mode.

455

456

```python { .api }

457

def flush():

458

"""

459

Force the changes to be uploaded to OSM and the changeset to be closed.

460

461

Raises:

462

- UsernamePasswordMissingError: If no authentication provided

463

- NoChangesetOpenError: If no changeset is open

464

- ChangesetAlreadyOpenError: If changeset conflict occurs

465

"""

466

```

467

468

**Usage Example:**

469

470

```python

471

import osmapi

472

473

# Configure automatic changeset management

474

api = osmapi.OsmApi(

475

username="your_username",

476

password="your_password",

477

changesetauto=True,

478

changesetautotags={"comment": "Automated cleanup"},

479

changesetautosize=100

480

)

481

482

# Make several changes - handled automatically

483

api.NodeCreate({"lat": 47.6, "lon": -122.3, "tag": {"amenity": "cafe"}})

484

api.NodeCreate({"lat": 47.61, "lon": -122.31, "tag": {"amenity": "bank"}})

485

486

# Force immediate upload and closure

487

api.flush()

488

print("All pending changes uploaded and changeset closed")

489

```

490

491

## Changeset Data Structure

492

493

### ChangesetData Dictionary

494

495

```python { .api }

496

ChangesetData = {

497

'id': int, # Changeset ID

498

'open': bool, # True if changeset is still open

499

'tag': dict, # Changeset tags (comment, source, etc.)

500

'created_at': str, # ISO timestamp of creation

501

'closed_at': str, # ISO timestamp of closure (if closed)

502

'comments_count': int, # Number of discussion comments

503

'discussion': list, # Discussion comments (if requested)

504

'max_lon': float, # Eastern boundary of changes

505

'max_lat': float, # Northern boundary of changes

506

'min_lon': float, # Western boundary of changes

507

'min_lat': float, # Southern boundary of changes

508

'user': str, # Username of changeset creator

509

'uid': int # User ID of changeset creator

510

}

511

512

ChangeData = {

513

'type': str, # 'node', 'way', or 'relation'

514

'action': str, # 'create', 'modify', or 'delete'

515

'data': dict # Element data (NodeData, WayData, or RelationData)

516

}

517

```

518

519

## Common Changeset Tags

520

521

### Standard Tags

522

523

```python

524

{

525

"comment": "Updated building addresses from survey",

526

"source": "GPS survey + local knowledge",

527

"created_by": "MyApp/1.0",

528

"locale": "en_US"

529

}

530

```

531

532

### Import Tags

533

534

```python

535

{

536

"comment": "Import government building dataset",

537

"source": "City Planning Department Open Data",

538

"import": "yes",

539

"url": "https://data.city.gov/buildings"

540

}

541

```

542

543

### Mechanical Edit Tags

544

545

```python

546

{

547

"comment": "Fix address format inconsistencies",

548

"source": "existing OSM data",

549

"mechanical": "yes",

550

"bot": "no"

551

}

552

```

553

554

## Changeset Best Practices

555

556

### Good Changeset Comments

557

- Be specific about what was changed

558

- Mention the source of information

559

- Use consistent language and format

560

- Keep comments concise but descriptive

561

562

### Changeset Size Management

563

- Keep changesets focused on related changes

564

- Avoid mixing different types of edits

565

- Use reasonable batch sizes (default 500 elements)

566

- Consider geographic locality of changes

567

568

### Error Handling

569

570

```python

571

import osmapi

572

573

api = osmapi.OsmApi(username="user", password="pass")

574

575

try:

576

changeset_id = api.ChangesetCreate({"comment": "Test changeset"})

577

# ... perform operations

578

api.ChangesetClose()

579

580

except osmapi.ChangesetAlreadyOpenError:

581

print("Already have an open changeset")

582

except osmapi.ChangesetClosedApiError:

583

print("Changeset was closed by someone else or timeout")

584

except osmapi.UsernamePasswordMissingError:

585

print("Authentication required for changeset operations")

586

```