Coverage for gws-app/gws/__init__.py: 99%

2083 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-10-23 20:06 +0200

1"""GBD WebSuite: basic types and interfaces. 

2 

3The ``gws`` package holds the types that all parts of GBD WebSuite share: the 

4basic data containers, enums and type aliases, the error classes, the object 

5tree interfaces, the base ``Config`` and ``Props`` classes, and the interfaces 

6of all configurable objects (``gws.Layer``, ``gws.Map``, ``gws.Model``, 

7``gws.Grabber``, ``gws.Project``, ``gws.Application`` and many more). Every GWS 

8module imports it with ``import gws``. 

9 

10``gws/__init__.py`` is generated by ``app/_make_init.py`` from this file 

11(``__init__.pyinc``). Each ``# @include`` line is replaced with the contents of 

12a ``*.pyinc`` fragment, so the types defined in ``core/*.pyinc`` and in the 

13``types.pyinc`` files of the other packages all end up in the ``gws`` 

14namespace. The package also re-exports these modules of ``gws.core`` under 

15short names: 

16 

17- ``gws.u``: general utilities (``gws.core.util``), 

18- ``gws.c``: constants (``gws.core.const``), 

19- ``gws.log``: logging, 

20- ``gws.debug``: debugging helpers, 

21- ``gws.env``: environment variables, 

22 

23and ``gws.ext``, the decorators that register extension classes and command 

24methods. 

25 

26Code base layout 

27---------------- 

28 

29- ``gws.core``: the lowest layer: basic types, the object tree, logging, 

30 constants and general utilities. 

31- ``gws.lib``: general purpose libraries (CRS, images, XML, networking, SVG, 

32 styles and so on), independent of the GWS object tree. 

33- ``gws.gis``: GIS functionality built on ``lib``: map rendering, zoom 

34 levels, source layers and tile caches. 

35- ``gws.base``: the base classes and managers of the configurable objects 

36 (application, projects, maps, layers, models, actions, auth and others). 

37- ``gws.plugin``: concrete implementations of the base classes (layer types, 

38 auth providers, OWS services, templates, model fields and so on), each 

39 registered with a ``gws.ext`` decorator. 

40- ``gws.config``: configuration parsing and loading, which builds the object 

41 tree from the configuration. 

42- ``gws.spec``: the spec generator and runtime: type metadata used to read 

43 configuration and requests and to find extension classes and commands. 

44- ``gws.server``: configuration and control of the embedded servers (uWSGI, 

45 NGINX, the spool server and the monitor). 

46- ``gws.ext``: the extension decorators (``gws.ext.object.*``, 

47 ``gws.ext.config.*``, ``gws.ext.props.*``, ``gws.ext.command.*``). 

48 ``gws/ext/__init__.py`` is generated as well. 

49- ``gws.test``: the test framework. 

50 

51The intended import hierarchy is ``core < lib < gis < base < plugin``: each 

52layer imports only from the layers below it. ``config``, ``spec`` and 

53``server`` import ``lib`` and each other, and ``base`` imports them. Nothing 

54outside ``gws.plugin`` imports plugins; plugin classes are found through the 

55specs and loaded on demand. 

56 

57Example:: 

58 

59 import gws 

60 import gws.base.layer 

61 

62 d = gws.Data(name='roads', crs='EPSG:3857') 

63 d.name # 'roads' 

64 d.title # None, missing attributes are None 

65 gws.u.get({'a': {'b': 1}}, 'a.b') # 1 

66 

67 @gws.ext.config.layer('my') 

68 class Config(gws.base.layer.Config): 

69 pass 

70 

71 @gws.ext.object.layer('my') 

72 class Object(gws.base.layer.Object): 

73 def configure(self): 

74 gws.log.info(f'configuring {self.uid}') 

75""" 

76 

77from typing import ( 

78 TYPE_CHECKING, 

79 TypeAlias, 

80 cast, 

81 Any, 

82 Callable, 

83 ContextManager, 

84 Generator, 

85 Iterable, 

86 Iterator, 

87 Literal, 

88 Optional, 

89 Protocol, 

90 Union, 

91) 

92 

93from collections.abc import ( 

94 Mapping, 

95 Sequence, 

96) 

97 

98import enum 

99import datetime 

100 

101if TYPE_CHECKING: 

102 import sqlalchemy 

103 import numpy.typing 

104 

105# mypy: disable-error-code="empty-body" 

106 

107 

108from . import ext 

109 

110from .core import ( 

111 log, 

112 debug, 

113 env, 

114 const as c, 

115 util as u, 

116) 

117 

118 

119################################################################################ 

120# /core/_data.pyinc 

121 

122 

123# basic data type 

124 

125class Data: 

126 """Basic data object. 

127 

128 This object can be instantiated by passing one or more ``dict`` or ``Data`` arguments 

129 and/or keyword args. All keys and keywords become attributes of the object. 

130 

131 Accessing an undefined attribute returns ``None`` and no error is raised, 

132 unless the attribute name starts with an underscore. 

133 

134 Example:: 

135 

136 d = gws.Data({'a': 1}, b=2) 

137 d.a # 1 

138 d['b'] # 2 

139 d.c # None 

140 """ 

141 

142 def __init__(self, *args, **kwargs): 

143 """Create the object from dicts, ``Data`` objects and keyword args. 

144 

145 Args: 

146 *args: Dicts, Mappings or ``Data`` objects. Other values are ignored. 

147 **kwargs: Keyword args. 

148 """ 

149 self.update(*args, **kwargs) 

150 

151 def __repr__(self): 

152 """Return the ``repr`` of the attributes dict.""" 

153 return repr(vars(self)) 

154 

155 def __getitem__(self, key): 

156 """Return an attribute value or ``None`` if it is undefined.""" 

157 return vars(self).get(key) 

158 

159 def __setitem__(self, key, value): 

160 """Set an attribute value.""" 

161 vars(self)[key] = value 

162 

163 # def __getattr__(self, attr): 

164 # if attr.startswith('_'): 

165 # # do not use None fallback for special props 

166 # raise AttributeError(attr) 

167 # return None 

168 

169 def get(self, key, default=None): 

170 """Get an attribute value. 

171 

172 Args: 

173 key: Attribute name. 

174 default: Default value, returned if the attribute is undefined. 

175 

176 Returns: 

177 The attribute value or the default. 

178 """ 

179 return vars(self).get(key, default) 

180 

181 def setdefault(self, key, val): 

182 """Set an attribute value if it is not already set. 

183 

184 Args: 

185 key: Attribute name. 

186 val: Attribute value. 

187 

188 Returns: 

189 The current attribute value, existing or new. 

190 """ 

191 return vars(self).setdefault(key, val) 

192 

193 def set(self, key, val): 

194 """Set an attribute value. 

195 

196 Args: 

197 key: Attribute name. 

198 val: Attribute value. 

199 """ 

200 vars(self)[key] = val 

201 

202 def update(self, *args, **kwargs): 

203 """Update the object with keys and values from args and keywords. 

204 

205 Later values override earlier ones, keywords override args. 

206 

207 Args: 

208 *args: Dicts, Mappings or ``Data`` objects. Other values are ignored. 

209 **kwargs: Keyword args. 

210 """ 

211 

212 d = {} 

213 for a in args: 

214 if isinstance(a, Mapping): 

215 d.update(a) 

216 elif isinstance(a, Data): 

217 d.update(vars(a)) 

218 d.update(kwargs) 

219 vars(self).update(d) 

220 

221 

222# getattr needs to be defined out of class, otherwise the type checker will accept any attribute 

223 

224def _data_getattr(self, attr): 

225 """Return ``None`` for undefined attributes, raise ``AttributeError`` for names starting with an underscore.""" 

226 if attr.startswith('_'): 

227 # do not use None fallback for special props 

228 raise AttributeError(attr) 

229 return None 

230 

231 

232setattr(Data, '__getattr__', _data_getattr) 

233 

234 

235def is_data_object(x): 

236 """Check if the argument is a ``Data`` object. 

237 

238 Args: 

239 x: A value. 

240 

241 Returns: 

242 ``True`` if the value is a ``Data`` object. 

243 """ 

244 return isinstance(x, Data) 

245 

246 

247def to_data_object(x) -> 'Data': 

248 """Convert a value to a ``Data`` object. 

249 

250 If the argument is already a ``Data`` object, simply return it. 

251 If the argument is ``None``, an empty object is returned. 

252 

253 Args: 

254 x: A ``Data`` object, a Mapping or ``None``. 

255 

256 Returns: 

257 A ``Data`` object. 

258 

259 Raises: 

260 ValueError: If the value cannot be converted. 

261 """ 

262 

263 if is_data_object(x): 

264 return x 

265 if isinstance(x, Mapping): 

266 return Data(x) 

267 if x is None: 

268 return Data() 

269 raise ValueError(f'cannot convert {x!r} to Data') 

270################################################################################ 

271 

272 

273 

274u.is_data_object = is_data_object 

275u.to_data_object = to_data_object 

276 

277 

278 

279################################################################################ 

280# /core/_basic.pyinc 

281 

282 

283class Enum(enum.Enum): 

284 """Enumeration type. 

285 

286 Despite being declared as extending ``Enum`` (for IDE support), this class is actually just a simple object 

287 and intended to be used as a collection of attributes. It doesn't provide any ``Enum``-specific utilities. 

288 

289 The rationale behind this is that we need ``Enum`` members (e.g. ``Color.RED``) to be scalars, 

290 and not complex objects as in the standard ``Enum``. 

291 """ 

292 pass 

293 

294 

295# hack to make Enum a simple object 

296globals()['Enum'] = type('Enum', (), {}) 

297 

298Extent: TypeAlias = tuple[float, float, float, float] 

299"""An array of 4 elements representing extent coordinates ``[min-x, min-y, max-x, max-y]``.""" 

300 

301Point: TypeAlias = tuple[float, float] 

302"""Point coordinates ``[x, y]``.""" 

303 

304Size: TypeAlias = tuple[float, float] 

305"""Size ``[width, height]``.""" 

306 

307 

308class Origin(Enum): 

309 """Grid origin.""" 

310 

311 nw = 'nw' 

312 """North-west.""" 

313 sw = 'sw' 

314 """South-west.""" 

315 ne = 'ne' 

316 """North-east.""" 

317 se = 'se' 

318 """South-east.""" 

319 lt = 'nw' 

320 """Left top.""" 

321 lb = 'sw' 

322 """Left bottom.""" 

323 rt = 'ne' 

324 """Right top.""" 

325 rb = 'se' 

326 """Right bottom.""" 

327 

328 

329FilePath: TypeAlias = str 

330"""File path on the server.""" 

331 

332DirPath: TypeAlias = str 

333"""Directory path on the server.""" 

334 

335Duration: TypeAlias = str 

336"""Duration like ``1w 2d 3h 4m 5s`` or an integer number of seconds.""" 

337 

338Color: TypeAlias = str 

339"""CSS color name.""" 

340 

341Regex: TypeAlias = str 

342"""Regular expression, as used in Python.""" 

343 

344FormatStr: TypeAlias = str 

345"""Format string as used in Python.""" 

346 

347DateStr: TypeAlias = str 

348"""ISO date string like ``2019-01-30``.""" 

349 

350DateTimeStr: TypeAlias = str 

351"""ISO datetime string like ``2019-01-30 01:02:03``.""" 

352 

353Url: TypeAlias = str 

354"""URL.""" 

355 

356ClassRef: TypeAlias = type | str 

357"""Class reference: a type, an ``ext`` class or name like ``gws.ext.object.layer``, or a full class name.""" 

358 

359 

360class Config(Data): 

361 """Object configuration.""" 

362 

363 uid: str = '' 

364 """Unique ID.""" 

365 

366 

367class Props(Data): 

368 """Object properties.""" 

369 

370 uid: str = '' 

371 """Unique ID.""" 

372 

373 

374class Request(Data): 

375 """Command request.""" 

376 

377 projectUid: Optional[str] 

378 """Unique ID of the project.""" 

379 localeUid: Optional[str] 

380 """Locale ID for this request.""" 

381 

382 

383class EmptyRequest(Data): 

384 """Empty command request.""" 

385 

386 pass 

387 

388 

389class ResponseError(Data): 

390 """Response error.""" 

391 

392 code: Optional[int] 

393 """Error code.""" 

394 info: Optional[str] 

395 """Information about the error.""" 

396 

397 

398class Response(Data): 

399 """Command response.""" 

400 

401 error: Optional[ResponseError] 

402 """Response error.""" 

403 status: int 

404 """Response status or exit code.""" 

405 

406 

407class ContentResponse(Response): 

408 """Web response with literal content.""" 

409 

410 content: bytes | str 

411 """Response content.""" 

412 contentFilename: str 

413 """File name for the attachment. If provided, the content is served as an attachment.""" 

414 contentPath: str 

415 """Local path with the content.""" 

416 mimeType: str 

417 """Response mime type.""" 

418 headers: dict 

419 """Additional headers.""" 

420 

421 

422class RedirectResponse(Response): 

423 """Web redirect response.""" 

424 

425 location: str 

426 """Redirect URL.""" 

427 headers: dict 

428 """Additional headers.""" 

429 

430 

431class AttributeType(Enum): 

432 """Feature attribute type.""" 

433 

434 bool = 'bool' 

435 """Boolean value.""" 

436 bytes = 'bytes' 

437 """Binary data.""" 

438 date = 'date' 

439 """Date value.""" 

440 datetime = 'datetime' 

441 """Date and time value.""" 

442 feature = 'feature' 

443 """Feature reference.""" 

444 featurelist = 'featurelist' 

445 """List of features.""" 

446 file = 'file' 

447 """File reference.""" 

448 float = 'float' 

449 """Floating-point number.""" 

450 floatlist = 'floatlist' 

451 """List of floating-point numbers.""" 

452 geometry = 'geometry' 

453 """Geometry reference.""" 

454 int = 'int' 

455 """Integer number.""" 

456 intlist = 'intlist' 

457 """List of integer numbers.""" 

458 str = 'str' 

459 """String value.""" 

460 strlist = 'strlist' 

461 """List of strings.""" 

462 time = 'time' 

463 """Time value.""" 

464 

465 

466class GeometryType(Enum): 

467 """Feature geometry type. 

468 

469 OGC and SQL/MM geometry types. 

470 

471 References: 

472 - OGC 06-103r4 (https://www.ogc.org/standards/sfa) 

473 - https://postgis.net/docs/manual-3.3/using_postgis_dbmanagement.html 

474 """ 

475 

476 geometry = 'geometry' 

477 """Any geometry.""" 

478 

479 point = 'point' 

480 """Point.""" 

481 curve = 'curve' 

482 """Curve.""" 

483 surface = 'surface' 

484 """Surface.""" 

485 

486 geometrycollection = 'geometrycollection' 

487 """Collection of geometries.""" 

488 

489 linestring = 'linestring' 

490 """Line string.""" 

491 line = 'line' 

492 """Line.""" 

493 linearring = 'linearring' 

494 """Linear ring.""" 

495 

496 polygon = 'polygon' 

497 """Polygon.""" 

498 triangle = 'triangle' 

499 """Triangle.""" 

500 

501 polyhedralsurface = 'polyhedralsurface' 

502 """Polyhedral surface.""" 

503 tin = 'tin' 

504 """Triangulated irregular network.""" 

505 

506 multipoint = 'multipoint' 

507 """Collection of points.""" 

508 multicurve = 'multicurve' 

509 """Collection of curves.""" 

510 multilinestring = 'multilinestring' 

511 """Collection of line strings.""" 

512 multipolygon = 'multipolygon' 

513 """Collection of polygons.""" 

514 multisurface = 'multisurface' 

515 """Collection of surfaces.""" 

516 

517 circularstring = 'circularstring' 

518 """Circular arc string.""" 

519 compoundcurve = 'compoundcurve' 

520 """Curve composed of line strings and circular strings.""" 

521 curvepolygon = 'curvepolygon' 

522 """Polygon with curved rings.""" 

523 

524 

525class CliParams(Data): 

526 """Parameters of a command line command.""" 

527 pass 

528################################################################################ 

529 

530 

531################################################################################ 

532# /core/_access.pyinc 

533 

534 

535Acl: TypeAlias = list[tuple[int, str]] 

536"""Access control list. 

537 

538A list of tuples ``(ACL bit, role-name)`` where ``ACL bit`` is ``1`` if the access is allowed and ``0`` otherwise. 

539""" 

540 

541AclStr: TypeAlias = str 

542"""Comma-separated rules ``allow <role>`` or ``deny <role>``.""" 

543 

544 

545class Access(Enum): 

546 """Access mode.""" 

547 

548 read = 'read' 

549 """Permission to read the object.""" 

550 write = 'write' 

551 """Permission to change the object.""" 

552 create = 'create' 

553 """Permission to create new objects.""" 

554 delete = 'delete' 

555 """Permission to delete objects.""" 

556 

557 

558class PermissionsConfig(Config): 

559 """Access rules per operation.""" 

560 

561 all: Optional[AclStr] 

562 """Rules for read, write, create and delete at once.""" 

563 read: Optional[AclStr] 

564 """Rules for reading or using the object.""" 

565 write: Optional[AclStr] 

566 """Rules for changing existing objects.""" 

567 create: Optional[AclStr] 

568 """Rules for creating new objects.""" 

569 delete: Optional[AclStr] 

570 """Rules for deleting objects.""" 

571 edit: Optional[AclStr] 

572 """Rules for write, create and delete at once.""" 

573 

574 

575class ConfigWithAccess(Config): 

576 """Basic config with permissions.""" 

577 

578 access: Optional[AclStr] 

579 """Permission to read or use the object.""" 

580 permissions: Optional[PermissionsConfig] 

581 """Access rules per operation.""" 

582################################################################################ 

583 

584 

585################################################################################ 

586# /core/_error.pyinc 

587 

588 

589class Error(Exception): 

590 """Generic GWS error. 

591 

592 Its ``repr`` is the first line of ``log.exception_backtrace``: the class name, the message and the location. 

593 """ 

594 def __repr__(self): 

595 return log.exception_backtrace(self)[0] 

596 

597 

598class ConfigurationError(Error): 

599 """GWS configuration error.""" 

600 pass 

601 

602 

603class NotFoundError(Error): 

604 """Generic 'object not found' error.""" 

605 pass 

606 

607 

608class ForbiddenError(Error): 

609 """Generic 'forbidden' error.""" 

610 pass 

611 

612 

613class AuthenticationError(ForbiddenError): 

614 """Credentials are missing, wrong or expired.""" 

615 pass 

616 

617 

618class BadRequestError(Error): 

619 """Generic 'bad request' error.""" 

620 pass 

621 

622 

623class TooManyRequestsError(Error): 

624 """Generic 'too many requests' error.""" 

625 

626 retryAfter: int = 0 

627 """Time in seconds after which the request can be repeated.""" 

628 

629 

630class ResponseTooLargeError(Error): 

631 """Generic error when a response is too large.""" 

632 pass 

633 

634 

635class ExternalServiceError(Error): 

636 """Generic error when an external service fails.""" 

637 pass 

638 

639 

640LockBusyError = u.LockBusyError 

641"""Raised when a server lock cannot be acquired within the timeout.""" 

642################################################################################ 

643 

644 

645 

646################################################################################ 

647# /spec/types.pyinc 

648 

649 

650class ApplicationManifestPlugin(Data): 

651 """Custom plugin entry in the application manifest.""" 

652 

653 path: DirPath 

654 """Path to the plugin directory; relative paths are resolved against the manifest location.""" 

655 

656 name: str = '' 

657 """Plugin name. When omitted, the directory name is used.""" 

658 

659 

660class ApplicationManifest(Data): 

661 """Application manifest, read from a ``MANIFEST.json`` file. 

662 

663 The manifest is JSON; lines starting with ``//`` or ``#`` are ignored. 

664 """ 

665 

666 uid: Optional[str] 

667 """Application identifier.""" 

668 release: Optional[str] 

669 """Application release version.""" 

670 excludePlugins: Optional[list[str]] 

671 """Names of the core plugins that should be deactivated.""" 

672 plugins: Optional[list[ApplicationManifestPlugin]] 

673 """Custom plugins.""" 

674 locales: list[str] 

675 """Locale names supported by this application.""" 

676 tsConfig: str 

677 """Path to ``tsconfig.json``.""" 

678 withFallbackConfig: bool = False 

679 """Use a minimal fallback configuration.""" 

680 withStrictConfig: bool = False 

681 """Stop the application upon a configuration error.""" 

682 

683 

684class ExtObjectDescriptor(Data): 

685 """Extension object descriptor.""" 

686 

687 extName: str 

688 """Full extension name like ``gws.ext.object.layer.wms``.""" 

689 extType: str 

690 """Extension type like ``wms``.""" 

691 classPtr: type 

692 """Class object.""" 

693 ident: str 

694 """Identifier.""" 

695 modName: str 

696 """Name of the module that contains the class.""" 

697 modPath: str 

698 """Path to the module that contains the class.""" 

699 

700 

701class ExtCommandDescriptor(Data): 

702 """Command descriptor, describes the action method that handles a command.""" 

703 

704 extName: str 

705 """Full command name like ``gws.ext.command.api.mapGetBox``.""" 

706 extType: str 

707 """Command name like ``mapGetBox``.""" 

708 extCommandCategory: 'CommandCategory' 

709 """Command category.""" 

710 methodName: str 

711 """Name of the action method that handles the command.""" 

712 methodPtr: Callable 

713 """Command method. Not set by ``SpecRuntime.command_descriptor``.""" 

714 request: 'Request' 

715 """Request sent to the command. Not set by ``SpecRuntime.command_descriptor``.""" 

716 tArg: str 

717 """Type uid of the command argument (the request).""" 

718 tOwner: str 

719 """Type uid of the action class that owns the command.""" 

720 owner: ExtObjectDescriptor 

721 """Object descriptor of the action class that owns the command.""" 

722 

723 

724class SpecReadOption(Enum): 

725 """Options for reading values with ``SpecRuntime.read``.""" 

726 

727 acceptExtraProps = 'acceptExtraProps' 

728 """Accept extra object properties.""" 

729 allowMissing = 'allowMissing' 

730 """Allow otherwise required properties to be missing.""" 

731 caseInsensitive = 'caseInsensitive' 

732 """Case insensitive search for properties.""" 

733 convertValues = 'convertValues' 

734 """Try to convert values to specified types.""" 

735 ignoreExtraProps = 'ignoreExtraProps' 

736 """Silently ignore extra object properties.""" 

737 verboseErrors = 'verboseErrors' 

738 """Add the value and the location of an error to ``ReadError`` exceptions.""" 

739 

740 

741class CommandCategory(Enum): 

742 """Command category.""" 

743 

744 api = 'api' 

745 """API command.""" 

746 cli = 'cli' 

747 """CLI command.""" 

748 get = 'get' 

749 """Web GET command.""" 

750 post = 'post' 

751 """Web POST command.""" 

752 raw = 'raw' 

753 """Raw Web command without preprocessing.""" 

754 

755 

756class SpecRuntime: 

757 """Spec runtime. 

758 

759 Provides access to the generated specs: reading and validating values, 

760 looking up extension objects and commands, and loading classes. 

761 """ 

762 

763 version: str 

764 """Application version.""" 

765 manifest: ApplicationManifest 

766 """Application manifest.""" 

767 appBundlePaths: list[str] 

768 """Paths of the client bundles of all chunks.""" 

769 

770 def read(self, value, type_name: str, path: str = '', options: set[SpecReadOption] = None): 

771 """Read and validate a raw value according to a spec type. 

772 

773 Args: 

774 value: Raw value from a config or a request. 

775 type_name: Type uid or extension name. 

776 path: Path of the config file, used to resolve relative paths and in error messages. 

777 options: Read options. 

778 

779 Returns: 

780 The parsed value. Objects are returned as ``gws.Data``. 

781 

782 Raises: 

783 ``gws.spec.core.ReadError``: If the value does not match the type. 

784 """ 

785 

786 def object_descriptor(self, type_name: str) -> Optional[ExtObjectDescriptor]: 

787 """Get an object descriptor. 

788 

789 Args: 

790 type_name: Type uid or extension name. 

791 

792 Returns: 

793 A descriptor or ``None`` if the type is not found. 

794 """ 

795 

796 def command_descriptor(self, command_category: CommandCategory, command_name: str) -> Optional[ExtCommandDescriptor]: 

797 """Get a command descriptor. 

798 

799 Args: 

800 command_category: Command category. 

801 command_name: Command name. 

802 

803 Returns: 

804 A descriptor or ``None`` if the command is not found. 

805 """ 

806 

807 def register_object(self, ext_name: ClassRef, obj_type: str, cls: type): 

808 """Register an extension class at run time. 

809 

810 The class gets the ``extName`` and ``extType`` attributes. 

811 

812 Args: 

813 ext_name: Extension category, like ``gws.ext.object.layer``. 

814 obj_type: Extension type, like ``wms``. 

815 cls: Class to register. 

816 

817 Raises: 

818 ``gws.spec.core.Error``: If the class reference is invalid. 

819 """ 

820 

821 def get_class(self, classref: ClassRef, ext_type: Optional[str] = None) -> Optional[type]: 

822 """Get a class object for a class reference. 

823 

824 The module defining the class is imported on demand. 

825 

826 Args: 

827 classref: Class reference: a class, a class name or an extension name. 

828 ext_type: Extension type, used when ``classref`` is an extension category name. 

829 Defaults to ``default``. 

830 

831 Returns: 

832 A class or ``None`` if the reference is not found. 

833 

834 Raises: 

835 ``gws.spec.core.LoadError``: If the module cannot be imported. 

836 """ 

837 

838 def parse_classref(self, classref: ClassRef) -> tuple[Optional[type], str, str]: 

839 """Parse a class reference. 

840 

841 Args: 

842 classref: Class reference. 

843 

844 Returns: 

845 A tuple ``(class object, class name, extension name)``, where only one element is set. 

846 

847 Raises: 

848 ``gws.spec.core.Error``: If the class reference is invalid. 

849 """ 

850 

851 def get_config_types(self, lang: str) -> list[dict]: 

852 """Get the configuration types as dictionaries. 

853 

854 Docstrings, titles and enum docs are taken from the strings in the given language. 

855 

856 Args: 

857 lang: Language code. 

858 

859 Returns: 

860 A list of type dictionaries. 

861 """ 

862################################################################################ 

863 

864 

865 

866################################################################################ 

867# /core/_tree.pyinc 

868 

869 

870class Object: 

871 """Basic GWS object. 

872 

873 An object has permissions and can provide properties for the client. 

874 """ 

875 

876 permissions: dict[Access, Acl] 

877 """Mapping from an access mode to a list of ACL tuples.""" 

878 

879 def props(self, user: 'User') -> Props: 

880 """Generate a ``Props`` struct for this object. 

881 

882 Do not call this method directly, use ``gws.props_of`` instead, which also checks permissions. 

883 

884 Args: 

885 user: The user for which the props should be generated. 

886 

887 Returns: 

888 A ``Props`` object or a dict. Nested objects are converted to props as well. 

889 """ 

890 

891 def __init__(self): 

892 self.permissions = {} 

893 

894 

895from .core import tree_impl 

896 

897setattr(tree_impl, 'Access', Access) 

898setattr(tree_impl, 'Error', Error) 

899setattr(tree_impl, 'Data', Data) 

900setattr(tree_impl, 'Props', Props) 

901setattr(tree_impl, 'Object', Object) 

902 

903Object.__repr__ = tree_impl.object_repr 

904 

905 

906class Node(Object): 

907 """GWS object tree node. 

908 

909 Nodes are created by the ``Root`` or by their parent node. Configuration hooks 

910 (``pre_configure``, ``configure``, ``post_configure``) are invoked for every class in the MRO 

911 that defines them, base classes first, so they do not need to call ``super()``. 

912 """ 

913 

914 extName: str 

915 """Full extension name like ``gws.ext.object.layer.wms``.""" 

916 extType: str 

917 """Extension type like ``wms``.""" 

918 

919 config: Config 

920 """Configuration for this object.""" 

921 root: 'Root' 

922 """Root object.""" 

923 parent: 'Node' 

924 """Parent object.""" 

925 children: list['Node'] 

926 """Child objects.""" 

927 uid: str 

928 """Unique ID.""" 

929 

930 def initialize(self, config): 

931 """Initialize the node. 

932 

933 Store the configuration, set up the permissions, then run ``pre_configure`` and ``configure``. 

934 

935 Args: 

936 config: Configuration. 

937 """ 

938 return tree_impl.node_initialize(self, config) 

939 

940 def pre_configure(self): 

941 """Pre-configuration hook. 

942 

943 Called before ``configure``, when the node is initialized. 

944 """ 

945 

946 def configure(self): 

947 """Configuration hook. 

948 

949 Called when the node is initialized. Raising an exception here aborts the creation of the node. 

950 """ 

951 

952 def post_configure(self): 

953 """Post-configuration hook. 

954 

955 Called after the whole object tree has been created. 

956 """ 

957 

958 def activate(self): 

959 """Activation hook. 

960 

961 Called by ``Root.activate`` after the configuration has been loaded. 

962 """ 

963 

964 def create_child(self, classref: ClassRef, config: Config = None, **kwargs) -> Optional['Node']: 

965 """Create a child object. 

966 

967 Args: 

968 classref: Class reference. 

969 config: Configuration. 

970 **kwargs: Additional configuration properties. 

971 

972 Returns: 

973 A newly created object or ``None`` if the object cannot be initialized. 

974 """ 

975 return tree_impl.node_create_child(self, classref, config, **kwargs) 

976 

977 def create_child_if_configured(self, classref: ClassRef, config=None, **kwargs) -> Optional['Node']: 

978 """Create a child object if the configuration is not None. 

979 

980 Args: 

981 classref: Class reference. 

982 config: Configuration. 

983 **kwargs: Additional configuration properties. 

984 

985 Returns: 

986 A newly created object or ``None`` if the configuration is ``None`` or the object cannot be initialized. 

987 """ 

988 return tree_impl.node_create_child_if_configured(self, classref, config, **kwargs) 

989 

990 def create_children(self, classref: ClassRef, configs: list[Config], **kwargs) -> list['Node']: 

991 """Create a list of child objects from a list of configurations. 

992 

993 Args: 

994 classref: Class reference. 

995 configs: List of configurations. 

996 **kwargs: Additional configuration properties. 

997 

998 Returns: 

999 A list of newly created objects. 

1000 """ 

1001 return tree_impl.node_create_children(self, classref, configs, **kwargs) 

1002 

1003 def cfg(self, key: str, default=None): 

1004 """Fetch a configuration property. 

1005 

1006 Args: 

1007 key: Property key. If it contains dots, fetch nested properties. 

1008 default: Default to return if the property is not found. 

1009 

1010 Returns: 

1011 A property value. 

1012 """ 

1013 return tree_impl.node_cfg(self, key, default) 

1014 

1015 def is_a(self, classref: ClassRef) -> bool: 

1016 """Check if the node matches the class reference. 

1017 

1018 Args: 

1019 classref: Class reference. 

1020 

1021 Returns: 

1022 ``True`` if the node matches. 

1023 """ 

1024 return tree_impl.is_a(self.root, self, classref) 

1025 

1026 def find_all(self, classref: Optional[ClassRef] = None) -> list['Node']: 

1027 """Find all direct children that match a specific class. 

1028 

1029 Args: 

1030 classref: Class reference. If omitted, all children are returned. 

1031 

1032 Returns: 

1033 A list of objects. 

1034 """ 

1035 return tree_impl.node_find_all(self, classref) 

1036 

1037 def find_first(self, classref: Optional[ClassRef] = None) -> Optional['Node']: 

1038 """Find the first direct child that matches a specific class. 

1039 

1040 Args: 

1041 classref: Class reference. If omitted, the first child is returned. 

1042 

1043 Returns: 

1044 An object or ``None``. 

1045 """ 

1046 return tree_impl.node_find_first(self, classref) 

1047 

1048 def find_closest(self, classref: Optional[ClassRef] = None) -> Optional['Node']: 

1049 """Find the closest node ancestor that matches a specific class. 

1050 

1051 Args: 

1052 classref: Class reference. If omitted, the parent is returned. 

1053 

1054 Returns: 

1055 An object or ``None``. 

1056 """ 

1057 

1058 return tree_impl.node_find_closest(self, classref) 

1059 

1060 def find_ancestors(self, classref: Optional[ClassRef] = None) -> list['Node']: 

1061 """Find node ancestors that match a specific class. 

1062 

1063 Args: 

1064 classref: Class reference. If omitted, all ancestors are returned. 

1065 

1066 Returns: 

1067 A list of objects, from the parent upwards. 

1068 """ 

1069 return tree_impl.node_find_ancestors(self, classref) 

1070 

1071 def find_descendants(self, classref: Optional[ClassRef] = None) -> list['Node']: 

1072 """Find node descendants that match a specific class. 

1073 

1074 Args: 

1075 classref: Class reference. If omitted, all descendants are returned. 

1076 

1077 Returns: 

1078 A list of objects in the depth-first order. 

1079 """ 

1080 

1081 return tree_impl.node_find_descendants(self, classref) 

1082 

1083 def enter_middleware(self, req: 'WebRequester') -> Optional['WebResponder']: 

1084 """Begin middleware processing. 

1085 

1086 Args: 

1087 req: Requester object. 

1088 

1089 Returns: 

1090 A Responder object to end the request processing, or ``None`` to continue. 

1091 """ 

1092 

1093 def exit_middleware(self, req: 'WebRequester', res: 'WebResponder'): 

1094 """Finish middleware processing. 

1095 

1096 Args: 

1097 req: Requester object. 

1098 res: Current responder object. 

1099 """ 

1100 

1101 def periodic_task(self): 

1102 """Periodic task hook. 

1103 

1104 Called by the server monitor for nodes registered with ``register_periodic_task``. 

1105 """ 

1106 

1107 

1108class Root: 

1109 """Root node of the object tree.""" 

1110 

1111 app: 'Application' 

1112 """Application object.""" 

1113 specs: 'SpecRuntime' 

1114 """Specs runtime.""" 

1115 configErrors: list 

1116 """List of configuration errors.""" 

1117 configWarnings: list 

1118 """List of configuration warnings.""" 

1119 

1120 nodes: list['Node'] 

1121 """All nodes in the tree, in the order of creation.""" 

1122 uidMap: dict[str, 'Node'] 

1123 """Mapping from uids to nodes.""" 

1124 uidCount: int 

1125 """Counter for generated uids.""" 

1126 configStack: list['Node'] 

1127 """Nodes being configured, from the outermost to the current one.""" 

1128 configPaths: list[str] 

1129 """Paths of the configuration files.""" 

1130 

1131 def __init__(self, specs: 'SpecRuntime'): 

1132 """Create an empty root. 

1133 

1134 Args: 

1135 specs: Specs runtime. 

1136 """ 

1137 tree_impl.root_init(self, specs) 

1138 

1139 def initialize(self, obj, config): 

1140 """Initialize a node and record configuration errors. 

1141 

1142 Args: 

1143 obj: The node. 

1144 config: Configuration. 

1145 

1146 Returns: 

1147 ``True`` if the node was initialized, ``False`` if it failed. 

1148 """ 

1149 return tree_impl.root_initialize(self, obj, config) 

1150 

1151 def post_initialize(self): 

1152 """Run ``post_configure`` on all nodes, in the reverse order of creation. 

1153 

1154 Errors are logged and recorded in ``configErrors``. 

1155 """ 

1156 return tree_impl.root_post_initialize(self) 

1157 

1158 def activate(self): 

1159 """Run ``activate`` on all nodes.""" 

1160 return tree_impl.root_activate(self) 

1161 

1162 def config_warning(self, message: str): 

1163 """Register a configuration warning. 

1164 

1165 The warning is logged immediately and reported again after the configuration is complete. 

1166 The object stack is only available when called from ``configure`` or ``post_configure``. 

1167 

1168 Args: 

1169 message: Warning message. 

1170 """ 

1171 return tree_impl.root_config_warning(self, message) 

1172 

1173 def find_all(self, classref: Optional[ClassRef] = None) -> list['Node']: 

1174 """Find all objects that match a specific class. 

1175 

1176 Args: 

1177 classref: Class reference. 

1178 

1179 Returns: 

1180 A list of objects. 

1181 """ 

1182 return tree_impl.root_find_all(self, classref) 

1183 

1184 def find_first(self, classref: Optional[ClassRef] = None) -> Optional['Node']: 

1185 """Find the first object that matches a specific class. 

1186 

1187 Args: 

1188 classref: Class reference. 

1189 

1190 Returns: 

1191 An object or ``None``. 

1192 """ 

1193 return tree_impl.root_find_first(self, classref) 

1194 

1195 def get(self, uid: str = None, classref: Optional[ClassRef] = None) -> Optional['Node']: 

1196 """Get an object by its unique ID. 

1197 

1198 Args: 

1199 uid: Object uid. 

1200 classref: Class reference. If provided, ensures that the object matches the reference. 

1201 

1202 Returns: 

1203 An object or ``None``. 

1204 """ 

1205 return tree_impl.root_get(self, uid, classref) 

1206 

1207 def object_count(self) -> int: 

1208 """Return the number of objects in the tree. 

1209 

1210 Returns: 

1211 The number of objects. 

1212 """ 

1213 return tree_impl.root_object_count(self) 

1214 

1215 def create( 

1216 self, 

1217 classref: ClassRef, 

1218 parent: Optional['Node'] = None, 

1219 config: Config = None, 

1220 **kwargs, 

1221 ) -> Optional['Node']: 

1222 """Create an object. 

1223 

1224 Args: 

1225 classref: Class reference. 

1226 parent: Parent object. 

1227 config: Configuration. 

1228 **kwargs: Additional configuration properties. 

1229 

1230 Returns: 

1231 A newly created object or ``None`` if the object cannot be initialized. 

1232 """ 

1233 return tree_impl.root_create(self, classref, parent, config, **kwargs) 

1234 

1235 def create_shared(self, classref: ClassRef, config: Config = None, **kwargs) -> Optional['Node']: 

1236 """Create a shared object, attached directly to the root. 

1237 

1238 If the config has no uid, it is computed from the class reference and the configuration. 

1239 If an object with this uid already exists, it is returned instead of creating a new one. 

1240 

1241 Args: 

1242 classref: Class reference. 

1243 config: Configuration. 

1244 **kwargs: Additional configuration properties. 

1245 

1246 Returns: 

1247 A newly created object or ``None`` if the object cannot be initialized. 

1248 """ 

1249 return tree_impl.root_create_shared(self, classref, config, **kwargs) 

1250 

1251 def create_temporary(self, classref: ClassRef, config: Config = None, **kwargs) -> Optional['Node']: 

1252 """Create a temporary object, not attached to the tree. 

1253 

1254 Args: 

1255 classref: Class reference. 

1256 config: Configuration. 

1257 **kwargs: Additional configuration properties. 

1258 

1259 Returns: 

1260 A newly created object or ``None`` if the object cannot be initialized. 

1261 """ 

1262 return tree_impl.root_create_temporary(self, classref, config, **kwargs) 

1263 

1264 def create_application(self, config: Config = None, **kwargs) -> 'Application': 

1265 """Create the Application object. 

1266 

1267 Args: 

1268 config: Configuration. 

1269 **kwargs: Additional configuration properties. 

1270 

1271 Returns: 

1272 The Application object. 

1273 """ 

1274 return tree_impl.root_create_application(self, config, **kwargs) 

1275 

1276 

1277def create_root(specs: 'SpecRuntime') -> Root: 

1278 """Create a new root object. 

1279 

1280 Args: 

1281 specs: Specs runtime. 

1282 

1283 Returns: 

1284 The root object. 

1285 """ 

1286 return Root(specs) 

1287 

1288 

1289def save_root(root: Root, path: str = None) -> str: 

1290 """Pickle the root object to a file. 

1291 

1292 ``sys.path`` is pickled next to it, to ``<path>.syspath``, so that ``load_root`` can restore it. 

1293 

1294 Args: 

1295 root: The root object. 

1296 path: File path. Defaults to ``config.pickle`` in the config directory. 

1297 

1298 Returns: 

1299 The file path. 

1300 """ 

1301 return tree_impl.save_root(root, path) 

1302 

1303 

1304def load_root(path: str = None) -> Root: 

1305 """Load a pickled root object, activate it and make it the current root. 

1306 

1307 ``sys.path`` is restored first, so that plugin modules can be imported. 

1308 

1309 Args: 

1310 path: File path. Defaults to ``config.pickle`` in the config directory. 

1311 

1312 Returns: 

1313 The root object. 

1314 """ 

1315 return tree_impl.load_root(path) 

1316 

1317 

1318def activate_root(root: Root) -> Root: 

1319 """Activate the root object and make it the current root. 

1320 

1321 Args: 

1322 root: The root object. 

1323 

1324 Returns: 

1325 The root object. 

1326 """ 

1327 return tree_impl.activate_root(root) 

1328 

1329 

1330def deactivate_root(): 

1331 """Remove the current root.""" 

1332 return tree_impl.deactivate_root() 

1333 

1334 

1335def get_root() -> Root: 

1336 """Return the current root object. 

1337 

1338 Returns: 

1339 The root object set by ``activate_root`` or ``load_root``. 

1340 

1341 Raises: 

1342 Error: If there is no current root. 

1343 """ 

1344 return tree_impl.get_root() 

1345 

1346 

1347def props_of(obj: Object, user: 'User', *context) -> Optional['Props']: 

1348 """Generate props for an object, if the user is allowed to use it. 

1349 

1350 Nested objects the user cannot read are removed from the result. 

1351 

1352 Args: 

1353 obj: The object. 

1354 user: The user. 

1355 *context: Context objects for the permission check. 

1356 

1357 Returns: 

1358 A ``Props`` object, or ``None`` if the user cannot use the object. 

1359 

1360 Raises: 

1361 Error: If the object's ``props`` returns an invalid type. 

1362 """ 

1363 return tree_impl.props_of(obj, user, *context) 

1364################################################################################ 

1365 

1366 

1367 

1368################################################################################ 

1369# /lib/mapserver/types.pyinc 

1370 

1371 

1372class MapServerLayerType(Enum): 

1373 """MapServer layer type.""" 

1374 

1375 point = 'point' 

1376 """Point layer.""" 

1377 line = 'line' 

1378 """Line layer.""" 

1379 polygon = 'polygon' 

1380 """Polygon layer.""" 

1381 raster = 'raster' 

1382 """Raster layer.""" 

1383 

1384class MapServerLayerOptions(Data): 

1385 """Options for a MapServer-based layer.""" 

1386 

1387 type: MapServerLayerType 

1388 """Layer type.""" 

1389 path: str 

1390 """Path to the data file, e.g. an image (layer DATA option).""" 

1391 tileIndex: str 

1392 """Path to the tile index SHP file.""" 

1393 crs: 'Crs' 

1394 """Layer CRS.""" 

1395 connectionType: str 

1396 """Type of connection, only ``postgres`` is supported.""" 

1397 connectionString: str 

1398 """Connection string for the data source.""" 

1399 dataString: str 

1400 """Layer DATA option, overrides ``path``.""" 

1401 style: 'StyleValues' 

1402 """Style for the layer; only a part of the style values is supported.""" 

1403 processing: list[str] 

1404 """Processing options for the layer.""" 

1405 transparentColor: str 

1406 """Color to treat as transparent in the layer (OFFSITE).""" 

1407 sldPath: str 

1408 """Path to SLD file for styling the layer.""" 

1409 sldName: str 

1410 """Name of an SLD NamedLayer to apply.""" 

1411################################################################################ 

1412 

1413 

1414################################################################################ 

1415# /lib/mime/types.pyinc 

1416 

1417 

1418MimeType: TypeAlias = str 

1419"""A MIME type or a file extension.""" 

1420################################################################################ 

1421 

1422 

1423################################################################################ 

1424# /lib/uom/types.pyinc 

1425 

1426 

1427class Uom(Enum): 

1428 """Unit of measure.""" 

1429 

1430 mi = 'mi' 

1431 """Statute mile (EPSG 9093).""" 

1432 us_ch = 'us-ch' 

1433 """US survey chain (EPSG 9033).""" 

1434 us_ft = 'us-ft' 

1435 """US survey foot (EPSG 9003).""" 

1436 us_in = 'us-in' 

1437 """US survey inch.""" 

1438 us_mi = 'us-mi' 

1439 """US survey mile (EPSG 9035).""" 

1440 us_yd = 'us-yd' 

1441 """US survey yard.""" 

1442 cm = 'cm' 

1443 """Centimetre (EPSG 1033).""" 

1444 ch = 'ch' 

1445 """Chain (EPSG 9097).""" 

1446 dm = 'dm' 

1447 """Decimetre.""" 

1448 deg = 'deg' 

1449 """Degree (EPSG 9102).""" 

1450 fath = 'fath' 

1451 """Fathom (EPSG 9014).""" 

1452 ft = 'ft' 

1453 """Foot (EPSG 9002).""" 

1454 grad = 'grad' 

1455 """Grad (EPSG 9105).""" 

1456 inch = 'in' 

1457 """Inch.""" 

1458 km = 'km' 

1459 """Kilometre (EPSG 9036).""" 

1460 link = 'link' 

1461 """Link (EPSG 9098).""" 

1462 m = 'm' 

1463 """Metre (EPSG 9001).""" 

1464 mm = 'mm' 

1465 """Millimetre (EPSG 1025).""" 

1466 kmi = 'kmi' 

1467 """Nautical mile (EPSG 9030).""" 

1468 rad = 'rad' 

1469 """Radian (EPSG 9101).""" 

1470 yd = 'yd' 

1471 """Yard (EPSG 9096).""" 

1472 px = 'px' 

1473 """Pixel.""" 

1474 pt = 'pt' 

1475 """Typographic point (1/72 inch).""" 

1476 

1477 

1478UomValue: TypeAlias = tuple[float, Uom] 

1479"""A value with a unit, like ``(5, Uom.mm)``.""" 

1480 

1481UomValueStr: TypeAlias = str 

1482"""A value with a unit like ``5mm``.""" 

1483 

1484UomPoint: TypeAlias = tuple[float, float, Uom] 

1485"""A point with a unit, like ``(1, 2, Uom.mm)``.""" 

1486 

1487UomPointStr: TypeAlias = list[str] 

1488"""A point with a unit like ``["1mm", "2mm"]``.""" 

1489 

1490UomSize: TypeAlias = tuple[float, float, Uom] 

1491"""A size with a unit, like ``(10, 20, Uom.mm)``.""" 

1492 

1493UomSizeStr: TypeAlias = list[str] 

1494"""A size with a unit like ``["1mm", "2mm"]``.""" 

1495 

1496UomExtent: TypeAlias = tuple[float, float, float, float, Uom] 

1497"""An extent with a unit, like ``(0, 0, 10, 20, Uom.mm)``.""" 

1498 

1499UomExtentStr: TypeAlias = list[str] 

1500"""An extent with a unit like ``["1mm", "2mm", "3mm", "4mm"]``.""" 

1501################################################################################ 

1502 

1503 

1504################################################################################ 

1505# /lib/image/types.pyinc 

1506 

1507 

1508class ImageFormat(Data): 

1509 """Image format: MIME types and encoding options.""" 

1510 

1511 name: str 

1512 """Name of the format.""" 

1513 mimeTypes: list[str] 

1514 """MIME types for this format.""" 

1515 options: dict 

1516 """Encoding options, as accepted by ``Image.to_bytes``.""" 

1517 

1518 

1519class Image: 

1520 """Raster image. 

1521 

1522 Manipulation methods change the image in place and return the image itself, so that calls can be chained. 

1523 """ 

1524 

1525 def size(self) -> Size: 

1526 """Get the image size. 

1527 

1528 Returns: 

1529 A tuple ``(width, height)`` in pixels. 

1530 """ 

1531 

1532 def mode(self) -> str: 

1533 """Get the image mode. 

1534 

1535 Returns: 

1536 PIL image mode, e.g. ``RGBA``. 

1537 """ 

1538 

1539 def convert(self, mode: str) -> 'Image': 

1540 """Convert the image to a mode. 

1541 

1542 Args: 

1543 mode: PIL image mode. 

1544 

1545 Returns: 

1546 The image. 

1547 """ 

1548 

1549 def add_box(self, color=None) -> 'Image': 

1550 """Draw a 1 pixel wide frame along the image edges. 

1551 

1552 The image is converted to RGBA. 

1553 

1554 Args: 

1555 color: Line color, black by default. 

1556 

1557 Returns: 

1558 The image. 

1559 """ 

1560 

1561 def add_text(self, text: str, x=0, y=0, color=None) -> 'Image': 

1562 """Draw text on the image with the default font. 

1563 

1564 The image is converted to RGBA. 

1565 

1566 Args: 

1567 text: Text, can contain multiple lines. 

1568 x: X coordinate of the top left corner of the text. 

1569 y: Y coordinate of the top left corner of the text. 

1570 color: Text color, black by default. 

1571 

1572 Returns: 

1573 The image. 

1574 """ 

1575 

1576 def compose(self, other: 'Image', opacity=1) -> 'Image': 

1577 """Place another image on top of this one, using alpha composition. 

1578 

1579 The other image is resized to the size of this one if needed. 

1580 

1581 Args: 

1582 other: Image to place on top. 

1583 opacity: Opacity of the other image, from 0 to 1. 

1584 

1585 Returns: 

1586 The image. 

1587 """ 

1588 

1589 def crop(self, box) -> 'Image': 

1590 """Crop the image. 

1591 

1592 Args: 

1593 box: Crop rectangle ``(left, upper, right, lower)`` in pixels. 

1594 

1595 Returns: 

1596 The image. 

1597 """ 

1598 

1599 def paste(self, other: 'Image', where=None) -> 'Image': 

1600 """Paste another image into this one. 

1601 

1602 Args: 

1603 other: Image to paste. 

1604 where: Position ``(x, y)`` of the upper left corner, or a box ``(left, upper, right, lower)``. 

1605 By default, the image is pasted at ``(0, 0)``. 

1606 

1607 Returns: 

1608 The image. 

1609 """ 

1610 

1611 def resize(self, size: Size, **kwargs) -> 'Image': 

1612 """Resize the image to a size, without keeping the aspect ratio. 

1613 

1614 Args: 

1615 size: New size ``(width, height)``. 

1616 **kwargs: Options for ``PIL.Image.resize``. The default resampling is bicubic. 

1617 

1618 Returns: 

1619 The image. 

1620 """ 

1621 

1622 def resize_to(self, width: int = 0, height: int = 0, **kwargs) -> 'Image': 

1623 """Resize the image to a width, a height or both. 

1624 

1625 If only one dimension is given, the other is computed to keep the aspect ratio. 

1626 If none is given, the image is not changed. 

1627 

1628 Args: 

1629 width: New width. 

1630 height: New height. 

1631 **kwargs: Options for ``PIL.Image.resize``. 

1632 

1633 Returns: 

1634 The image. 

1635 """ 

1636 

1637 def rotate(self, angle: int, **kwargs) -> 'Image': 

1638 """Rotate the image counter-clockwise. 

1639 

1640 Args: 

1641 angle: Angle in degrees. 

1642 **kwargs: Options for ``PIL.Image.rotate``. The default resampling is bicubic. 

1643 

1644 Returns: 

1645 The image. 

1646 """ 

1647 

1648 def to_bytes(self, mime: MimeType = '', options: Optional[dict] = None) -> bytes: 

1649 """Encode the image. 

1650 

1651 The ``options`` dict can contain any PIL save option 

1652 (see https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html). 

1653 

1654 An additional option ``mode`` is the image mode 

1655 (see https://pillow.readthedocs.io/en/stable/handbook/concepts.html#concept-modes). 

1656 If provided, the image is converted to that mode before saving, with an adaptive palette. 

1657 

1658 An additional option ``background`` sets the color to replace the alpha channel with 

1659 when an RGBA image is saved as JPEG (default is white). 

1660 

1661 Args: 

1662 mime: MIME type of the output, PNG by default. 

1663 options: Encoding options. 

1664 

1665 Returns: 

1666 The encoded image. 

1667 """ 

1668 

1669 def to_base64(self, mime: MimeType = '', options: Optional[dict] = None) -> str: 

1670 """Encode the image as a base64 string. 

1671 

1672 Args: 

1673 mime: MIME type of the output, PNG by default. 

1674 options: Encoding options, as in ``to_bytes``. 

1675 

1676 Returns: 

1677 The base64 encoded image. 

1678 """ 

1679 

1680 def to_data_url(self, mime: MimeType = '', options: Optional[dict] = None) -> str: 

1681 """Encode the image as a base64 data URL. 

1682 

1683 Args: 

1684 mime: MIME type of the output, PNG by default. 

1685 options: Encoding options, as in ``to_bytes``. 

1686 

1687 Returns: 

1688 A ``data:`` URL. 

1689 """ 

1690 

1691 def to_path(self, path: str, mime: MimeType = '', options: Optional[dict] = None) -> str: 

1692 """Encode the image and save it to a file. 

1693 

1694 Args: 

1695 path: File path. 

1696 mime: MIME type of the output, PNG by default. 

1697 options: Encoding options, as in ``to_bytes``. 

1698 

1699 Returns: 

1700 The file path. 

1701 """ 

1702 

1703 def to_array(self) -> 'numpy.typing.NDArray': 

1704 """Convert the image to a numpy array. 

1705 

1706 Returns: 

1707 An array of shape ``(height, width)`` or ``(height, width, channels)``. 

1708 """ 

1709 

1710 def compare_to(self, other: 'Image') -> float: 

1711 """Compare this image to another one. 

1712 

1713 Computes the mean squared difference of the RGBA channels over all pixels, 

1714 normalized to the range 0 to 1. Both images must be RGBA and have the same size. 

1715 

1716 Args: 

1717 other: Image to compare to. 

1718 

1719 Returns: 

1720 ``0`` if the images are equal, larger values for larger differences. 

1721 """ 

1722################################################################################ 

1723 

1724 

1725################################################################################ 

1726# /lib/intl/types.pyinc 

1727 

1728 

1729LocaleUid: TypeAlias = str 

1730"""Locale UID like ``de_DE``.""" 

1731 

1732 

1733class Locale(Data): 

1734 """Locale data: language, territory, date and number conventions.""" 

1735 

1736 uid: str 

1737 """Locale uid like ``de_DE``. A locale without a territory has the territory ``ZZ``.""" 

1738 dateFormatLong: str 

1739 """Long date format pattern.""" 

1740 dateFormatMedium: str 

1741 """Medium date format pattern.""" 

1742 dateFormatShort: str 

1743 """Short date format pattern.""" 

1744 dayNamesLong: list[str] 

1745 """Full day names.""" 

1746 dayNamesShort: list[str] 

1747 """Abbreviated day names.""" 

1748 dayNamesNarrow: list[str] 

1749 """Narrow day names.""" 

1750 firstWeekDay: int 

1751 """First day of the week, ``0`` is Monday.""" 

1752 

1753 language: str 

1754 """Language code: ``de``.""" 

1755 language3: str 

1756 """ISO 639 alpha-3 language code: ``deu``.""" 

1757 languageBib: str 

1758 """ISO 639-2 bibliographic language code: ``ger``.""" 

1759 languageName: str 

1760 """Native language name: ``Deutsch``.""" 

1761 languageNameEn: str 

1762 """English language name: ``German``.""" 

1763 

1764 territory: str 

1765 """Territory code: ``DE``.""" 

1766 territoryName: str 

1767 """Native territory name: ``Deutschland``.""" 

1768 monthNamesLong: list[str] 

1769 """Full month names.""" 

1770 monthNamesShort: list[str] 

1771 """Abbreviated month names.""" 

1772 monthNamesNarrow: list[str] 

1773 """Narrow month names.""" 

1774 numberDecimal: str 

1775 """Decimal separator.""" 

1776 numberGroup: str 

1777 """Group (thousands) separator.""" 

1778 

1779 

1780class DateTimeFormat(Enum): 

1781 """Date or time format.""" 

1782 short = 'short' 

1783 """Local short format.""" 

1784 medium = 'medium' 

1785 """Local medium format.""" 

1786 long = 'long' 

1787 """Local long format.""" 

1788 iso = 'iso' 

1789 """ISO 8601 format.""" 

1790 

1791 

1792class NumberFormat(Enum): 

1793 """Number format.""" 

1794 decimal = 'decimal' 

1795 """Locale decimal format.""" 

1796 grouped = 'grouped' 

1797 """Locale grouped format.""" 

1798 currency = 'currency' 

1799 """Locale currency format.""" 

1800 percent = 'percent' 

1801 """Locale percent format.""" 

1802 

1803 

1804class DateFormatter: 

1805 """Locale-aware date formatter.""" 

1806 

1807 def format(self, fmt: DateTimeFormat | str, date: Optional[Union['datetime.date', str]] = None) -> str: 

1808 """Format a date. 

1809 

1810 Args: 

1811 fmt: Format type, or a ``babel`` (CLDR) date pattern like ``dd.MM.yyyy``. 

1812 date: Date or date string, the current date by default. 

1813 

1814 Returns: 

1815 The formatted date. 

1816 

1817 Raises: 

1818 ``Error``: If the date cannot be parsed. 

1819 """ 

1820 

1821 def short(self, date=None) -> str: 

1822 """Format a date in the short format of the locale, e.g. ``11.12.13``. 

1823 

1824 Args: 

1825 date: Date or date string, the current date by default. 

1826 

1827 Returns: 

1828 The formatted date. 

1829 """ 

1830 

1831 def medium(self, date=None) -> str: 

1832 """Format a date in the medium format of the locale, e.g. ``11.12.2013``. 

1833 

1834 Args: 

1835 date: Date or date string, the current date by default. 

1836 

1837 Returns: 

1838 The formatted date. 

1839 """ 

1840 

1841 def long(self, date=None) -> str: 

1842 """Format a date in the long format of the locale, e.g. ``11. Dezember 2013``. 

1843 

1844 Args: 

1845 date: Date or date string, the current date by default. 

1846 

1847 Returns: 

1848 The formatted date. 

1849 """ 

1850 

1851 def iso(self, date=None) -> str: 

1852 """Format a date in the ISO 8601 format, e.g. ``2013-12-11``. 

1853 

1854 Args: 

1855 date: Date or date string, the current date by default. 

1856 

1857 Returns: 

1858 The formatted date. 

1859 """ 

1860 

1861 

1862class TimeFormatter: 

1863 """Locale-aware time formatter.""" 

1864 

1865 def format(self, fmt: DateTimeFormat | str, time: Optional[Union['datetime.time', str]] = None) -> str: 

1866 """Format a time. 

1867 

1868 Args: 

1869 fmt: Format type, or a ``babel`` (CLDR) time pattern like ``HH:mm``. 

1870 time: Time, datetime or time string, the current time by default. 

1871 

1872 Returns: 

1873 The formatted time. 

1874 

1875 Raises: 

1876 ``Error``: If the time cannot be parsed. 

1877 """ 

1878 

1879 def short(self, time=None) -> str: 

1880 """Format a time in the short format of the locale, e.g. ``11:22``. 

1881 

1882 Args: 

1883 time: Time, datetime or time string, the current time by default. 

1884 

1885 Returns: 

1886 The formatted time. 

1887 """ 

1888 

1889 def medium(self, time=None) -> str: 

1890 """Format a time in the medium format of the locale, e.g. ``11:22:33``. 

1891 

1892 Args: 

1893 time: Time, datetime or time string, the current time by default. 

1894 

1895 Returns: 

1896 The formatted time. 

1897 """ 

1898 

1899 def long(self, time=None) -> str: 

1900 """Format a time in the long format of the locale, which usually includes the time zone. 

1901 

1902 Args: 

1903 time: Time, datetime or time string, the current time by default. 

1904 

1905 Returns: 

1906 The formatted time. 

1907 """ 

1908 

1909 def iso(self, time=None) -> str: 

1910 """Format a time in the ISO 8601 format, with the time zone offset, e.g. ``11:22:33+0100``. 

1911 

1912 Args: 

1913 time: Time, datetime or time string, the current time by default. 

1914 

1915 Returns: 

1916 The formatted time. 

1917 """ 

1918 

1919 

1920class NumberFormatter: 

1921 """Locale-aware number formatter.""" 

1922 

1923 def format(self, fmt: NumberFormat | str, n, *args, **kwargs) -> str: 

1924 """Format a number. 

1925 

1926 Args: 

1927 fmt: Format type. For an unknown format, the number is converted with ``str``. 

1928 n: Number. 

1929 *args: Arguments for the format method, e.g. the currency for ``currency``. 

1930 **kwargs: Keyword arguments for the format method. 

1931 

1932 Returns: 

1933 The formatted number. 

1934 """ 

1935 

1936 def decimal(self, n, *args, **kwargs) -> str: 

1937 """Format a number as a decimal without group separators. 

1938 

1939 Args: 

1940 n: Number. 

1941 *args: Arguments for ``babel.numbers.format_decimal``. 

1942 **kwargs: Keyword arguments for ``babel.numbers.format_decimal``. 

1943 

1944 Returns: 

1945 The formatted number. 

1946 """ 

1947 

1948 def grouped(self, n, *args, **kwargs) -> str: 

1949 """Format a number as a decimal with group separators. 

1950 

1951 Args: 

1952 n: Number. 

1953 *args: Arguments for ``babel.numbers.format_decimal``. 

1954 **kwargs: Keyword arguments for ``babel.numbers.format_decimal``. 

1955 

1956 Returns: 

1957 The formatted number. 

1958 """ 

1959 

1960 def currency(self, n, currency: str, *args, **kwargs) -> str: 

1961 """Format a number as a currency value. 

1962 

1963 Args: 

1964 n: Number. 

1965 currency: Currency code like ``EUR``. 

1966 *args: Arguments for ``babel.numbers.format_currency``. 

1967 **kwargs: Keyword arguments for ``babel.numbers.format_currency``. 

1968 

1969 Returns: 

1970 The formatted value. 

1971 """ 

1972 

1973 def percent(self, n, *args, **kwargs) -> str: 

1974 """Format a number as a percentage, ``0.5`` is 50 percent. 

1975 

1976 Args: 

1977 n: Number. 

1978 *args: Arguments for ``babel.numbers.format_percent``. 

1979 **kwargs: Keyword arguments for ``babel.numbers.format_percent``. 

1980 

1981 Returns: 

1982 The formatted value. 

1983 """ 

1984################################################################################ 

1985 

1986 

1987################################################################################ 

1988# /lib/style/types.pyinc 

1989 

1990 

1991class StyleValues(Data): 

1992 """Style values, as parsed by ``gws.lib.style.parser``.""" 

1993 

1994 fill: Color 

1995 """Fill color.""" 

1996 

1997 stroke: Color 

1998 """Stroke (line) color.""" 

1999 stroke_dasharray: list[int] 

2000 """Dash pattern, as a list of dash and gap lengths.""" 

2001 stroke_dashoffset: int 

2002 """Offset of the dash pattern.""" 

2003 stroke_linecap: Literal['butt', 'round', 'square'] 

2004 """Shape of line ends.""" 

2005 stroke_linejoin: Literal['bevel', 'round', 'miter'] 

2006 """Shape of line corners.""" 

2007 stroke_miterlimit: int 

2008 """Limit for miter joins.""" 

2009 stroke_width: int 

2010 """Stroke width in pixels.""" 

2011 

2012 marker: Literal['circle', 'square', 'arrow', 'cross'] 

2013 """Marker symbol drawn at the vertices of a geometry.""" 

2014 marker_fill: Color 

2015 """Marker fill color.""" 

2016 marker_size: int 

2017 """Marker size in pixels.""" 

2018 marker_stroke: Color 

2019 """Marker stroke color.""" 

2020 marker_stroke_dasharray: list[int] 

2021 """Marker dash pattern.""" 

2022 marker_stroke_dashoffset: int 

2023 """Offset of the marker dash pattern.""" 

2024 marker_stroke_linecap: Literal['butt', 'round', 'square'] 

2025 """Shape of marker line ends.""" 

2026 marker_stroke_linejoin: Literal['bevel', 'round', 'miter'] 

2027 """Shape of marker line corners.""" 

2028 marker_stroke_miterlimit: int 

2029 """Limit for marker miter joins.""" 

2030 marker_stroke_width: int 

2031 """Marker stroke width in pixels.""" 

2032 

2033 with_geometry: Literal['all', 'none'] 

2034 """Draw the geometry (``all``) or not (``none``).""" 

2035 with_label: Literal['all', 'none'] 

2036 """Draw the label (``all``) or not (``none``).""" 

2037 

2038 label_align: Literal['left', 'right', 'center'] 

2039 """Horizontal text alignment of the label.""" 

2040 label_background: Color 

2041 """Label background color.""" 

2042 label_fill: Color 

2043 """Label text color.""" 

2044 label_font_family: str 

2045 """Label font family.""" 

2046 label_font_size: int 

2047 """Label font size in pixels.""" 

2048 label_font_style: Literal['normal', 'italic'] 

2049 """Label font style.""" 

2050 label_font_weight: Literal['normal', 'bold'] 

2051 """Label font weight.""" 

2052 label_line_height: int 

2053 """Line spacing for multi-line labels.""" 

2054 label_max_scale: int 

2055 """Maximal scale denominator at which the label is shown.""" 

2056 label_min_scale: int 

2057 """Minimal scale denominator at which the label is shown.""" 

2058 label_offset_x: int 

2059 """Horizontal label offset in pixels.""" 

2060 label_offset_y: int 

2061 """Vertical label offset in pixels.""" 

2062 label_padding: list[int] 

2063 """Label padding in pixels, as ``[top, right, bottom, left]``.""" 

2064 label_placement: Literal['start', 'end', 'middle'] 

2065 """Label position along the geometry: the first point, the last point or the centroid.""" 

2066 label_stroke: Color 

2067 """Label text stroke color.""" 

2068 label_stroke_dasharray: list[int] 

2069 """Label text dash pattern.""" 

2070 label_stroke_dashoffset: int 

2071 """Offset of the label text dash pattern.""" 

2072 label_stroke_linecap: Literal['butt', 'round', 'square'] 

2073 """Shape of label text line ends.""" 

2074 label_stroke_linejoin: Literal['bevel', 'round', 'miter'] 

2075 """Shape of label text line corners.""" 

2076 label_stroke_miterlimit: int 

2077 """Limit for label text miter joins.""" 

2078 label_stroke_width: int 

2079 """Label text stroke width in pixels.""" 

2080 

2081 point_size: int 

2082 """Diameter of point geometries in pixels.""" 

2083 icon: Optional['XmlElement'] 

2084 """Icon for point geometries, the normalized SVG element.""" 

2085 

2086 offset_x: int 

2087 """Horizontal offset of the drawn geometry in pixels.""" 

2088 offset_y: int 

2089 """Vertical offset of the drawn geometry in pixels.""" 

2090 

2091 

2092class StyleProps(Props): 

2093 """CSS Style properties.""" 

2094 

2095 cssSelector: Optional[str] 

2096 text: Optional[str] 

2097 values: Optional[dict] 

2098 

2099 

2100class Style: 

2101 """Feature style.""" 

2102 

2103 cssSelector: str 

2104 """CSS selector of the style.""" 

2105 text: str 

2106 """Raw CSS text of the style.""" 

2107 values: StyleValues 

2108 """Parsed style values.""" 

2109################################################################################ 

2110 

2111 

2112################################################################################ 

2113# /lib/xmlx/types.pyinc 

2114 

2115 

2116class XmlNamespace(Data): 

2117 """XML namespace.""" 

2118 

2119 prefix: str 

2120 """Default prefix for this Namespace, empty for a default namespace declaration.""" 

2121 uri: Url 

2122 """Namespace uri.""" 

2123 schemaLocation: Url 

2124 """Namespace schema location.""" 

2125 extendsGml: bool 

2126 """Namespace schema extends the GML3 schema.""" 

2127 

2128 

2129class XmlOptions(Data): 

2130 """XML options for parsing and serialization.""" 

2131 

2132 removeNamespaces: bool = False 

2133 """Strip namespaces when parsing: tags and attributes are local names, declarations are dropped.""" 

2134 

2135 customNamespacePrefixes: Optional[dict[str, str]] = None 

2136 """Serialization: prefixes to use instead of the default ones (namespace uri -> prefix).""" 

2137 

2138 defaultNamespace: Optional['XmlNamespace'] = None 

2139 """Serialization: elements in this namespace are written without a prefix.""" 

2140 

2141 doctype: Optional[str] = None 

2142 """Serialization: document type definition (DTD), written after the XML declaration.""" 

2143 

2144 compactWhitespace: bool = False 

2145 """Collapse whitespace in text content (parsing and serialization).""" 

2146 

2147 withNamespaceDeclarations: bool = False 

2148 """Serialization: declare all namespaces used in the tree on the root element.""" 

2149 

2150 withSchemaLocations: bool = False 

2151 """Serialization: add ``xsi:schemaLocation`` for declared namespaces that have a schema location.""" 

2152 

2153 withXmlDeclaration: bool = False 

2154 """Serialization: write the ``<?xml ...?>`` declaration.""" 

2155 

2156 

2157class XmlElement(Iterable): 

2158 """XML Element. 

2159 

2160 Implements a subset of the ``ElementTree.Element`` API. 

2161 

2162 ``tag`` is either a local name (``Point``) or a Clark name (``{http://www.opengis.net/gml/3.2}Point``); 

2163 ``name`` is always the local name. Prefixed names never occur in a tree: ``tag()`` resolves ``ID:name`` 

2164 to a Clark name, the parser resolves prefixes against the document's declarations. The element itself 

2165 (constructor, ``add()``, ``set()``) takes names as they are; it has no namespace map to resolve against. 

2166 """ 

2167 

2168 tag: str 

2169 """Tag name, local or Clark.""" 

2170 

2171 name: str 

2172 """Element name (tag without a namespace).""" 

2173 

2174 text: str 

2175 """Text before first subelement.""" 

2176 

2177 tail: str 

2178 """Text after this element's end tag.""" 

2179 

2180 attrib: dict 

2181 """Dictionary of element attributes.""" 

2182 

2183 namespaces: list[XmlNamespace] 

2184 """Namespaces declared on this element (``prefix == ''`` for the default namespace).""" 

2185 

2186 def __len__(self) -> int: ... 

2187 

2188 def __iter__(self) -> Iterator['XmlElement']: ... 

2189 

2190 def __getitem__(self, item: int) -> 'XmlElement': ... 

2191 

2192 def append(self, subelement: 'XmlElement'): 

2193 """Add a child at the end of the list of children. 

2194 

2195 Args: 

2196 subelement: The element to add. 

2197 """ 

2198 

2199 def clear(self): 

2200 """Remove the attributes, namespace declarations, children, text and tail of this element.""" 

2201 

2202 def extend(self, subelements: Iterable['XmlElement']): 

2203 """Add children at the end of the list of children. 

2204 

2205 Args: 

2206 subelements: The elements to add. 

2207 """ 

2208 

2209 def find(self, path: str) -> Optional['XmlElement']: 

2210 """Find the first matching subelement. 

2211 

2212 Args: 

2213 path: Tag name or path in ``ElementTree`` syntax, with local or Clark names. 

2214 

2215 Returns: 

2216 The element, or ``None`` if nothing matches. 

2217 """ 

2218 

2219 def require(self, path: str) -> 'XmlElement': 

2220 """Find the first matching subelement, which must exist. 

2221 

2222 Args: 

2223 path: Tag name or path in ``ElementTree`` syntax, with local or Clark names. 

2224 

2225 Returns: 

2226 The element. 

2227 

2228 Raises: 

2229 gws.lib.xmlx.Error: If nothing matches. 

2230 """ 

2231 

2232 def findall(self, path: str) -> list['XmlElement']: 

2233 """Find all matching subelements. 

2234 

2235 Args: 

2236 path: Tag name or path in ``ElementTree`` syntax, with local or Clark names. 

2237 

2238 Returns: 

2239 A list of elements in document order. 

2240 """ 

2241 

2242 def findtext(self, path: str, default: str = '') -> str: 

2243 """Find the text of the first matching subelement. 

2244 

2245 Args: 

2246 path: Tag name or path in ``ElementTree`` syntax, with local or Clark names. 

2247 default: Value to return if nothing matches. 

2248 

2249 Returns: 

2250 The text of the element, or ``default``. 

2251 """ 

2252 

2253 def get(self, key: str, default: str = '') -> str: 

2254 """Get an attribute value. 

2255 

2256 Args: 

2257 key: Attribute name, local or Clark. 

2258 default: Value to return if the attribute does not exist. 

2259 

2260 Returns: 

2261 The attribute value, or ``default``. 

2262 """ 

2263 

2264 def insert(self, index: int, subelement: 'XmlElement'): 

2265 """Insert a child at the given position. 

2266 

2267 Args: 

2268 index: Position in the list of children. 

2269 subelement: The element to insert. 

2270 """ 

2271 

2272 def items(self) -> Iterable[tuple[str, Any]]: 

2273 """Get the attributes. 

2274 

2275 Returns: 

2276 The attributes as ``(name, value)`` pairs. 

2277 """ 

2278 

2279 def iter(self, tag: Optional[str] = None) -> Iterable['XmlElement']: 

2280 """Iterate over this element and all its descendants, depth-first. 

2281 

2282 Args: 

2283 tag: Only return elements with this tag; ``None`` or ``*`` returns all elements. 

2284 

2285 Returns: 

2286 An iterator of elements, starting with this element if it matches. 

2287 """ 

2288 

2289 def iterfind(self, path: str) -> Iterable['XmlElement']: 

2290 """Iterate over all matching subelements. 

2291 

2292 Args: 

2293 path: Tag name or path in ``ElementTree`` syntax, with local or Clark names. 

2294 

2295 Returns: 

2296 An iterator of elements in document order. 

2297 """ 

2298 

2299 def itertext(self) -> Iterable[str]: 

2300 """Iterate over the text content of this element and its descendants. 

2301 

2302 Returns: 

2303 An iterator of the non-empty texts and tails in document order, without the tail of this element. 

2304 """ 

2305 

2306 def keys(self) -> Iterable[str]: 

2307 """Get the attribute names. 

2308 

2309 Returns: 

2310 The attribute names. 

2311 """ 

2312 

2313 def remove(self, other: 'XmlElement'): 

2314 """Remove a child. 

2315 

2316 Args: 

2317 other: The child to remove. 

2318 

2319 Raises: 

2320 ValueError: If the element is not a child of this element. 

2321 """ 

2322 

2323 def set(self, key: str, value: Any): 

2324 """Set an attribute. 

2325 

2326 Args: 

2327 key: Attribute name, local or Clark. 

2328 value: Attribute value. 

2329 """ 

2330 

2331 # extensions 

2332 

2333 def hasattr(self, key: str) -> bool: 

2334 """Check if an attribute exists. 

2335 

2336 Args: 

2337 key: Attribute name, local or Clark. 

2338 

2339 Returns: 

2340 ``True`` if the attribute exists. 

2341 """ 

2342 

2343 def isa(self, *names: str) -> bool: 

2344 """Check if the local name of this element matches one of the given names, case-insensitively. 

2345 

2346 Args: 

2347 *names: Local names. 

2348 

2349 Returns: 

2350 ``True`` if the name matches. 

2351 """ 

2352 

2353 def add(self, tag: str, attrib: Optional[dict] = None, **extra) -> 'XmlElement': 

2354 """Create a new element and add it as a child. 

2355 

2356 Names are taken as they are (local or Clark); ``ID:name`` resolution is done by ``tag()`` only. 

2357 

2358 Args: 

2359 tag: Tag name, local or Clark. 

2360 attrib: Attributes. 

2361 **extra: Additional attributes. 

2362 

2363 Returns: 

2364 The new element. 

2365 """ 

2366 

2367 def children(self) -> list['XmlElement']: 

2368 """Get the children of this element. 

2369 

2370 Returns: 

2371 The list of children. This is the internal list, not a copy. 

2372 """ 

2373 

2374 def declare(self, *namespaces: XmlNamespace): 

2375 """Add namespace declarations to this element. 

2376 

2377 The declarations are written as ``xmlns`` attributes on output. Namespaces already declared 

2378 with the same prefix and URI are skipped. 

2379 

2380 Args: 

2381 *namespaces: Namespaces to declare. 

2382 """ 

2383 

2384 def findfirst(self, *paths) -> Optional['XmlElement']: 

2385 """Find the first element that matches one of the given paths. 

2386 

2387 Args: 

2388 *paths: Tag names or paths in ``ElementTree`` syntax, tried in order. 

2389 

2390 Returns: 

2391 The first match, or ``None``. Without paths, the first child, or ``None`` if there are no children. 

2392 """ 

2393 

2394 def textof(self, *paths) -> str: 

2395 """Get the text of the first matching element that has text. 

2396 

2397 Args: 

2398 *paths: Tag names or paths in ``ElementTree`` syntax, tried in order. 

2399 

2400 Returns: 

2401 The text, or an empty string if no matching element has text. 

2402 """ 

2403 

2404 def textlist(self, *paths, deep=False) -> list[str]: 

2405 """Collect texts from subelements. 

2406 

2407 Texts are stripped, empty texts are skipped. 

2408 

2409 Args: 

2410 *paths: Tag names or paths in ``ElementTree`` syntax. Without paths, the direct children are used. 

2411 deep: If ``True``, also collect texts from all descendants of the found elements. 

2412 

2413 Returns: 

2414 A list of texts in document order. 

2415 """ 

2416 

2417 def textdict(self, *paths, deep=False) -> dict[str, str]: 

2418 """Collect texts from subelements, keyed by tag. 

2419 

2420 Texts are stripped, empty texts are skipped. If several elements have the same tag, the last text wins. 

2421 

2422 Args: 

2423 *paths: Tag names or paths in ``ElementTree`` syntax. Without paths, the direct children are used. 

2424 deep: If ``True``, also collect texts from all descendants of the found elements. 

2425 

2426 Returns: 

2427 A dict of tags (local or Clark) and texts. 

2428 """ 

2429 

2430 def to_string(self, opts: Optional[XmlOptions] = None) -> str: 

2431 """Serialize this element and its subtree. 

2432 

2433 Args: 

2434 opts: Serialization options. 

2435 

2436 Returns: 

2437 An XML string. 

2438 

2439 Raises: 

2440 gws.lib.xmlx.WriteError: If the tree contains an invalid or prefixed name. 

2441 gws.lib.xmlx.NamespaceError: If a namespace is unknown, or one prefix is used for different URIs. 

2442 """ 

2443 

2444 def to_dict(self) -> dict: 

2445 """Convert the element tree to a dict. 

2446 

2447 Returns: 

2448 A dict with the keys ``tag``, ``attrib``, ``text``, ``tail`` and ``children``, 

2449 where ``children`` is a list of such dicts. 

2450 """ 

2451################################################################################ 

2452 

2453 

2454 

2455################################################################################ 

2456# /lib/crs/types.pyinc 

2457 

2458 

2459CrsName: TypeAlias = int | str 

2460"""A CRS code like ``EPSG:3857`` or a SRID like ``3857``.""" 

2461 

2462 

2463class CrsFormat(Enum): 

2464 """CRS name format.""" 

2465 

2466 none = '' 

2467 """No format.""" 

2468 crs = 'crs' 

2469 """Like ``crs84``.""" 

2470 srid = 'srid' 

2471 """Like ``3857``.""" 

2472 epsg = 'epsg' 

2473 """Like ``EPSG:3857``.""" 

2474 url = 'url' 

2475 """Like ``http://www.opengis.net/gml/srs/epsg.xml#3857``.""" 

2476 uri = 'uri' 

2477 """Like ``http://www.opengis.net/def/crs/epsg/0/3857``.""" 

2478 urnx = 'urnx' 

2479 """Like ``urn:x-ogc:def:crs:EPSG:3857``.""" 

2480 urn = 'urn' 

2481 """Like ``urn:ogc:def:crs:EPSG::3857``.""" 

2482 

2483 

2484class Axis(Enum): 

2485 """Axis orientation.""" 

2486 

2487 xy = 'xy' 

2488 """XY (longitude/latitude) axis orientation.""" 

2489 yx = 'yx' 

2490 """YX (latitude/longitude) axis orientation.""" 

2491 

2492 

2493class Bounds(Data): 

2494 """Geo-referenced extent: an extent together with its CRS.""" 

2495 

2496 crs: 'Crs' 

2497 """Coordinate reference system of the extent.""" 

2498 extent: Extent 

2499 """Extent in the coordinates of ``crs``.""" 

2500 

2501 

2502class Crs: 

2503 """Coordinate reference system.""" 

2504 

2505 axis: Axis 

2506 """Axis orientation.""" 

2507 base: int 

2508 """Base CRS code.""" 

2509 bounds: Bounds 

2510 """CRS own Bounds.""" 

2511 coordinatePrecision: int 

2512 """Preferred precision for coordinates in this CRS.""" 

2513 datum: str 

2514 """Datum.""" 

2515 epsg: str 

2516 """Name in the "epsg" format.""" 

2517 extent: Extent 

2518 """CRS own Extent.""" 

2519 isGeographic: bool 

2520 """This CRS is geographic.""" 

2521 isProjected: bool 

2522 """This CRS is projected.""" 

2523 isYX: bool 

2524 """This CRS has a lat/lon axis.""" 

2525 name: str 

2526 """CRS name.""" 

2527 proj4text: str 

2528 """Proj4 definition.""" 

2529 srid: int 

2530 """CRS SRID.""" 

2531 uom: Uom 

2532 """CRS unit.""" 

2533 uri: str 

2534 """Name in the "uri" format.""" 

2535 url: str 

2536 """Name in the "url" format.""" 

2537 urn: str 

2538 """Name in the "urn" format.""" 

2539 urnx: str 

2540 """Name in the "urnx" format.""" 

2541 wgsExtent: Extent 

2542 """CRS Extent in the WGS projection.""" 

2543 wgsMaxExtent: Extent 

2544 """Maximal extent that makes sense for this CRS, in the WGS projection.""" 

2545 wkt: str 

2546 """WKT definition.""" 

2547 

2548 def axis_for_format(self, fmt: 'CrsFormat') -> Axis: 

2549 """Get the axis orientation implied by a CRS name format. 

2550 

2551 For CRSs with a lat/lon axis, the orientation depends on how the CRS is named. 

2552 We adhere to the GeoServer convention: the ``srid``, ``epsg``, ``url`` and ``uri`` 

2553 formats imply XY, the ``urn`` and ``urnx`` formats imply YX 

2554 (see https://docs.geoserver.org/latest/en/user/services/wfs/axis_order.html). 

2555 For XY CRSs, the own axis is always returned. 

2556 

2557 Args: 

2558 fmt: CRS name format. 

2559 

2560 Returns: 

2561 The axis orientation. 

2562 """ 

2563 

2564 def clip_wgs_extent(self, wgs_extent: Extent) -> Optional[Extent]: 

2565 """Clip a WGS extent to the maximal extent of this CRS. 

2566 

2567 Args: 

2568 wgs_extent: Extent in the WGS projection. 

2569 

2570 Returns: 

2571 The clipped extent in the WGS projection, or ``None`` if there is no intersection. 

2572 """ 

2573 

2574 def extent_size_in_meters(self, extent: Extent) -> Size: 

2575 """Calculate the width and height of an extent in meters. 

2576 

2577 For projected CRSs, the extent size is returned as is. For geographic CRSs, 

2578 geodesic distances on the WGS84 ellipsoid are measured along the middle 

2579 latitude and the middle longitude of the extent. 

2580 

2581 Args: 

2582 extent: Extent in this CRS. 

2583 

2584 Returns: 

2585 A ``(width, height)`` tuple in meters. 

2586 

2587 Raises: 

2588 ``gws.lib.crs.Error``: If this is a projected CRS with units other than meters. 

2589 """ 

2590 

2591 def point_offset_in_meters(self, xy: Point, dist: float, az: int) -> Point: 

2592 """Calculate a point at a given distance and direction from another point. 

2593 

2594 Args: 

2595 xy: Point in this CRS. 

2596 dist: Distance in meters. 

2597 az: Azimuth in degrees (0 = North, 90 = East, etc.). 

2598 

2599 Returns: 

2600 The offset point in this CRS. 

2601 

2602 Raises: 

2603 ``gws.lib.crs.Error``: If this is a projected CRS with units other than meters. 

2604 """ 

2605 

2606 def to_geojson(self) -> dict: 

2607 """Return a GeoJSON representation of the CRS. 

2608 

2609 The CRS is represented as a "named CRS" with its ``urn`` name, 

2610 as per the 2008 GeoJSON specification (https://geojson.org/geojson-spec#named-crs). 

2611 

2612 Returns: 

2613 A GeoJSON ``crs`` dict. 

2614 """ 

2615 

2616 def to_string(self, fmt: Optional['CrsFormat'] = None) -> str: 

2617 """Return the name of the CRS in a given format. 

2618 

2619 Args: 

2620 fmt: Format to use, ``CrsFormat.epsg`` by default. 

2621 

2622 Returns: 

2623 The CRS name, like ``EPSG:3857``. 

2624 """ 

2625 

2626 def transform_extent(self, extent: Extent, crs_to: 'Crs') -> Extent: 

2627 """Transform an Extent from this CRS to another. 

2628 

2629 The transformation goes through WGS84. If the extent is very large 

2630 (almost the whole world) and the target CRS has a limited area of use, 

2631 the result is computed by sampling points, so that it stays finite. 

2632 

2633 Args: 

2634 extent: Extent in this CRS. 

2635 crs_to: Target CRS. 

2636 

2637 Returns: 

2638 The transformed Extent, with min and max values in order. 

2639 """ 

2640 

2641 def transform_resolution(self, extent: Extent, res: float, crs_to: 'Crs') -> float: 

2642 """Transform a resolution over an extent from this CRS to another. 

2643 

2644 The returned resolution is the finest one found at a set of sample points of the extent, 

2645 so that the target resolution is never coarser than the source resolution anywhere in the extent. 

2646 

2647 Args: 

2648 extent: Extent in this CRS. 

2649 res: Resolution in units of this CRS per pixel. 

2650 crs_to: Target CRS. 

2651 

2652 Returns: 

2653 The resolution in units of the target CRS per pixel, or ``0.0`` if the transformation fails. 

2654 """ 

2655 

2656 def transformer(self, crs_to: 'Crs') -> Callable: 

2657 """Create a transformer function to another CRS. 

2658 

2659 The function always uses the XY (easting/longitude first) axis order. 

2660 

2661 Args: 

2662 crs_to: Target CRS. 

2663 

2664 Returns: 

2665 A function that takes ``x, y`` and returns a transformed ``(x, y)`` tuple. 

2666 """ 

2667################################################################################ 

2668 

2669 

2670################################################################################ 

2671# /lib/shape/types.pyinc 

2672 

2673 

2674class ShapeProps(Props): 

2675 """Shape properties.""" 

2676 

2677 crs: str 

2678 geometry: dict 

2679 

2680 

2681class Shape(Object): 

2682 """Geo-referenced geometry.""" 

2683 

2684 type: GeometryType 

2685 """Geometry type.""" 

2686 

2687 crs: 'Crs' 

2688 """CRS of this shape.""" 

2689 

2690 x: Optional[float] 

2691 """X-coordinate for Point geometries, None otherwise.""" 

2692 

2693 y: Optional[float] 

2694 """Y-coordinate for Point geometries, None otherwise.""" 

2695 

2696 # common props 

2697 

2698 def area(self) -> float: 

2699 """Compute the area of the geometry. 

2700 

2701 Returns: 

2702 The area in CRS units, 0 for geometries without an area. 

2703 """ 

2704 

2705 def bounds(self) -> Bounds: 

2706 """Compute the bounds of this shape. 

2707 

2708 Returns: 

2709 A Bounds object in the CRS of this shape. 

2710 """ 

2711 

2712 def centroid(self) -> 'Shape': 

2713 """Compute the centroid of this shape. 

2714 

2715 Returns: 

2716 A Point shape. 

2717 """ 

2718 

2719 def center(self) -> tuple[float, float]: 

2720 """Compute the coordinates of the centroid. 

2721 

2722 Returns: 

2723 A tuple ``(x, y)``. 

2724 """ 

2725 

2726 # formats 

2727 

2728 def to_wkb(self) -> bytes: 

2729 """Convert this shape to WKB. 

2730 

2731 Returns: 

2732 WKB bytes. 

2733 """ 

2734 

2735 def to_wkb_hex(self) -> str: 

2736 """Convert this shape to hex-encoded WKB. 

2737 

2738 Returns: 

2739 A hex string. 

2740 """ 

2741 

2742 def to_ewkb(self) -> bytes: 

2743 """Convert this shape to EWKB, which includes the SRID. 

2744 

2745 Returns: 

2746 EWKB bytes. 

2747 """ 

2748 

2749 def to_ewkb_hex(self) -> str: 

2750 """Convert this shape to hex-encoded EWKB, which includes the SRID. 

2751 

2752 Returns: 

2753 A hex string. 

2754 """ 

2755 

2756 def to_wkt(self, trim=False, rounding_precision=-1, output_dimension=3) -> str: 

2757 """Convert this shape to WKT. 

2758 

2759 Whitespace around commas and parentheses is removed. 

2760 

2761 Args: 

2762 trim: Remove trailing zeros from the coordinates. 

2763 rounding_precision: Number of decimal places, -1 for full precision. 

2764 output_dimension: Max. number of dimensions to output. 

2765 

2766 Returns: 

2767 A WKT string. 

2768 """ 

2769 

2770 def to_ewkt(self, trim=False, rounding_precision=-1, output_dimension=3) -> str: 

2771 """Convert this shape to EWKT, which is WKT prefixed with ``SRID=<srid>;``. 

2772 

2773 Args: 

2774 trim: Remove trailing zeros from the coordinates. 

2775 rounding_precision: Number of decimal places, -1 for full precision. 

2776 output_dimension: Max. number of dimensions to output. 

2777 

2778 Returns: 

2779 An EWKT string. 

2780 """ 

2781 

2782 def to_geojson(self, keep_crs=False) -> dict: 

2783 """Convert this shape to a GeoJSON geometry dict. 

2784 

2785 Args: 

2786 keep_crs: Keep the CRS of this shape, otherwise transform the coordinates to WGS84. 

2787 

2788 Returns: 

2789 A GeoJSON geometry dict. 

2790 """ 

2791 

2792 def to_precision(self, prec: int) -> 'Shape': 

2793 """Create a copy of this shape with coordinates snapped to the given precision. 

2794 

2795 Args: 

2796 prec: Number of decimal places. 

2797 

2798 Returns: 

2799 A new shape. 

2800 """ 

2801 

2802 def to_props(self) -> ShapeProps: 

2803 """Convert this shape to props, with the EPSG code and a GeoJSON geometry in the CRS of this shape. 

2804 

2805 Returns: 

2806 Shape props. 

2807 """ 

2808 

2809 # predicates (https://shapely.readthedocs.io/en/stable/manual.html#predicates-and-relationships) 

2810 

2811 def is_empty(self) -> bool: 

2812 """Check if this shape is empty. 

2813 

2814 Returns: 

2815 ``True`` if this shape is empty. 

2816 """ 

2817 

2818 def is_ring(self) -> bool: 

2819 """Check if this shape is a closed and simple line. 

2820 

2821 Returns: 

2822 ``True`` if this shape is a ring. 

2823 """ 

2824 

2825 def is_simple(self) -> bool: 

2826 """Check if this shape is simple, that is, has no self-intersections. 

2827 

2828 Returns: 

2829 ``True`` if this shape is simple. 

2830 """ 

2831 

2832 def is_valid(self) -> bool: 

2833 """Check if this shape is valid. 

2834 

2835 Returns: 

2836 ``True`` if this shape is valid. 

2837 """ 

2838 

2839 def equals(self, other: 'Shape') -> bool: 

2840 """Check if this shape is spatially equal to the other. 

2841 

2842 The other shape is transformed to the CRS of this shape. The same applies to 

2843 all binary predicates. 

2844 

2845 Args: 

2846 other: Another shape. 

2847 

2848 Returns: 

2849 ``True`` if the shapes are equal. 

2850 """ 

2851 

2852 def contains(self, other: 'Shape') -> bool: 

2853 """Check if this shape contains the other. 

2854 

2855 Args: 

2856 other: Another shape. 

2857 

2858 Returns: 

2859 ``True`` if this shape contains the other. 

2860 """ 

2861 

2862 def covers(self, other: 'Shape') -> bool: 

2863 """Check if this shape covers the other. 

2864 

2865 Args: 

2866 other: Another shape. 

2867 

2868 Returns: 

2869 ``True`` if this shape covers the other. 

2870 """ 

2871 

2872 def covered_by(self, other: 'Shape') -> bool: 

2873 """Check if this shape is covered by the other. 

2874 

2875 Args: 

2876 other: Another shape. 

2877 

2878 Returns: 

2879 ``True`` if this shape is covered by the other. 

2880 """ 

2881 

2882 def crosses(self, other: 'Shape') -> bool: 

2883 """Check if this shape crosses the other. 

2884 

2885 Args: 

2886 other: Another shape. 

2887 

2888 Returns: 

2889 ``True`` if this shape crosses the other. 

2890 """ 

2891 

2892 def disjoint(self, other: 'Shape') -> bool: 

2893 """Check if this shape does not intersect the other. 

2894 

2895 Args: 

2896 other: Another shape. 

2897 

2898 Returns: 

2899 ``True`` if the shapes have no point in common. 

2900 """ 

2901 

2902 def intersects(self, other: 'Shape') -> bool: 

2903 """Check if this shape intersects the other. 

2904 

2905 Args: 

2906 other: Another shape. 

2907 

2908 Returns: 

2909 ``True`` if the shapes have at least one point in common. 

2910 """ 

2911 

2912 def overlaps(self, other: 'Shape') -> bool: 

2913 """Check if this shape overlaps the other. 

2914 

2915 Args: 

2916 other: Another shape. 

2917 

2918 Returns: 

2919 ``True`` if this shape overlaps the other. 

2920 """ 

2921 

2922 def touches(self, other: 'Shape') -> bool: 

2923 """Check if this shape touches the other. 

2924 

2925 Args: 

2926 other: Another shape. 

2927 

2928 Returns: 

2929 ``True`` if this shape touches the other. 

2930 """ 

2931 

2932 def within(self, other: 'Shape') -> bool: 

2933 """Check if this shape is within the other. 

2934 

2935 Args: 

2936 other: Another shape. 

2937 

2938 Returns: 

2939 ``True`` if this shape is within the other. 

2940 """ 

2941 

2942 # set operations 

2943 

2944 def union(self, others: list['Shape']) -> 'Shape': 

2945 """Compute the union of this shape and other shapes. 

2946 

2947 Args: 

2948 others: Other shapes, transformed to the CRS of this shape. 

2949 

2950 Returns: 

2951 A new shape, or this shape if ``others`` is empty. 

2952 """ 

2953 

2954 def intersection(self, *others: 'Shape') -> 'Shape': 

2955 """Compute the intersection of this shape and other shapes. 

2956 

2957 Args: 

2958 *others: Other shapes, transformed to the CRS of this shape. 

2959 

2960 Returns: 

2961 A new shape, or this shape if no others are given. 

2962 """ 

2963 

2964 # convertors 

2965 

2966 def to_multi(self) -> 'Shape': 

2967 """Convert a single geometry shape to a multi-geometry one. 

2968 

2969 Returns: 

2970 A multi-geometry shape for a point, a line string or a polygon, otherwise this shape. 

2971 """ 

2972 

2973 def to_type(self, new_type: 'GeometryType') -> 'Shape': 

2974 """Convert this shape to another geometry type. 

2975 

2976 Only the conversion from a single to the respective multi-geometry is supported. 

2977 

2978 Args: 

2979 new_type: Target geometry type. ``geometry`` and the current type return this shape. 

2980 

2981 Returns: 

2982 A converted shape. 

2983 

2984 Raises: 

2985 ``gws.Error``: If the conversion is not supported. 

2986 """ 

2987 

2988 def to_2d(self) -> 'Shape': 

2989 """Convert this shape to 2 dimensions. 

2990 

2991 Returns: 

2992 A 2D shape, or this shape if it is already 2D. 

2993 """ 

2994 

2995 # misc 

2996 

2997 def tolerance_polygon(self, tolerance=None, quad_segs=None) -> 'Shape': 

2998 """Build a buffer polygon around this shape. 

2999 

3000 Polygons without a tolerance are returned as is. Other shapes always get a 

3001 buffer, with a small minimal radius if no tolerance is given. Shapes in a 

3002 geographic CRS are buffered in Web Mercator. 

3003 

3004 Args: 

3005 tolerance: Buffer radius in CRS units, or in meters for geographic CRS. 

3006 quad_segs: Number of segments per quarter circle. 

3007 

3008 Returns: 

3009 A polygon shape. 

3010 """ 

3011 

3012 def transformed_to(self, crs: 'Crs') -> 'Shape': 

3013 """Transform this shape to another CRS. 

3014 

3015 Args: 

3016 crs: Target CRS. 

3017 

3018 Returns: 

3019 A transformed shape, or this shape if the CRS is the same. 

3020 """ 

3021################################################################################ 

3022 

3023 

3024################################################################################ 

3025# /lib/grid/types.pyinc 

3026 

3027 

3028MapTile: TypeAlias = tuple[int, int, int] 

3029"""Grid tile: ``(x, y, z)``.""" 

3030 

3031MapTileRange: TypeAlias = tuple[int, int, int, int, int] 

3032"""Rectangle of tiles at one level: ``(min_x, min_y, max_x, max_y, z)``.""" 

3033 

3034class MapGrid(Data): 

3035 """Fixed tile grid over a CRS, origin north-west. 

3036 

3037 Level ``z`` has the resolution ``baseResolution / 2**z``. See ``gws.lib.grid``. 

3038 """ 

3039 

3040 crs: Crs 

3041 """Grid CRS.""" 

3042 extent: Extent 

3043 """Frame extent; the origin is its north-west corner.""" 

3044 baseResolution: float 

3045 """Resolution at level 0, in CRS units per pixel.""" 

3046 tileSize: int 

3047 """Tile width and height in pixels.""" 

3048 

3049 

3050class TileMatrix(Data): 

3051 """Tile matrix, one level of a tile matrix set, as in WMTS.""" 

3052 

3053 identifier: str 

3054 """Matrix identifier.""" 

3055 scale: float 

3056 """Scale denominator.""" 

3057 resolution: float 

3058 """Resolution in CRS units per pixel.""" 

3059 x: float 

3060 """X coordinate of the top left corner.""" 

3061 y: float 

3062 """Y coordinate of the top left corner.""" 

3063 width: float 

3064 """Matrix width in tiles.""" 

3065 height: float 

3066 """Matrix height in tiles.""" 

3067 tileWidth: float 

3068 """Tile width in pixels.""" 

3069 tileHeight: float 

3070 """Tile height in pixels.""" 

3071 extent: Extent 

3072 """Matrix extent.""" 

3073 

3074 

3075class TileMatrixSet(Data): 

3076 """Tile matrix set, a pyramid of tile matrices, as in WMTS.""" 

3077 

3078 identifier: str 

3079 """Matrix set identifier.""" 

3080 crs: 'Crs' 

3081 """CRS of the matrices.""" 

3082 matrices: list[TileMatrix] 

3083 """Matrices of the set.""" 

3084################################################################################ 

3085 

3086 

3087################################################################################ 

3088# /gis/cache/types.pyinc 

3089 

3090 

3091class MapCache(Data): 

3092 """Tile cache settings of a grabber.""" 

3093 

3094 name: str 

3095 """Cache name, also the name of the cache directory.""" 

3096 maxAge: int 

3097 """Max. age of cached tiles in seconds, 0 disables storing.""" 

3098 maxLevel: int 

3099 """Finest zoom level to store.""" 

3100 requestBuffer: int 

3101 """Pixel buffer around source requests.""" 

3102 requestTiles: int 

3103 """Tiles per side of the block rendered in one source request.""" 

3104 

3105 

3106class TileStoreStats(Data): 

3107 """Tile store statistics.""" 

3108 

3109 count: int 

3110 """Number of stored tiles.""" 

3111 size: int 

3112 """Total size of stored tiles in bytes.""" 

3113 range: Optional[MapTileRange] 

3114 """Bounding tile range of the stored tiles, only for a single level.""" 

3115 

3116 

3117class TileStore: 

3118 """Storage for encoded map tiles of one grid. 

3119 

3120 Tiles are addressed by ``(x, y, z)``. A tile counts as stored only while it is younger than ``maxAge``. 

3121 """ 

3122 

3123 baseDir: str 

3124 """Base directory of the store.""" 

3125 maxAge: int 

3126 """Max. age of stored tiles in seconds.""" 

3127 

3128 def stats(self) -> TileStoreStats: 

3129 """Compute statistics for the whole store. 

3130 

3131 Returns: 

3132 Number and size of stored tiles. The tile range is not set. 

3133 """ 

3134 

3135 def stats_for_level(self, z: int) -> TileStoreStats: 

3136 """Compute statistics for a level. 

3137 

3138 Args: 

3139 z: Zoom level. 

3140 

3141 Returns: 

3142 Number, size and bounding tile range of the stored tiles of the level. 

3143 """ 

3144 

3145 def path(self, mt: MapTile) -> str: 

3146 """Return the file path of a tile. 

3147 

3148 Args: 

3149 mt: Tile. 

3150 

3151 Returns: 

3152 The file path, whether the tile exists or not. 

3153 """ 

3154 

3155 def has(self, mt: MapTile) -> bool: 

3156 """Check if a tile is stored. 

3157 

3158 Args: 

3159 mt: Tile. 

3160 

3161 Returns: 

3162 ``True`` if the tile is stored and younger than ``maxAge``. 

3163 """ 

3164 

3165 def read(self, mt: MapTile) -> Optional[bytes]: 

3166 """Read a stored tile. 

3167 

3168 Args: 

3169 mt: Tile. 

3170 

3171 Returns: 

3172 The tile content, or ``None`` if the tile is missing, stale or unreadable. 

3173 """ 

3174 

3175 def write(self, mt: MapTile, blob: bytes): 

3176 """Store a tile. 

3177 

3178 Args: 

3179 mt: Tile. 

3180 blob: Encoded tile content. 

3181 """ 

3182 

3183 def drop(self): 

3184 """Remove the whole store.""" 

3185 

3186 def drop_level(self, z: int): 

3187 """Remove all tiles of a level. 

3188 

3189 Args: 

3190 z: Zoom level. 

3191 """ 

3192 

3193 def drop_range(self, mtr: MapTileRange): 

3194 """Remove the tiles of a range. 

3195 

3196 Args: 

3197 mtr: Tile range. 

3198 """ 

3199################################################################################ 

3200 

3201 

3202################################################################################ 

3203# /gis/render/types.pyinc 

3204 

3205 

3206class MapView(Data): 

3207 """Geometry of a rendered map.""" 

3208 

3209 bounds: Bounds 

3210 """Bounds of the map, not rotated.""" 

3211 center: Point 

3212 """Center point.""" 

3213 rotation: int 

3214 """Rotation angle in degrees.""" 

3215 scale: int 

3216 """Scale denominator.""" 

3217 mmSize: Size 

3218 """Map size in mm.""" 

3219 pxSize: Size 

3220 """Map size in pixels.""" 

3221 dpi: int 

3222 """Resolution in dots per inch.""" 

3223 

3224 

3225class MapRenderInputPlaneType(Enum): 

3226 """Type of a map render input plane.""" 

3227 

3228 features = 'features' 

3229 """A list of features, rendered as SVG.""" 

3230 image = 'image' 

3231 """A raster image.""" 

3232 imageLayer = 'imageLayer' 

3233 """A layer, rendered as an image.""" 

3234 svgLayer = 'svgLayer' 

3235 """A layer, rendered as SVG.""" 

3236 svgSoup = 'svgSoup' 

3237 """An SVG soup, a resolution-independent drawing, see ``gws.lib.svg.soup_to_fragment``.""" 

3238 

3239 

3240class MapRenderInputPlane(Data): 

3241 """A plane of a map to render.""" 

3242 

3243 type: MapRenderInputPlaneType 

3244 """Plane type.""" 

3245 features: list['Feature'] 

3246 """Features, for the ``features`` type.""" 

3247 image: 'Image' 

3248 """Image, for the ``image`` type.""" 

3249 layer: 'Layer' 

3250 """Layer, for the ``imageLayer`` and ``svgLayer`` types.""" 

3251 opacity: float 

3252 """Opacity from 0 to 1, defaults to the layer opacity or 1.""" 

3253 soupPoints: list[Point] 

3254 """Points in map coordinates, for the ``svgSoup`` type.""" 

3255 soupTags: list[Any] 

3256 """Tags that refer to the points, for the ``svgSoup`` type.""" 

3257 styles: list['Style'] 

3258 """Styles. For ``features``, matched by CSS selector; for ``svgLayer``, the first style is used.""" 

3259 compositeLayerUids: list[str] 

3260 """Child layers to render in one composite image, for the ``imageLayer`` type.""" 

3261 

3262 

3263class MapRenderInput(Data): 

3264 """Input of the map renderer.""" 

3265 

3266 backgroundColor: int 

3267 """Background color of the first raster plane.""" 

3268 bbox: Extent 

3269 """Bounding box of the map. If not set, ``center`` and ``scale`` are used.""" 

3270 center: Point 

3271 """Center point of the map.""" 

3272 targetCrs: 'Crs' 

3273 """CRS of the map.""" 

3274 dpi: int 

3275 """Resolution of raster planes, for maps sized in mm.""" 

3276 mapSize: UomSize 

3277 """Map size in mm or pixels.""" 

3278 notify: Callable 

3279 """Callback, called with an event name and the plane before and after each plane is rendered.""" 

3280 planes: list['MapRenderInputPlane'] 

3281 """Planes to render, top to bottom.""" 

3282 project: 'Project' 

3283 """Project of the map.""" 

3284 rotation: int 

3285 """Rotation angle in degrees.""" 

3286 scale: int 

3287 """Scale denominator, used with ``center``.""" 

3288 user: 'User' 

3289 """User who requests the map.""" 

3290 visibleLayers: Optional[list['Layer']] 

3291 """Visible layers of the map.""" 

3292 

3293 

3294class MapRenderOutputPlaneType(Enum): 

3295 """Type of a map render output plane.""" 

3296 

3297 image = 'image' 

3298 """A raster image.""" 

3299 path = 'path' 

3300 """A path to an image file.""" 

3301 svg = 'svg' 

3302 """A list of SVG elements.""" 

3303 

3304 

3305class MapRenderOutputPlane(Data): 

3306 """A plane of a rendered map.""" 

3307 

3308 type: MapRenderOutputPlaneType 

3309 """Plane type.""" 

3310 path: str 

3311 """Image file path, for the ``path`` type.""" 

3312 elements: list[XmlElement] 

3313 """SVG elements, for the ``svg`` type.""" 

3314 image: 'Image' 

3315 """Image, for the ``image`` type.""" 

3316 

3317 

3318class MapRenderOutput(Data): 

3319 """Output of the map renderer.""" 

3320 

3321 planes: list['MapRenderOutputPlane'] 

3322 """Rendered planes, bottom to top.""" 

3323 view: MapView 

3324 """Map view of the vector planes.""" 

3325 

3326 

3327class LayerRenderInputType(Enum): 

3328 """Type of a layer render request.""" 

3329 

3330 box = 'box' 

3331 """Render an image of the view extent.""" 

3332 tile = 'tile' 

3333 """Render a tile of the layer grid.""" 

3334 svg = 'svg' 

3335 """Render SVG elements for the view.""" 

3336 

3337 

3338class LayerRenderInput(Data): 

3339 """Input of a layer render request.""" 

3340 

3341 extraParams: dict 

3342 """Additional request parameters, e.g. ``compositeLayerUids``.""" 

3343 renderParams: dict 

3344 """Parameters set by the layer for its grabber. Non-empty params mark a dynamic, uncached request.""" 

3345 project: 'Project' 

3346 """Project of the request.""" 

3347 style: 'Style' 

3348 """Style for the ``svg`` type.""" 

3349 targetCrs: 'Crs' 

3350 """CRS of the output.""" 

3351 type: LayerRenderInputType 

3352 """Request type.""" 

3353 user: 'User' 

3354 """User who requests the rendering.""" 

3355 view: MapView 

3356 """Map view, for the ``box`` and ``svg`` types.""" 

3357 x: int 

3358 """Tile column, for the ``tile`` type.""" 

3359 y: int 

3360 """Tile row, for the ``tile`` type.""" 

3361 z: int 

3362 """Zoom level, for the ``tile`` type.""" 

3363 

3364 

3365class LayerRenderOutput(Data): 

3366 """Output of a layer render request.""" 

3367 

3368 content: bytes 

3369 """Encoded image, for the ``box`` and ``tile`` types.""" 

3370 tags: list[XmlElement] 

3371 """SVG elements, for the ``svg`` type.""" 

3372################################################################################ 

3373 

3374 

3375################################################################################ 

3376# /gis/source/types.pyinc 

3377 

3378 

3379class SourceStyle(Data): 

3380 """A style of a source layer, as listed in the capabilities of a service.""" 

3381 

3382 isDefault: bool 

3383 """The style is the default style of the layer.""" 

3384 legendUrl: Url 

3385 """URL of the legend image.""" 

3386 metadata: 'Metadata' 

3387 """Style metadata.""" 

3388 name: str 

3389 """Style name.""" 

3390 

3391 

3392class SourceLayer(Data): 

3393 """A layer of an external source, such as a WMS, WFS or WMTS service or a QGIS project. 

3394 

3395 Source layers are read from capabilities and form a tree. The ``a*`` properties 

3396 are set by ``gws.gis.source.check_layers``. 

3397 """ 

3398 

3399 aLevel: int 

3400 """Depth in the layer tree, 1 for top-level layers.""" 

3401 aPath: str 

3402 """Path of uids from the top of the tree, e.g. ``/root/roads``.""" 

3403 aUid: str 

3404 """Uid derived from the name or title.""" 

3405 

3406 dataSource: dict 

3407 """Parsed data source of a QGIS layer.""" 

3408 metadata: 'Metadata' 

3409 """Layer metadata.""" 

3410 

3411 supportedCrs: list['Crs'] 

3412 """CRS supported by the source for this layer.""" 

3413 wgsExtent: Extent 

3414 """Layer extent in WGS84.""" 

3415 

3416 isExpanded: bool 

3417 """The layer is expanded in the source layer tree.""" 

3418 isGroup: bool 

3419 """The layer is a group.""" 

3420 isImage: bool 

3421 """The layer can be rendered as an image.""" 

3422 isQueryable: bool 

3423 """The layer can be queried for features.""" 

3424 isReadOnly: bool 

3425 """The layer has the readOnly flag set.""" 

3426 isVisible: bool 

3427 """The layer is visible by default.""" 

3428 

3429 layers: list['SourceLayer'] 

3430 """Sub-layers.""" 

3431 

3432 name: str 

3433 """Layer name, used in requests to the source.""" 

3434 title: str 

3435 """Layer title.""" 

3436 

3437 legendUrl: Url 

3438 """URL of the legend image.""" 

3439 opacity: float 

3440 """Layer opacity from 0 to 1.""" 

3441 scaleRange: list[float] 

3442 """Min. and max. scale denominators at which the layer is visible.""" 

3443 

3444 styles: list[SourceStyle] 

3445 """Available styles.""" 

3446 defaultStyle: Optional[SourceStyle] 

3447 """Default style.""" 

3448 

3449 tileMatrixIds: list[str] 

3450 """Ids of the WMTS tile matrix sets the layer links to.""" 

3451 tileMatrixSets: list[TileMatrixSet] 

3452 """WMTS tile matrix sets of the layer.""" 

3453 imageFormat: str 

3454 """Image format for WMTS requests.""" 

3455 resourceUrls: dict 

3456 """WMTS resource URL templates, keyed by resource type.""" 

3457 

3458 sourceId: str 

3459 """Id of the layer in the source, e.g. the QGIS layer id.""" 

3460 properties: dict 

3461 """Custom properties of a QGIS layer.""" 

3462################################################################################ 

3463 

3464 

3465 

3466################################################################################ 

3467# /config/types.pyinc 

3468 

3469 

3470class ConfigLocation(Data): 

3471 """Location in the configuration tree.""" 

3472 

3473 objectUid: str 

3474 """UID of the object.""" 

3475 objectType: str 

3476 """Type of the object.""" 

3477 objectName: str 

3478 """Name of the object.""" 

3479 propName: str 

3480 """Property of the parent this object is located at.""" 

3481 

3482 

3483class ConfigErrorInfo(Data): 

3484 """Full information about a configuration error.""" 

3485 

3486 message: str 

3487 """Error message.""" 

3488 path: str 

3489 """Path to the configuration file.""" 

3490 line: int 

3491 """Line number where the error occurred.""" 

3492 value: str 

3493 """Value that caused the error.""" 

3494 stack: list[ConfigLocation] 

3495 """Locations of the objects being configured when the error occurred, innermost first.""" 

3496 contextLines: list[str] 

3497 """Source lines around the error, with line numbers, the error line is marked with ``>>>``.""" 

3498 cause: str 

3499 """Representation of the exception that caused the error.""" 

3500 

3501 

3502class ConfigContext(Data): 

3503 """Shared state for parsing and validating a configuration.""" 

3504 

3505 specs: SpecRuntime 

3506 """Specs used to validate the configuration.""" 

3507 readOptions: set[SpecReadOption] 

3508 """Options passed to the spec reader.""" 

3509 errors: list[ConfigErrorInfo] 

3510 """Errors collected so far.""" 

3511 warnings: list[ConfigErrorInfo] 

3512 """Warnings collected so far.""" 

3513 paths: set[str] 

3514 """Paths of all configuration files that were read, including included files.""" 

3515 

3516 

3517 

3518class ConfigResult(Data): 

3519 """Result of a configuration run.""" 

3520 

3521 root: Optional['Root'] 

3522 """Configured root object, or ``None`` if configuration failed or was not requested.""" 

3523 config: Optional['Config'] 

3524 """Parsed application configuration.""" 

3525 errors: list[ConfigErrorInfo] 

3526 """Configuration errors.""" 

3527 warnings: list[ConfigErrorInfo] 

3528 """Configuration warnings.""" 

3529 info: str 

3530 """Summary with the number of objects, time and memory used.""" 

3531################################################################################ 

3532 

3533 

3534################################################################################ 

3535# /server/types.pyinc 

3536 

3537 

3538class ServerManager(Node): 

3539 """Server configuration manager. 

3540 

3541 Holds the ``server`` configuration and creates the configuration files for 

3542 the embedded servers and the server start script. 

3543 """ 

3544 

3545 templates: list['Template'] 

3546 """Templates for the server configuration files and the start script.""" 

3547 

3548 def create_server_configs(self, target_dir: str, script_path: str, pid_paths: dict): 

3549 """Create the server configuration files and the start script. 

3550 

3551 Args: 

3552 target_dir: Directory for the configuration files. 

3553 script_path: Path of the start script. 

3554 pid_paths: Paths of the pid files, keyed by server name (``web``, ``spool``, ``nginx``). 

3555 """ 

3556 

3557 

3558class ServerMonitor(Node): 

3559 """Server monitor. 

3560 

3561 Watches configuration files and directories and reconfigures the server 

3562 when they change, and runs periodic tasks of registered objects. 

3563 """ 

3564 

3565 def watch_directory(self, path: str, pattern: 'Regex', recursive=False): 

3566 """Add a directory to watch. 

3567 

3568 Args: 

3569 path: Directory path. 

3570 pattern: Regex pattern for file names to watch. 

3571 recursive: Also watch subdirectories. 

3572 """ 

3573 

3574 def watch_file(self, path: str): 

3575 """Add a file to watch. 

3576 

3577 Args: 

3578 path: File path. 

3579 """ 

3580 

3581 def register_periodic_task(self, obj: Node, frequency: int = 0): 

3582 """Register an object as a periodic task handler. 

3583 

3584 Args: 

3585 obj: A node with a ``periodic_task`` method. 

3586 frequency: Interval between runs in seconds, the monitor default if 0. 

3587 

3588 Raises: 

3589 ``gws.Error``: If the object has no ``periodic_task`` method. 

3590 """ 

3591 

3592 def schedule_reload(self, with_reconfigure: bool = False): 

3593 """Schedule a reload of the web and spool backends. 

3594 

3595 The reload is performed by the monitor on its next tick. 

3596 

3597 Args: 

3598 with_reconfigure: Reconfigure the server before reloading. 

3599 """ 

3600 

3601 def start(self): 

3602 """Start watching files and register the timer that drives the monitor. 

3603 

3604 Must be called in a uWSGI process. 

3605 """ 

3606################################################################################ 

3607 

3608 

3609 

3610################################################################################ 

3611# /base/metadata/types.pyinc 

3612 

3613 

3614class MetadataLink(Data): 

3615 """Link to a metadata document or another resource related to an object.""" 

3616 

3617 about: str 

3618 """Aspect of the object the link describes.""" 

3619 description: str 

3620 """Description of the linked resource.""" 

3621 format: str 

3622 """Format of the linked resource.""" 

3623 formatVersion: str 

3624 """Version of the format of the linked resource.""" 

3625 function: str 

3626 """Function of the link.""" 

3627 mimeType: str 

3628 """MIME type of the linked resource.""" 

3629 scheme: str 

3630 """Link scheme or protocol.""" 

3631 title: str 

3632 """Link title.""" 

3633 type: str 

3634 """Link type.""" 

3635 url: str 

3636 """Link URL.""" 

3637 

3638 

3639class Metadata(Data): 

3640 """Metadata of an object, used in the client, in OWS services and in catalog records.""" 

3641 

3642 name: str 

3643 """Object name.""" 

3644 title: str 

3645 """Object title.""" 

3646 

3647 abstract: str 

3648 """Abstract, a brief description of the object.""" 

3649 accessConstraints: str 

3650 """Access constraints.""" 

3651 accessConstraintsType: str 

3652 """Type of the access constraints.""" 

3653 attribution: str 

3654 """Attribution text.""" 

3655 attributionUrl: str 

3656 """URL of the attribution.""" 

3657 dateCreated: Optional['datetime.datetime'] 

3658 """Creation date.""" 

3659 dateUpdated: Optional['datetime.datetime'] 

3660 """Last update date.""" 

3661 fees: str 

3662 """Fees for using the object.""" 

3663 image: str 

3664 """Image URL or path associated with the object.""" 

3665 keywords: list[str] 

3666 """Keywords, optionally prefixed with a vocabulary, e.g. ``gemet:river``.""" 

3667 license: str 

3668 """License text.""" 

3669 licenseUrl: str 

3670 """License URL.""" 

3671 

3672 contactAddress: str 

3673 """Street address of the contact.""" 

3674 contactAddressType: str 

3675 """Type of the contact address.""" 

3676 contactArea: str 

3677 """Administrative area, state or province of the contact address.""" 

3678 contactCity: str 

3679 """Contact city.""" 

3680 contactCountry: str 

3681 """Contact country.""" 

3682 contactEmail: str 

3683 """Contact email address.""" 

3684 contactFax: str 

3685 """Contact fax number.""" 

3686 contactOrganization: str 

3687 """Contact organization.""" 

3688 contactPerson: str 

3689 """Contact person name.""" 

3690 contactPhone: str 

3691 """Contact phone number.""" 

3692 contactPosition: str 

3693 """Contact position or job title.""" 

3694 contactProviderName: str 

3695 """Name of the service provider.""" 

3696 contactProviderSite: str 

3697 """Website of the service provider.""" 

3698 contactRole: str 

3699 """Role of the contact, an ISO ``CI_RoleCode`` value.""" 

3700 contactUrl: str 

3701 """Website of the contact.""" 

3702 contactZip: str 

3703 """Contact postal code.""" 

3704 

3705 authorityIdentifier: str 

3706 """Identifier issued by the authority.""" 

3707 authorityName: str 

3708 """Name of the authority that issues identifiers.""" 

3709 authorityUrl: str 

3710 """URL of the authority that issues identifiers.""" 

3711 

3712 metaLinks: list[MetadataLink] 

3713 """Links to metadata documents.""" 

3714 serviceMetadataURL: str 

3715 """URL of the service metadata document.""" 

3716 

3717 catalogCitationUid: str 

3718 """Identifier of the resource in catalog records.""" 

3719 catalogUid: str 

3720 """Identifier of the metadata record.""" 

3721 

3722 language: str 

3723 """Language as an ISO 639-1 code.""" 

3724 language3: str 

3725 """Language as an ISO 639-2 three-letter code, derived from ``language``.""" 

3726 languageBib: str 

3727 """Language as an ISO 639-2 bibliographic code, derived from ``language``.""" 

3728 languageName: str 

3729 """Name of the language.""" 

3730 

3731 parentIdentifier: str 

3732 """Identifier of the parent metadata record.""" 

3733 wgsExtent: Optional[Extent] 

3734 """Geographic extent in WGS84.""" 

3735 crs: Optional['Crs'] 

3736 """Reference system of the data.""" 

3737 temporalBegin: Optional['datetime.datetime'] 

3738 """Start of the temporal extent.""" 

3739 temporalEnd: Optional['datetime.datetime'] 

3740 """End of the temporal extent.""" 

3741 

3742 inspireMandatoryKeyword: str 

3743 """INSPIRE mandatory keyword (service type).""" 

3744 inspireDegreeOfConformity: str 

3745 """Degree of conformity with the INSPIRE implementing rules.""" 

3746 inspireResourceType: str 

3747 """INSPIRE resource type.""" 

3748 inspireSpatialDataServiceType: str 

3749 """INSPIRE spatial data service type.""" 

3750 inspireSpatialScope: str 

3751 """INSPIRE spatial scope.""" 

3752 inspireSpatialScopeName: str 

3753 """Display name of the INSPIRE spatial scope.""" 

3754 inspireTheme: str 

3755 """INSPIRE data theme code.""" 

3756 

3757 inspireThemeNameLocal: str 

3758 """Name of the INSPIRE theme in the metadata language, derived from ``inspireTheme``.""" 

3759 inspireThemeNameEn: str 

3760 """English name of the INSPIRE theme, derived from ``inspireTheme``.""" 

3761 

3762 isoMaintenanceFrequencyCode: str 

3763 """How often the data is updated.""" 

3764 isoQualityConformanceExplanation: str 

3765 """Explanation of the conformance result.""" 

3766 isoQualityConformanceQualityPass: bool 

3767 """The data passes the conformance test.""" 

3768 isoQualityConformanceSpecificationDate: str 

3769 """Publication date of the conformance specification.""" 

3770 isoQualityConformanceSpecificationTitle: str 

3771 """Title of the conformance specification.""" 

3772 isoQualityLineageSource: str 

3773 """Description of the source data.""" 

3774 isoQualityLineageSourceScale: int 

3775 """Scale denominator of the source data.""" 

3776 isoQualityLineageStatement: str 

3777 """Statement on the lineage of the data.""" 

3778 isoRestrictionCode: str 

3779 """Restrictions on access or use of the data.""" 

3780 isoServiceFunction: str 

3781 """ISO service function.""" 

3782 isoScope: str 

3783 """Scope of the metadata.""" 

3784 isoScopeName: str 

3785 """Name of the scope.""" 

3786 isoSpatialRepresentationType: str 

3787 """How the data is represented spatially.""" 

3788 isoTopicCategories: list[str] 

3789 """ISO 19115 topic categories.""" 

3790 isoSpatialResolution: int 

3791 """Spatial resolution as a scale denominator.""" 

3792################################################################################ 

3793 

3794 

3795################################################################################ 

3796# /base/feature/types.pyinc 

3797 

3798 

3799FeatureUid: TypeAlias = str 

3800"""Unique Feature id.""" 

3801 

3802class FeatureRecord(Data): 

3803 """Raw data from a feature source.""" 

3804 

3805 attributes: dict 

3806 """Attribute values as read from the source or as written to it.""" 

3807 meta: dict 

3808 """Extra source information, e.g. ``layerName`` for features from OWS responses.""" 

3809 uid: Optional[str] 

3810 """Feature id provided by the source.""" 

3811 shape: Optional['Shape'] 

3812 """Geometry provided by the source.""" 

3813 ewkt: str 

3814 """Geometry as EWKT, provided by some sources.""" 

3815 

3816 

3817class FeatureProps(Props): 

3818 """Feature Proprieties.""" 

3819 

3820 attributes: dict 

3821 category: Optional[str] 

3822 cssSelector: str 

3823 errors: Optional[list['ModelValidationError']] 

3824 createWithFeatures: Optional[list['FeatureProps']] 

3825 isNew: bool 

3826 modelUid: str 

3827 uid: str 

3828 views: dict 

3829 

3830 

3831class Feature: 

3832 """Feature object. 

3833 

3834 A set of named attributes that belongs to a model. The model defines the 

3835 uid attribute (``uidName``) and the geometry attribute (``geometryName``). 

3836 """ 

3837 

3838 attributes: dict 

3839 """Attribute values as python values.""" 

3840 category: str 

3841 """Category for grouping features in the client, e.g. the source layer name.""" 

3842 cssSelector: str 

3843 """CSS selector for the feature style in the client.""" 

3844 errors: list['ModelValidationError'] 

3845 """Validation errors.""" 

3846 isNew: bool 

3847 """The feature is new and not yet saved.""" 

3848 model: 'Model' 

3849 """Model the feature belongs to.""" 

3850 props: 'FeatureProps' 

3851 """Data from or for the client.""" 

3852 record: 'FeatureRecord' 

3853 """Raw data from or for the source.""" 

3854 views: dict 

3855 """Rendered views, keyed by view name, e.g. ``title`` or ``label``.""" 

3856 createWithFeatures: list['Feature'] 

3857 """Related features a new feature is created with.""" 

3858 insertedPrimaryKey: Optional[int | str] 

3859 """Primary key of the row inserted when the feature was created.""" 

3860 

3861 def get(self, name: str, default=None) -> Any: 

3862 """Get an attribute value. 

3863 

3864 Args: 

3865 name: Attribute name. 

3866 default: Value to return if the attribute does not exist. 

3867 

3868 Returns: 

3869 The attribute value, or ``default``. 

3870 """ 

3871 

3872 def has(self, name: str) -> bool: 

3873 """Check if an attribute exists. 

3874 

3875 Args: 

3876 name: Attribute name. 

3877 

3878 Returns: 

3879 ``True`` if the attribute exists. 

3880 """ 

3881 

3882 def set(self, name: str, value: Any) -> 'Feature': 

3883 """Set an attribute value. 

3884 

3885 Args: 

3886 name: Attribute name. 

3887 value: Attribute value. 

3888 

3889 Returns: 

3890 The feature itself. 

3891 """ 

3892 

3893 def raw(self, name: str) -> Any: 

3894 """Get a raw attribute value from the record. 

3895 

3896 Args: 

3897 name: Attribute name. 

3898 

3899 Returns: 

3900 The value, or ``None`` if the record has no such attribute. 

3901 """ 

3902 

3903 def render_views(self, templates: list['Template'], **kwargs) -> 'Feature': 

3904 """Render feature views and store them in ``views``. 

3905 

3906 Each template renders the view named after the last part of its subject, 

3907 e.g. ``feature.title`` renders ``title``. The templates receive the 

3908 feature attributes, ``feature`` and the extra arguments. 

3909 

3910 Args: 

3911 templates: Feature templates. 

3912 **kwargs: Extra template arguments. 

3913 

3914 Returns: 

3915 The feature itself. 

3916 """ 

3917 

3918 def shape(self) -> Optional['Shape']: 

3919 """Get the feature geometry. 

3920 

3921 Returns: 

3922 The geometry, or ``None`` if the model has no geometry or the feature has no value. 

3923 """ 

3924 

3925 def to_svg(self, view: 'MapView', label: Optional[str] = None, style: Optional['Style'] = None) -> list[XmlElement]: 

3926 """Render the feature geometry as SVG fragments for a map view. 

3927 

3928 Args: 

3929 view: Map view. The geometry is transformed to its CRS. 

3930 label: Label text. 

3931 style: Style. 

3932 

3933 Returns: 

3934 A list of SVG elements, empty if the feature has no geometry. 

3935 """ 

3936 

3937 def to_geojson(self, keep_crs=False) -> dict: 

3938 """Convert the feature to a GeoJSON feature. 

3939 

3940 The geometry is converted to WGS84 unless ``keep_crs`` is set. The uid 

3941 is added as the ``id`` property. 

3942 

3943 Args: 

3944 keep_crs: Keep the geometry coordinates in the feature CRS. 

3945 

3946 Returns: 

3947 A GeoJSON feature dict. 

3948 """ 

3949 

3950 def transform_to(self, crs: 'Crs') -> 'Feature': 

3951 """Transform the feature geometry to another CRS, in place. 

3952 

3953 Args: 

3954 crs: Target CRS. 

3955 

3956 Returns: 

3957 The feature itself. 

3958 """ 

3959 

3960 def uid(self) -> FeatureUid: 

3961 """Get the unique id of the feature. 

3962 

3963 Returns: 

3964 The value of the uid attribute as a string, an empty string if the model 

3965 has no uid attribute, or ``None`` if the feature has no value. 

3966 """ 

3967################################################################################ 

3968 

3969 

3970 

3971################################################################################ 

3972# /base/action/types.pyinc 

3973 

3974 

3975class ActionManager(Node): 

3976 """Action manager. 

3977 

3978 Locates actions in projects and the application and prepares command calls. 

3979 """ 

3980 

3981 def actions_for_project(self, project: 'Project', user: 'User') -> list['Action']: 

3982 """Get the actions a user can use in a project. 

3983 

3984 Includes the project actions and the application actions, one action per type. 

3985 A project action takes precedence over an application action of the same type. 

3986 

3987 Args: 

3988 project: The project. 

3989 user: The user. 

3990 

3991 Returns: 

3992 A list of actions. 

3993 """ 

3994 

3995 def find_action(self, project: Optional['Project'], ext_type: str, user: 'User') -> Optional['Action']: 

3996 """Find an action by its type. 

3997 

3998 Searches the project actions first, if a project is given, then the application actions. 

3999 

4000 Args: 

4001 project: The project, or ``None`` to search the application actions only. 

4002 ext_type: Action type, for example ``map``. 

4003 user: The user who wants to use the action. 

4004 

4005 Returns: 

4006 The action object, or ``None`` if not found. 

4007 

4008 Raises: 

4009 ForbiddenError: If the action is found but the user may not use it. 

4010 """ 

4011 

4012 def prepare_action( 

4013 self, 

4014 command_category: CommandCategory, 

4015 command_name: str, 

4016 params: dict, 

4017 path: str, 

4018 user: 'User', 

4019 read_options: Optional[set[SpecReadOption]]=None, 

4020 ) -> tuple[Callable, Request]: 

4021 """Prepare a command call. 

4022 

4023 Parses the parameters into the command's request type, finds the action 

4024 that owns the command (in the requested project, then in the application) 

4025 and checks the user's access. 

4026 

4027 Args: 

4028 command_category: Command category. 

4029 command_name: Command name, for example ``mapDescribeLayer``. 

4030 params: Raw request parameters. 

4031 path: Request path; for ``raw`` commands, the project uid can be given as a ``/projectUid/<uid>`` segment. 

4032 user: The user who runs the command. 

4033 read_options: Options for the spec reader. 

4034 

4035 Returns: 

4036 A tuple of the bound command method and the parsed request object. 

4037 

4038 Raises: 

4039 NotFoundError: If the command, the project or the action is not found. 

4040 BadRequestError: If the parameters cannot be parsed. 

4041 ForbiddenError: If the user may not use the project or the action. 

4042 """ 

4043 

4044 

4045class Action(Node): 

4046 """Server action. 

4047 

4048 An action is a configurable object that provides server commands. 

4049 """ 

4050################################################################################ 

4051 

4052 

4053################################################################################ 

4054# /base/auth/types.pyinc 

4055 

4056 

4057class User(Object): 

4058 """User. 

4059 

4060 A user has a set of roles, which are checked against the permissions of 

4061 objects to decide access. 

4062 """ 

4063 

4064 isGuest: bool 

4065 """The user is the guest user.""" 

4066 

4067 authProvider: 'AuthProvider' 

4068 """The provider that created the user.""" 

4069 

4070 attributes: dict 

4071 """Public user attributes, sent to the client.""" 

4072 data: dict 

4073 """Private user data from the provider.""" 

4074 roles: set[str] 

4075 """User roles.""" 

4076 uid: str 

4077 """Global user uid, made of the provider uid and the local uid.""" 

4078 

4079 authToken: str 

4080 """Token for the ``token`` authentication method.""" 

4081 displayName: str 

4082 """User display name.""" 

4083 email: str 

4084 """User email.""" 

4085 localUid: str 

4086 """User uid within its provider.""" 

4087 loginName: str 

4088 """User login name.""" 

4089 mfaUid: str 

4090 """Uid of the multi-factor adapter for this user, empty if none.""" 

4091 mfaSecret: str 

4092 """Secret for the multi-factor adapter.""" 

4093 

4094 def acl_bit(self, access: Access, obj: Object) -> Optional[int]: 

4095 """Get the access decision for an object itself, without parents. 

4096 

4097 Args: 

4098 access: Access mode. 

4099 obj: The object. 

4100 

4101 Returns: 

4102 ``gws.c.ALLOW`` or ``gws.c.DENY`` if the object's permissions decide 

4103 for one of the user's roles, ``None`` otherwise. 

4104 """ 

4105 

4106 def can(self, access: Access, obj: Object, *context) -> bool: 

4107 """Check if the user can access an object. 

4108 

4109 If the object's permissions do not decide, the context objects are 

4110 checked in turn, then the parents of the last checked object. 

4111 

4112 Args: 

4113 access: Access mode. 

4114 obj: The object. 

4115 *context: Further objects to check, before the parents. 

4116 

4117 Returns: 

4118 ``True`` if access is granted. 

4119 """ 

4120 

4121 def can_create(self, obj: Object, *context) -> bool: 

4122 """Check if the user has the ``create`` permission on an object. 

4123 

4124 Args: 

4125 obj: The object. 

4126 *context: Further objects to check, before the parents. 

4127 

4128 Returns: 

4129 ``True`` if access is granted. 

4130 """ 

4131 

4132 def can_delete(self, obj: Object, *context) -> bool: 

4133 """Check if the user has the ``delete`` permission on an object. 

4134 

4135 Args: 

4136 obj: The object. 

4137 *context: Further objects to check, before the parents. 

4138 

4139 Returns: 

4140 ``True`` if access is granted. 

4141 """ 

4142 

4143 def can_read(self, obj: Object, *context) -> bool: 

4144 """Check if the user has the ``read`` permission on an object. 

4145 

4146 Args: 

4147 obj: The object. 

4148 *context: Further objects to check, before the parents. 

4149 

4150 Returns: 

4151 ``True`` if access is granted. 

4152 """ 

4153 

4154 def can_use(self, obj: Object, *context) -> bool: 

4155 """Check if the user can use an object, which requires the ``read`` permission. 

4156 

4157 Args: 

4158 obj: The object. 

4159 *context: Further objects to check, before the parents. 

4160 

4161 Returns: 

4162 ``True`` if access is granted. 

4163 """ 

4164 

4165 def can_write(self, obj: Object, *context) -> bool: 

4166 """Check if the user has the ``write`` permission on an object. 

4167 

4168 Args: 

4169 obj: The object. 

4170 *context: Further objects to check, before the parents. 

4171 

4172 Returns: 

4173 ``True`` if access is granted. 

4174 """ 

4175 

4176 def can_edit(self, obj: Object, *context) -> bool: 

4177 """Check if the user has any of the ``write``, ``create`` or ``delete`` permissions on an object. 

4178 

4179 Args: 

4180 obj: The object. 

4181 *context: Further objects to check, before the parents. 

4182 

4183 Returns: 

4184 ``True`` if access is granted. 

4185 """ 

4186 

4187 def has_role(self, role: str) -> bool: 

4188 """Check if the user has a role. 

4189 

4190 Args: 

4191 role: Role name. 

4192 

4193 Returns: 

4194 ``True`` if the user has the role. 

4195 """ 

4196 

4197 def acquire(self, uid: str = None, classref: Optional[ClassRef] = None, access: Optional[Access] = None) -> Optional[Object]: 

4198 """Get an object by uid, if the user can access it. 

4199 

4200 Args: 

4201 uid: Object uid. 

4202 classref: Class reference. If provided, the object must match it. 

4203 access: Access mode, ``Access.read`` if omitted. 

4204 

4205 Returns: 

4206 The object, or ``None`` if it does not exist or the user may not access it. 

4207 """ 

4208 

4209 def require(self, uid: str = None, classref: Optional[ClassRef] = None, access: Optional[Access] = None) -> Object: 

4210 """Get an object by uid and fail if it is not found or not accessible. 

4211 

4212 Args: 

4213 uid: Object uid. 

4214 classref: Class reference. If provided, the object must match it. 

4215 access: Access mode, ``Access.read`` if omitted. 

4216 

4217 Returns: 

4218 The object. 

4219 

4220 Raises: 

4221 NotFoundError: If the object does not exist. 

4222 ForbiddenError: If the user may not access the object. 

4223 """ 

4224 

4225 def require_project(self, uid: str = None) -> 'Project': 

4226 """Get a project the user can read. 

4227 

4228 Args: 

4229 uid: Project uid. 

4230 

4231 Returns: 

4232 The project. 

4233 

4234 Raises: 

4235 NotFoundError: If the project does not exist. 

4236 ForbiddenError: If the user may not read the project. 

4237 """ 

4238 

4239 def require_layer(self, uid=None) -> 'Layer': 

4240 """Get a layer the user can read. 

4241 

4242 Args: 

4243 uid: Layer uid. 

4244 

4245 Returns: 

4246 The layer. 

4247 

4248 Raises: 

4249 NotFoundError: If the layer does not exist. 

4250 ForbiddenError: If the user may not read the layer. 

4251 """ 

4252 

4253 

4254class AuthManager(Node): 

4255 """Authorization manager. 

4256 

4257 Holds the authentication methods, providers, multi-factor adapters and the 

4258 session manager, authenticates users and opens a session for every web request. 

4259 """ 

4260 

4261 guestSession: 'AuthSession' 

4262 """Session of the guest user, used for requests without a session.""" 

4263 

4264 guestUser: 'User' 

4265 """The guest user.""" 

4266 systemUser: 'User' 

4267 """The system user, allowed everything.""" 

4268 

4269 providers: list['AuthProvider'] 

4270 """Authentication providers.""" 

4271 methods: list['AuthMethod'] 

4272 """Authentication methods.""" 

4273 mfAdapters: list['AuthMultiFactorAdapter'] 

4274 """Multi-factor adapters.""" 

4275 

4276 sessionMgr: 'AuthSessionManager' 

4277 """Session manager.""" 

4278 

4279 def authenticate(self, method: 'AuthMethod', credentials: Data, req: 'WebRequester') -> Optional['User']: 

4280 """Authenticate a user with the providers that allow the method. 

4281 

4282 Args: 

4283 method: The authentication method. 

4284 credentials: The credentials, for example ``username`` and ``password``. 

4285 req: The web request. 

4286 

4287 Returns: 

4288 The user, or ``None`` if no provider accepts the credentials. 

4289 

4290 Raises: 

4291 ForbiddenError: If a provider rejects the credentials. 

4292 TooManyRequestsError: If the attempt is blocked by the throttle. 

4293 """ 

4294 

4295 def create_transient_session(self, method: 'AuthMethod', user: 'User', data: Optional[dict] = None) -> 'AuthSession': 

4296 """Create a session that lives only for the duration of the request. 

4297 

4298 The session is not stored in the session manager. 

4299 

4300 Args: 

4301 method: The method that creates the session. 

4302 user: The session user. 

4303 data: Session data. 

4304 

4305 Returns: 

4306 A new session. 

4307 """ 

4308 

4309 def get_user(self, user_uid: str) -> Optional['User']: 

4310 """Get a user by its global uid. 

4311 

4312 Args: 

4313 user_uid: Global user uid. 

4314 

4315 Returns: 

4316 The user, or ``None`` if the provider is not found or does not return the user. 

4317 """ 

4318 

4319 def add_provider(self, provider: 'AuthProvider'): 

4320 """Add an authentication provider. 

4321 

4322 Args: 

4323 provider: The provider. 

4324 """ 

4325 

4326 def add_method(self, method: 'AuthMethod'): 

4327 """Add an authentication method. 

4328 

4329 Args: 

4330 method: The method. 

4331 """ 

4332 

4333 def add_multi_factor_adapter(self, adapter: 'AuthMultiFactorAdapter'): 

4334 """Add a multi-factor adapter. 

4335 

4336 Args: 

4337 adapter: The adapter. 

4338 """ 

4339 

4340 def can_use_method(self, req: 'WebRequester', method: 'AuthMethod') -> bool: 

4341 """Check if a method may be used for a request. 

4342 

4343 A secure method can only be used on secure requests, or from the addresses 

4344 listed in its ``allowInsecureFrom``. 

4345 

4346 Args: 

4347 req: The web request. 

4348 method: The method. 

4349 

4350 Returns: 

4351 ``True`` if the method may be used. 

4352 """ 

4353 

4354 def get_provider(self, uid: str) -> Optional['AuthProvider']: 

4355 """Get an authentication provider by its uid. 

4356 

4357 Args: 

4358 uid: Provider uid. 

4359 

4360 Returns: 

4361 The provider, or ``None`` if not found. 

4362 """ 

4363 

4364 def get_method(self, uid: str) -> Optional['AuthMethod']: 

4365 """Get an authentication method by its uid. 

4366 

4367 Args: 

4368 uid: Method uid. 

4369 

4370 Returns: 

4371 The method, or ``None`` if not found. 

4372 """ 

4373 

4374 def get_multi_factor_adapter(self, uid: str) -> Optional['AuthMultiFactorAdapter']: 

4375 """Get a multi-factor adapter by its uid. 

4376 

4377 Args: 

4378 uid: Adapter uid. 

4379 

4380 Returns: 

4381 The adapter, or ``None`` if not found. 

4382 """ 

4383 

4384 def serialize_user(self, user: 'User') -> str: 

4385 """Serialize a user to a string, together with its provider uid. 

4386 

4387 Args: 

4388 user: The user. 

4389 

4390 Returns: 

4391 A JSON string. 

4392 """ 

4393 

4394 def unserialize_user(self, ser: str) -> Optional['User']: 

4395 """Restore a user serialized by ``serialize_user``. 

4396 

4397 Args: 

4398 ser: The serialized user. 

4399 

4400 Returns: 

4401 The user, or ``None`` if the provider is not found. 

4402 """ 

4403 

4404 def is_public_object(self, obj: Object, *context) -> bool: 

4405 """Check if the guest user can read an object. 

4406 

4407 Args: 

4408 obj: The object. 

4409 *context: Further objects to check, before the parents. 

4410 

4411 Returns: 

4412 ``True`` if the object is public. 

4413 """ 

4414 

4415 

4416class AuthMethod(Node): 

4417 """Authentication method. 

4418 

4419 Defines how credentials and sessions are passed between the client and the 

4420 server, for example as a login form and a session cookie. 

4421 """ 

4422 

4423 secure: bool 

4424 """The method may only be used on secure (HTTPS) requests.""" 

4425 

4426 allowInsecureFrom: list[str] 

4427 """IP addresses from which the method may be used without HTTPS.""" 

4428 

4429 def open_session(self, req: 'WebRequester') -> Optional['AuthSession']: 

4430 """Try to open a session for a request. 

4431 

4432 Called at the start of every web request. 

4433 

4434 Args: 

4435 req: The web request. 

4436 

4437 Returns: 

4438 A session, or ``None`` if the request has no session for this method. 

4439 """ 

4440 

4441 def close_session(self, req: 'WebRequester', res: 'WebResponder') -> None: 

4442 """Close the session of a request. 

4443 

4444 Called at the end of every web request whose session was opened by this 

4445 method, for example to set or delete the session cookie. 

4446 

4447 Args: 

4448 req: The web request. 

4449 res: The web response. 

4450 """ 

4451 

4452 

4453class AuthMultiFactorState(Enum): 

4454 """State of a multi-factor authentication transaction.""" 

4455 

4456 open = 'open' 

4457 """The transaction is started and waits for verification.""" 

4458 ok = 'ok' 

4459 """The verification was successful.""" 

4460 retry = 'retry' 

4461 """The verification failed and can be retried.""" 

4462 failed = 'failed' 

4463 """The transaction failed.""" 

4464 

4465 

4466class AuthMultiFactorTransaction(Data): 

4467 """Multi-factor authentication transaction. 

4468 

4469 Kept in the user's session from the login until the verification succeeds, 

4470 fails or expires. 

4471 """ 

4472 

4473 state: AuthMultiFactorState 

4474 """Current state.""" 

4475 restartCount: int 

4476 """Number of restarts.""" 

4477 verifyCount: int 

4478 """Number of verification attempts.""" 

4479 secret: str 

4480 """Secret for code generation.""" 

4481 startTime: int 

4482 """Start time, as a Unix timestamp.""" 

4483 generateTime: int 

4484 """Time when the code was last generated, as a Unix timestamp.""" 

4485 message: str 

4486 """Message shown to the user.""" 

4487 adapter: 'AuthMultiFactorAdapter' 

4488 """The adapter handling the transaction.""" 

4489 user: 'User' 

4490 """The user who logs in.""" 

4491 

4492 

4493class AuthMultiFactorAdapter(Node): 

4494 """Multi-factor authentication adapter. 

4495 

4496 Provides the second verification step of a login, for example a code sent by 

4497 email or generated by an authenticator app. 

4498 """ 

4499 

4500 message: str 

4501 """Message shown to the user during the verification step.""" 

4502 lifeTime: int 

4503 """Time in seconds allowed to complete the verification.""" 

4504 maxRestarts: int 

4505 """How often a transaction can be restarted.""" 

4506 maxVerifyAttempts: int 

4507 """Number of verification attempts allowed.""" 

4508 

4509 def start(self, user: 'User') -> Optional[AuthMultiFactorTransaction]: 

4510 """Start a transaction for a user. 

4511 

4512 Args: 

4513 user: The user who logs in. 

4514 

4515 Returns: 

4516 A new transaction, or ``None`` if the adapter cannot be used for this 

4517 user, for example because a required user attribute is missing. 

4518 """ 

4519 

4520 def verify(self, mfa: AuthMultiFactorTransaction, payload: dict) -> AuthMultiFactorTransaction: 

4521 """Verify a payload submitted by the user. 

4522 

4523 Args: 

4524 mfa: The transaction. 

4525 payload: The payload, for example ``{'code': '123456'}``. 

4526 

4527 Returns: 

4528 The transaction with an updated state. 

4529 """ 

4530 

4531 def check_state(self, mfa: AuthMultiFactorTransaction) -> bool: 

4532 """Check if a transaction is still valid, and mark it failed if not. 

4533 

4534 Args: 

4535 mfa: The transaction. 

4536 

4537 Returns: 

4538 ``True`` if the transaction is valid. 

4539 """ 

4540 

4541 def check_restart(self, mfa: AuthMultiFactorTransaction) -> bool: 

4542 """Check if a transaction can be restarted. 

4543 

4544 Args: 

4545 mfa: The transaction. 

4546 

4547 Returns: 

4548 ``True`` if a restart is allowed. 

4549 """ 

4550 

4551 def restart(self, mfa: AuthMultiFactorTransaction) -> Optional[AuthMultiFactorTransaction]: 

4552 """Restart a transaction, for example by sending a new code. 

4553 

4554 Args: 

4555 mfa: The transaction. 

4556 

4557 Returns: 

4558 A new transaction, or ``None`` if a restart is not possible. 

4559 """ 

4560 

4561 def key_uri(self, secret: str | bytes, issuer_name: str, account_name: str) -> Optional[str]: 

4562 """Generate a key URI for authenticator apps. 

4563 

4564 Args: 

4565 secret: The user's secret. 

4566 issuer_name: Issuer name shown in the app. 

4567 account_name: Account name shown in the app. 

4568 

4569 Returns: 

4570 An ``otpauth://`` URI, or ``None`` if the adapter does not support it. 

4571 """ 

4572 

4573 

4574class AuthProvider(Node): 

4575 """Authentication provider. 

4576 

4577 A source of users, for example a file, an LDAP directory or a database table, 

4578 which verifies credentials. 

4579 """ 

4580 

4581 allowedMethods: list[str] 

4582 """Method types this provider accepts, all methods if empty.""" 

4583 

4584 def get_user(self, local_uid: str) -> Optional['User']: 

4585 """Get a user by its local uid. 

4586 

4587 Args: 

4588 local_uid: User uid within the provider. 

4589 

4590 Returns: 

4591 The user, or ``None`` if not found. 

4592 """ 

4593 

4594 def authenticate(self, method: 'AuthMethod', credentials: Data) -> Optional['User']: 

4595 """Authenticate a user. 

4596 

4597 Args: 

4598 method: The authentication method. 

4599 credentials: The credentials, for example ``username`` and ``password``. 

4600 

4601 Returns: 

4602 The user, or ``None`` if the provider does not know the user. 

4603 

4604 Raises: 

4605 AuthenticationError: If the credentials are wrong or match more than one user. 

4606 """ 

4607 

4608 def serialize_user(self, user: 'User') -> str: 

4609 """Serialize a user to a string. 

4610 

4611 Args: 

4612 user: The user. 

4613 

4614 Returns: 

4615 The serialized user. 

4616 """ 

4617 

4618 def unserialize_user(self, ser: str) -> Optional['User']: 

4619 """Restore a user serialized by ``serialize_user``. 

4620 

4621 Args: 

4622 ser: The serialized user. 

4623 

4624 Returns: 

4625 The user, or ``None`` if it cannot be restored. 

4626 """ 

4627 

4628 

4629class AuthSession: 

4630 """Authentication session. 

4631 

4632 Holds the user and arbitrary data between requests. 

4633 """ 

4634 

4635 uid: str 

4636 """Session uid.""" 

4637 method: Optional['AuthMethod'] 

4638 """The method that created the session, ``None`` for the guest session.""" 

4639 user: 'User' 

4640 """The session user.""" 

4641 data: dict 

4642 """Session data.""" 

4643 created: 'datetime.datetime' 

4644 """Creation time.""" 

4645 updated: 'datetime.datetime' 

4646 """Last update time.""" 

4647 isChanged: bool 

4648 """The session data has changed since the session was loaded.""" 

4649 isTransient: bool 

4650 """The session lives only for the duration of the request and is not stored.""" 

4651 

4652 def get(self, key: str, default=None): 

4653 """Get a session data value. 

4654 

4655 Args: 

4656 key: Value name. 

4657 default: Default value. 

4658 

4659 Returns: 

4660 The value, or the default if it is not set. 

4661 """ 

4662 

4663 def set(self, key: str, value): 

4664 """Set a session data value and mark the session as changed. 

4665 

4666 Args: 

4667 key: Value name. 

4668 value: The value. 

4669 """ 

4670 

4671 

4672class AuthSessionManager(Node): 

4673 """Authentication session manager. 

4674 

4675 Stores sessions persistently. A session is valid until ``lifeTime`` has passed 

4676 since its last update, or ``maxLifeTime`` since its creation. 

4677 """ 

4678 

4679 lifeTime: int 

4680 """Session life time in seconds, counted from the last update.""" 

4681 

4682 maxLifeTime: int 

4683 """Absolute session life time in seconds, counted from the creation, or 0 if not limited.""" 

4684 

4685 def create(self, method: 'AuthMethod', user: 'User', data: Optional[dict] = None) -> 'AuthSession': 

4686 """Create and store a new session. 

4687 

4688 Args: 

4689 method: The method that creates the session. 

4690 user: The session user. 

4691 data: Session data. 

4692 

4693 Returns: 

4694 The new session. 

4695 """ 

4696 

4697 def delete(self, sess: 'AuthSession'): 

4698 """Delete a session. 

4699 

4700 Args: 

4701 sess: The session. 

4702 """ 

4703 

4704 def delete_all(self): 

4705 """Delete all sessions.""" 

4706 

4707 def get(self, uid: str) -> Optional['AuthSession']: 

4708 """Get a valid session by its uid. 

4709 

4710 Args: 

4711 uid: Session uid. 

4712 

4713 Returns: 

4714 The session, or ``None`` if it does not exist or has expired. 

4715 """ 

4716 

4717 def list_all(self) -> list['AuthSession']: 

4718 """Get all stored sessions. 

4719 

4720 Returns: 

4721 A list of sessions. 

4722 """ 

4723 

4724 def save(self, sess: 'AuthSession'): 

4725 """Save the session data. 

4726 

4727 Args: 

4728 sess: The session. 

4729 """ 

4730 

4731 def touch(self, sess: 'AuthSession'): 

4732 """Update the last activity time of a session. 

4733 

4734 Args: 

4735 sess: The session. 

4736 """ 

4737 

4738 def cleanup(self): 

4739 """Remove expired sessions from the storage.""" 

4740################################################################################ 

4741 

4742 

4743 

4744################################################################################ 

4745# /base/layer/types.pyinc 

4746 

4747 

4748class LayerDisplayMode(Enum): 

4749 """How a layer is rendered.""" 

4750 

4751 box = 'box' 

4752 """Render the map view as a single image.""" 

4753 tile = 'tile' 

4754 """Render the layer as tiles of a grid.""" 

4755 client = 'client' 

4756 """Let the client render the layer from its source.""" 

4757 

4758 

4759class FeatureLoadingStrategy(Enum): 

4760 """When the client loads a layer's features.""" 

4761 

4762 all = 'all' 

4763 """Load all features once, on first display.""" 

4764 bbox = 'bbox' 

4765 """Reload features for the current map extent whenever it changes.""" 

4766 lazy = 'lazy' 

4767 """Load features only when a search text is entered.""" 

4768 

4769 

4770class LayerOwsBinding(Node): 

4771 """Binding of a layer to OWS services: access, names and models.""" 

4772 

4773 allowedServiceUids: list[str] 

4774 """UIDs of services which can use this layer; empty means any.""" 

4775 deniedServiceUids: list[str] 

4776 """UIDs of services which can not use this layer.""" 

4777 featureName: str 

4778 """Name for features in this layer.""" 

4779 geometryName: str 

4780 """Name for geometries in this layer.""" 

4781 layerName: str 

4782 """Name for this layer in OWS services.""" 

4783 models: list['Model'] 

4784 """OWS-specific models.""" 

4785 xmlNamespace: Optional['XmlNamespace'] 

4786 """XML namespace for feature and layer names.""" 

4787 

4788 

4789class Layer(Node): 

4790 """Layer object.""" 

4791 

4792 bounds: Bounds 

4793 """Bounds in the map CRS: the WGS extent clipped to the parent extent and to the CRS.""" 

4794 canRenderBox: bool 

4795 """The layer can render a single image for an arbitrary extent.""" 

4796 canRenderInClient: bool 

4797 """The layer can be drawn by the client directly from its source (``display: client``).""" 

4798 canRenderSvg: bool 

4799 """The layer can render its features as SVG.""" 

4800 canRenderTile: bool 

4801 """The layer can render tiles in a fixed grid.""" 

4802 cssSelector: str 

4803 """CSS selector for feature styling.""" 

4804 displayMode: LayerDisplayMode 

4805 """How the client displays the layer.""" 

4806 finders: list['Finder'] 

4807 """Search providers.""" 

4808 grabbers: dict[int, 'Grabber'] 

4809 """Grabbers by CRS code, one for each CRS the application supports.""" 

4810 hasLegend: bool 

4811 """The layer has a legend.""" 

4812 imageFormat: ImageFormat 

4813 """Image format for box and tile rendering.""" 

4814 isEnabledForOws: bool 

4815 """The layer can be used by OWS services.""" 

4816 isGroup: bool 

4817 """The layer is a group of other layers.""" 

4818 isSearchable: bool 

4819 """The layer has at least one search provider.""" 

4820 layers: list['Layer'] 

4821 """Child layers.""" 

4822 legend: Optional['Legend'] 

4823 """Legend object.""" 

4824 loadingStrategy: FeatureLoadingStrategy 

4825 """How the client loads features.""" 

4826 mapCrs: 'Crs' 

4827 """CRS of the map this layer belongs to.""" 

4828 metadata: 'Metadata' 

4829 """Layer metadata.""" 

4830 models: list['Model'] 

4831 """Data models.""" 

4832 opacity: float 

4833 """Layer opacity, 0 to 1.""" 

4834 ows: 'LayerOwsBinding' 

4835 """Binding to OWS services.""" 

4836 resolutions: list[float] 

4837 """Resolutions the layer is visible at, in map units per pixel.""" 

4838 sourceLayers: list['SourceLayer'] 

4839 """Source layers this layer is built from.""" 

4840 templates: list['Template'] 

4841 """Layer templates.""" 

4842 title: str 

4843 """Layer title.""" 

4844 wgsExtent: Extent 

4845 """Layer extent in WGS84.""" 

4846 zoomBounds: Bounds 

4847 """Bounds the client zooms to for this layer; defaults to ``bounds``.""" 

4848 

4849 def find_features(self, search: 'SearchQuery', user: 'User') -> list['Feature']: 

4850 """Find features in the layer. 

4851 

4852 Vector layers search in the first model the user can read; other 

4853 layers return an empty list. 

4854 

4855 Args: 

4856 search: Search query. 

4857 user: The user who searches. 

4858 

4859 Returns: 

4860 Found features. 

4861 """ 

4862 

4863 def render(self, lri: LayerRenderInput) -> Optional['LayerRenderOutput']: 

4864 """Render a box, a tile or an SVG fragment, depending on the input type. 

4865 

4866 Args: 

4867 lri: Render input. 

4868 

4869 Returns: 

4870 Render output with image content or SVG tags, or ``None`` if the 

4871 layer has nothing to render. 

4872 """ 

4873 

4874 def render_legend(self, args: Optional[dict | Data] = None) -> Optional['LegendRenderOutput']: 

4875 """Render the layer legend. 

4876 

4877 Without ``args`` the output is cached for the server lifetime. 

4878 

4879 Args: 

4880 args: Arguments passed to the legend renderer. 

4881 

4882 Returns: 

4883 Legend output, or ``None`` if the layer has no legend. 

4884 """ 

4885 

4886 def url_path_for(self, kind: str) -> str: 

4887 """Return the URL path for requests to this layer. 

4888 

4889 Args: 

4890 kind: ``box``, ``tile``, ``legend`` or ``features``. The ``tile`` 

4891 path contains ``{z}``, ``{x}`` and ``{y}`` placeholders. 

4892 

4893 Returns: 

4894 URL path. 

4895 

4896 Raises: 

4897 ``gws.Error``: If ``kind`` is not recognized. 

4898 """ 

4899################################################################################ 

4900 

4901 

4902################################################################################ 

4903# /base/grabber/types.pyinc 

4904 

4905 

4906class Grabber: 

4907 """Raster grabber. 

4908 

4909 Provides raster images for a layer: fetches them from a source, aligns them to a 

4910 tile grid, stores and reads them back. 

4911 """ 

4912 

4913 cache: MapCache 

4914 """Cache settings; the name (``<layer cache name>_<srid>``) keys the tile store.""" 

4915 extent: Extent 

4916 """Extent covered by this grabber, in the target CRS.""" 

4917 grid: MapGrid 

4918 """The fixed target grid for the CRS.""" 

4919 imageFormat: ImageFormat 

4920 """Format tiles are stored and returned in.""" 

4921 sourceCrs: Crs 

4922 """Source CRS; defines the original CRS of the raster data.""" 

4923 store: 'TileStore' 

4924 """Persistent tile store.""" 

4925 targetCrs: Crs 

4926 """Target CRS; one grabber serves exactly one CRS.""" 

4927 

4928 def get_tile_as_bytes(self, mt: MapTile, params: Optional[dict] = None) -> bytes: 

4929 """Return a single tile as an encoded image, composing and storing it if needed. 

4930 

4931 A tile outside the layer's range is a transparent image. 

4932 

4933 Args: 

4934 mt: Tile. 

4935 params: Dynamic request parameters. With ``params``, the persistent store is bypassed. 

4936 

4937 Returns: 

4938 The encoded tile. 

4939 

4940 Raises: 

4941 ``Exception``: Errors of the source request are passed through. 

4942 """ 

4943 

4944 def get_tile_as_image(self, mt: MapTile, params: Optional[dict] = None) -> 'Image': 

4945 """Return a single tile as an image, composing and storing it if needed. 

4946 

4947 Same contract as ``get_tile_as_bytes``, decoded pixels instead of bytes. 

4948 

4949 Args: 

4950 mt: Tile. 

4951 params: Dynamic request parameters. With ``params``, the persistent store is bypassed. 

4952 

4953 Returns: 

4954 The tile image. 

4955 

4956 Raises: 

4957 ``Exception``: Errors of the source request are passed through. 

4958 """ 

4959 

4960 def get_tiles_as_bytes_dict(self, mtr: MapTileRange, params: Optional[dict] = None) -> dict[MapTile, bytes]: 

4961 """Return a rectangular block of tiles as encoded images. 

4962 

4963 Args: 

4964 mtr: Tile range. 

4965 params: Dynamic request parameters. With ``params``, the persistent store is bypassed. 

4966 

4967 Returns: 

4968 Encoded tiles, keyed by tile. Sparse: contains entries only for tiles present in the grid. 

4969 

4970 Raises: 

4971 ``Exception``: Errors of the source request are passed through. 

4972 """ 

4973 

4974 def get_tiles_as_image_dict(self, mtr: MapTileRange, params: Optional[dict] = None) -> dict[MapTile, 'Image']: 

4975 """Return a rectangular block of tiles as images. 

4976 

4977 Same contract as ``get_tiles_as_bytes_dict``, decoded pixels instead of bytes. 

4978 

4979 Args: 

4980 mtr: Tile range. 

4981 params: Dynamic request parameters. With ``params``, the persistent store is bypassed. 

4982 

4983 Returns: 

4984 Tile images, keyed by tile. 

4985 

4986 Raises: 

4987 ``Exception``: Errors of the source request are passed through. 

4988 """ 

4989 

4990 def get_box_as_bytes(self, extent: Extent, w: int, h: int, params: Optional[dict] = None) -> bytes: 

4991 """Return an encoded image for arbitrary extent and pixel size. 

4992 

4993 A box overlapping no data is a transparent image. 

4994 

4995 Args: 

4996 extent: Extent in the target CRS. 

4997 w: Width in pixels. 

4998 h: Height in pixels. 

4999 params: Dynamic request parameters. With ``params``, the persistent store is bypassed. 

5000 

5001 Returns: 

5002 The encoded image. 

5003 

5004 Raises: 

5005 ``Exception``: Errors of the source request are passed through. 

5006 """ 

5007 

5008 def get_box_as_image(self, extent: Extent, w: int, h: int, params: Optional[dict] = None) -> 'Image': 

5009 """Return an image for arbitrary extent and pixel size. 

5010 

5011 Same contract as ``get_box_as_bytes``, decoded pixels instead of bytes. 

5012 

5013 Args: 

5014 extent: Extent in the target CRS. 

5015 w: Width in pixels. 

5016 h: Height in pixels. 

5017 params: Dynamic request parameters. With ``params``, the persistent store is bypassed. 

5018 

5019 Returns: 

5020 The image. 

5021 

5022 Raises: 

5023 ``Exception``: Errors of the source request are passed through. 

5024 """ 

5025 

5026 def levels(self) -> list[int]: 

5027 """Return the levels this grabber supports. 

5028 

5029 Returns: 

5030 A list of levels. 

5031 """ 

5032 

5033 def tile_range_for_level(self, z: int) -> MapTileRange: 

5034 """Return the tile range covered by the grabber's extent at a level. 

5035 

5036 Args: 

5037 z: Level. 

5038 

5039 Returns: 

5040 The tile range in the grabber's grid. 

5041 """ 

5042################################################################################ 

5043 

5044 

5045################################################################################ 

5046# /base/legend/types.pyinc 

5047 

5048 

5049class LegendRenderOutput(Data): 

5050 """Legend render output.""" 

5051 

5052 html: str 

5053 """HTML representation of the legend; not set by the built-in legend types.""" 

5054 image: 'Image' 

5055 """Legend image.""" 

5056 size: Size 

5057 """Size of the legend image in pixels.""" 

5058 

5059 

5060class Legend(Node): 

5061 """Legend object.""" 

5062 

5063 def render(self, args: Optional[dict | Data] = None) -> Optional[LegendRenderOutput]: 

5064 """Render the legend. 

5065 

5066 Args: 

5067 args: Arguments for the renderer, for example template arguments. 

5068 

5069 Returns: 

5070 Legend output, or ``None`` if there is nothing to show. 

5071 """ 

5072################################################################################ 

5073 

5074 

5075################################################################################ 

5076# /base/map/types.pyinc 

5077 

5078 

5079class Map(Node): 

5080 """Map object.""" 

5081 

5082 rootLayer: 'Layer' 

5083 """Root group layer that holds the map layers.""" 

5084 

5085 bounds: Bounds 

5086 """Map extent in the map CRS.""" 

5087 center: Point 

5088 """Initial map center.""" 

5089 coordinatePrecision: int 

5090 """Decimal places for coordinates.""" 

5091 initResolution: float 

5092 """Initial resolution.""" 

5093 resolutions: list[float] 

5094 """Resolutions the map can be displayed at, in map units per pixel.""" 

5095 title: str 

5096 """Map title.""" 

5097 wgsExtent: Extent 

5098 """Map extent in WGS84.""" 

5099################################################################################ 

5100 

5101 

5102 

5103################################################################################ 

5104# /base/model/types.pyinc 

5105 

5106 

5107class ModelClientOptions(Data): 

5108 """Client options for a model.""" 

5109 

5110 keepFormOpen: Optional[bool] 

5111 """Keep the edit form open after saving.""" 

5112 

5113 

5114class ModelValidationError(Data): 

5115 """Validation error of a feature field.""" 

5116 

5117 fieldName: str 

5118 """Name of the field that failed validation.""" 

5119 message: str 

5120 """Error message, or a message key for the client.""" 

5121 

5122 

5123class ModelOperation(Enum): 

5124 """Model operation.""" 

5125 

5126 read = 'read' 

5127 """Read features.""" 

5128 create = 'create' 

5129 """Create new features.""" 

5130 update = 'update' 

5131 """Update existing features.""" 

5132 delete = 'delete' 

5133 """Delete features.""" 

5134 export = 'export' 

5135 """Export features.""" 

5136 

5137 

5138class ModelReadTarget(Enum): 

5139 """Target for the read operation.""" 

5140 

5141 map = 'map' 

5142 """The feature is to be drawn on a map.""" 

5143 searchResults = 'searchResults' 

5144 """The feature is to be displayed in the search results list.""" 

5145 list = 'list' 

5146 """The feature is to be displayed in a list view.""" 

5147 editList = 'editList' 

5148 """The feature is to be displayed in an editable list view.""" 

5149 editForm = 'editForm' 

5150 """The feature is to be displayed in an edit form.""" 

5151 

5152 

5153class ModelSelectBuild(Data): 

5154 """Parts of a database select statement, collected from the model fields.""" 

5155 

5156 columns: list['sqlalchemy.Column'] 

5157 """Columns to select.""" 

5158 geometryWhere: list 

5159 """Conditions for the geometry search, combined with OR.""" 

5160 keywordWhere: list 

5161 """Conditions for the keyword search, combined with OR.""" 

5162 where: list 

5163 """Other conditions, combined with AND.""" 

5164 order: list 

5165 """Sort expressions.""" 

5166 

5167 

5168class ModelContext(Data): 

5169 """Context of a model operation.""" 

5170 

5171 op: ModelOperation 

5172 """The operation.""" 

5173 target: ModelReadTarget 

5174 """Where the features are to be displayed, for read operations.""" 

5175 user: 'User' 

5176 """The user performing the operation.""" 

5177 project: Optional['Project'] 

5178 """The current project.""" 

5179 relDepth: int = 0 

5180 """Current depth of related features.""" 

5181 maxDepth: int = 0 

5182 """Maximum depth of related features to process.""" 

5183 search: 'SearchQuery' 

5184 """The search query, for read operations.""" 

5185 dbSelect: ModelSelectBuild 

5186 """The select statement being built, for database read operations.""" 

5187 

5188 

5189EmptyValue = object() 

5190"""Special value for empty fields.""" 

5191 

5192ErrorValue = object() 

5193"""Special value for invalid fields.""" 

5194 

5195 

5196class ModelWidget(Node): 

5197 """Model widget. 

5198 

5199 Describes how the client displays and edits a field value. 

5200 """ 

5201 

5202 supportsTableView: bool = True 

5203 """The widget can be used in the table view.""" 

5204 

5205 

5206class ModelValidator(Node): 

5207 """Model validator. 

5208 

5209 Checks the value of a field. 

5210 """ 

5211 

5212 message: str 

5213 """Error message, or a message key for the client.""" 

5214 ops: set[ModelOperation] 

5215 """Operations the validator applies to.""" 

5216 

5217 def validate(self, field: 'ModelField', feature: 'Feature', mc: ModelContext) -> bool: 

5218 """Check the value of a field in a feature. 

5219 

5220 Args: 

5221 field: The field. 

5222 feature: The feature. 

5223 mc: The model context. 

5224 

5225 Returns: 

5226 True if the value is valid. 

5227 """ 

5228 

5229 

5230class ModelValue(Node): 

5231 """Model value. 

5232 

5233 Computes a value for a field. 

5234 """ 

5235 

5236 isDefault: bool 

5237 """The value is used only when the source provides no value.""" 

5238 ops: set[ModelOperation] 

5239 """Operations the value applies to.""" 

5240 

5241 def compute(self, field: 'ModelField', feature: 'Feature', mc: 'ModelContext'): 

5242 """Compute the value of a field. 

5243 

5244 Args: 

5245 field: The field. 

5246 feature: The feature. 

5247 mc: The model context. 

5248 

5249 Returns: 

5250 The computed value. 

5251 """ 

5252 

5253 

5254class ModelField(Node): 

5255 """Model field. 

5256 

5257 Handles a subset of feature data. The model calls the field methods when it performs 

5258 an operation; the methods read and write ``feature.attributes``, ``feature.record`` 

5259 and ``feature.props``. 

5260 """ 

5261 

5262 name: str 

5263 """Field name.""" 

5264 title: str 

5265 """Field title.""" 

5266 

5267 attributeType: AttributeType 

5268 """Type of the field value.""" 

5269 

5270 widget: Optional['ModelWidget'] = None 

5271 """Widget for the client.""" 

5272 

5273 values: list['ModelValue'] 

5274 """Value objects.""" 

5275 validators: list['ModelValidator'] 

5276 """Validators.""" 

5277 

5278 isPrimaryKey: bool 

5279 """The field is a primary key.""" 

5280 isRequired: bool 

5281 """The field must not be empty.""" 

5282 isUnique: bool 

5283 """The field is unique.""" 

5284 isAuto: bool 

5285 """The value is set by the database and never written.""" 

5286 isHidden: bool 

5287 """The field is not automatically displayed in the client.""" 

5288 

5289 supportsFilterSearch: bool = False 

5290 """The field supports filter search.""" 

5291 supportsGeometrySearch: bool = False 

5292 """The field supports geometry search.""" 

5293 supportsKeywordSearch: bool = False 

5294 """The field supports keyword search.""" 

5295 

5296 model: 'Model' 

5297 """The model of the field.""" 

5298 

5299 def before_select(self, mc: ModelContext): 

5300 """Called before features are selected, adds columns and conditions to ``mc.dbSelect``. 

5301 

5302 Args: 

5303 mc: The model context. 

5304 """ 

5305 

5306 def after_select(self, features: list['Feature'], mc: ModelContext): 

5307 """Called after features are selected, sets the field value in the features. 

5308 

5309 Args: 

5310 features: The selected features. 

5311 mc: The model context. 

5312 """ 

5313 

5314 def before_create(self, feature: 'Feature', mc: ModelContext): 

5315 """Called before a feature is inserted, writes the field value to ``feature.record``. 

5316 

5317 Args: 

5318 feature: The feature. 

5319 mc: The model context. 

5320 """ 

5321 

5322 def after_create(self, feature: 'Feature', mc: ModelContext): 

5323 """Called after a feature is inserted. 

5324 

5325 Args: 

5326 feature: The feature. 

5327 mc: The model context. 

5328 """ 

5329 

5330 def before_create_related(self, dst_feature: 'Feature', mc: ModelContext): 

5331 """Called before a feature of another model, created together with features of this model, is inserted. 

5332 

5333 Args: 

5334 dst_feature: The feature being created. 

5335 mc: The model context. 

5336 """ 

5337 

5338 def after_create_related(self, dst_feature: 'Feature', mc: ModelContext): 

5339 """Called after a feature of another model, created together with features of this model, is inserted. 

5340 

5341 Args: 

5342 dst_feature: The created feature. 

5343 mc: The model context. 

5344 """ 

5345 

5346 def before_update(self, feature: 'Feature', mc: ModelContext): 

5347 """Called before a feature is updated, writes the field value to ``feature.record``. 

5348 

5349 Args: 

5350 feature: The feature. 

5351 mc: The model context. 

5352 """ 

5353 

5354 def after_update(self, feature: 'Feature', mc: ModelContext): 

5355 """Called after a feature is updated. 

5356 

5357 Args: 

5358 feature: The feature. 

5359 mc: The model context. 

5360 """ 

5361 

5362 def before_delete(self, feature: 'Feature', mc: ModelContext): 

5363 """Called before a feature is deleted. 

5364 

5365 Args: 

5366 feature: The feature. 

5367 mc: The model context. 

5368 """ 

5369 

5370 def after_delete(self, feature: 'Feature', mc: ModelContext): 

5371 """Called after a feature is deleted. 

5372 

5373 Args: 

5374 feature: The feature. 

5375 mc: The model context. 

5376 """ 

5377 

5378 def do_init(self, feature: 'Feature', mc: ModelContext): 

5379 """Set the initial field value of a new feature. 

5380 

5381 Args: 

5382 feature: The feature. 

5383 mc: The model context. 

5384 """ 

5385 

5386 def do_init_related(self, dst_feature: 'Feature', mc: ModelContext): 

5387 """Initialize a new feature of another model that is created together with features of this model. 

5388 

5389 Args: 

5390 dst_feature: The new feature. 

5391 mc: The model context. 

5392 """ 

5393 

5394 def do_validate(self, feature: 'Feature', mc: ModelContext): 

5395 """Validate the field value and append errors to ``feature.errors``. 

5396 

5397 Args: 

5398 feature: The feature. 

5399 mc: The model context. 

5400 """ 

5401 

5402 def from_props(self, feature: 'Feature', mc: ModelContext): 

5403 """Set the field value from ``feature.props``. 

5404 

5405 Args: 

5406 feature: The feature. 

5407 mc: The model context. 

5408 """ 

5409 

5410 def to_props(self, feature: 'Feature', mc: ModelContext): 

5411 """Write the field value to ``feature.props``. 

5412 

5413 Args: 

5414 feature: The feature. 

5415 mc: The model context. 

5416 """ 

5417 

5418 def from_record(self, feature: 'Feature', mc: ModelContext): 

5419 """Set the field value from ``feature.record``. 

5420 

5421 Args: 

5422 feature: The feature. 

5423 mc: The model context. 

5424 """ 

5425 

5426 def to_record(self, feature: 'Feature', mc: ModelContext): 

5427 """Write the field value to ``feature.record``. 

5428 

5429 Args: 

5430 feature: The feature. 

5431 mc: The model context. 

5432 """ 

5433 

5434 def related_models(self) -> list['Model']: 

5435 """Return the models related to this field. 

5436 

5437 Returns: 

5438 A list of models, empty for fields that are not related fields. 

5439 """ 

5440 

5441 def find_relatable_features(self, search: 'SearchQuery', mc: ModelContext) -> list['Feature']: 

5442 """Find features that can be linked by this field. 

5443 

5444 Args: 

5445 search: The search query. 

5446 mc: The model context. 

5447 

5448 Returns: 

5449 The features found in the related models. 

5450 """ 

5451 

5452 def raw_to_python(self, feature: 'Feature', value, mc: ModelContext): 

5453 """Convert a raw source value to a python value. 

5454 

5455 Args: 

5456 feature: The feature. 

5457 value: The value to convert. 

5458 mc: The model context. 

5459 

5460 Returns: 

5461 The converted value. 

5462 """ 

5463 

5464 def prop_to_python(self, feature: 'Feature', value, mc: ModelContext): 

5465 """Convert a client props value to a python value. 

5466 

5467 Args: 

5468 feature: The feature. 

5469 value: The value to convert. 

5470 mc: The model context. 

5471 

5472 Returns: 

5473 The converted value. 

5474 """ 

5475 

5476 def python_to_raw(self, feature: 'Feature', value, mc: ModelContext): 

5477 """Convert a python value to a raw source value. 

5478 

5479 Args: 

5480 feature: The feature. 

5481 value: The value to convert. 

5482 mc: The model context. 

5483 

5484 Returns: 

5485 The converted value. 

5486 """ 

5487 

5488 def python_to_prop(self, feature: 'Feature', value, mc: ModelContext): 

5489 """Convert a python value to a client props value. 

5490 

5491 Args: 

5492 feature: The feature. 

5493 value: The value to convert. 

5494 mc: The model context. 

5495 

5496 Returns: 

5497 The converted value. 

5498 """ 

5499 

5500 def describe(self) -> Optional['ColumnDescription']: 

5501 """Return the description of the source column of this field. 

5502 

5503 Returns: 

5504 The column description, or None if the source has no such column. 

5505 """ 

5506 

5507 

5508class Model(Node): 

5509 """Data model. 

5510 

5511 Reads features from a source, converts them to and from client props and, 

5512 if editable, writes them back. 

5513 """ 

5514 

5515 clientOptions: ModelClientOptions 

5516 """Client options.""" 

5517 defaultSort: list['SearchSort'] 

5518 """Default sort order of features.""" 

5519 fields: list['ModelField'] 

5520 """Model fields.""" 

5521 geometryCrs: Optional['Crs'] 

5522 """CRS of the geometry field.""" 

5523 geometryName: str 

5524 """Name of the geometry field.""" 

5525 geometryType: Optional[GeometryType] 

5526 """Type of the geometry field.""" 

5527 isEditable: bool 

5528 """Features of this model can be edited.""" 

5529 loadingStrategy: 'FeatureLoadingStrategy' 

5530 """How the client loads features.""" 

5531 exportStrategy: 'FeatureExportStrategy' 

5532 """How features are obtained for export.""" 

5533 title: str 

5534 """Model title.""" 

5535 uidName: str 

5536 """Name of the uid (primary key) field.""" 

5537 withTableView: bool 

5538 """The table view of features is enabled in the client.""" 

5539 

5540 def find_features(self, search: 'SearchQuery', mc: ModelContext) -> list['Feature']: 

5541 """Find features matching a search query. 

5542 

5543 Args: 

5544 search: The search query. 

5545 mc: The model context. 

5546 

5547 Returns: 

5548 The features found. 

5549 """ 

5550 

5551 def get_features(self, uids: Iterable[str | int], mc: ModelContext) -> list['Feature']: 

5552 """Return features by uid. 

5553 

5554 Args: 

5555 uids: Feature uids. 

5556 mc: The model context. 

5557 

5558 Returns: 

5559 The features found, empty if no uids are given. 

5560 """ 

5561 

5562 def get_feature(self, uid: str | int, mc: ModelContext) -> Optional['Feature']: 

5563 """Return a feature by uid. 

5564 

5565 Args: 

5566 uid: The feature uid. 

5567 mc: The model context. 

5568 

5569 Returns: 

5570 The feature, or None if it is not found. 

5571 """ 

5572 

5573 def init_feature(self, feature: 'Feature', mc: ModelContext): 

5574 """Initialize a new feature with initial field values. 

5575 

5576 Args: 

5577 feature: The new feature. 

5578 mc: The model context. 

5579 

5580 Raises: 

5581 gws.ForbiddenError: If the user cannot create features of this model. 

5582 """ 

5583 

5584 def create_feature(self, feature: 'Feature', mc: ModelContext) -> FeatureUid: 

5585 """Insert a new feature into the source. 

5586 

5587 Args: 

5588 feature: The feature. 

5589 mc: The model context. 

5590 

5591 Returns: 

5592 The primary key of the inserted feature. 

5593 

5594 Raises: 

5595 gws.ForbiddenError: If the user cannot create features of this model. 

5596 """ 

5597 

5598 def update_feature(self, feature: 'Feature', mc: ModelContext) -> FeatureUid: 

5599 """Update an existing feature in the source. 

5600 

5601 Args: 

5602 feature: The feature. 

5603 mc: The model context. 

5604 

5605 Returns: 

5606 The uid of the feature. 

5607 

5608 Raises: 

5609 gws.ForbiddenError: If the user cannot write to this model. 

5610 """ 

5611 

5612 def delete_feature(self, feature: 'Feature', mc: ModelContext) -> FeatureUid: 

5613 """Delete a feature from the source. 

5614 

5615 Args: 

5616 feature: The feature. 

5617 mc: The model context. 

5618 

5619 Returns: 

5620 The uid of the feature. 

5621 

5622 Raises: 

5623 gws.ForbiddenError: If the user cannot delete features of this model. 

5624 """ 

5625 

5626 def validate_feature(self, feature: 'Feature', mc: ModelContext) -> bool: 

5627 """Validate a feature and store validation errors in ``feature.errors``. 

5628 

5629 Args: 

5630 feature: The feature. 

5631 mc: The model context. 

5632 

5633 Returns: 

5634 True if the feature has no errors. 

5635 """ 

5636 

5637 def feature_from_props(self, props: 'FeatureProps', mc: ModelContext) -> 'Feature': 

5638 """Create a feature from client props. 

5639 

5640 Args: 

5641 props: The feature props. 

5642 mc: The model context. 

5643 

5644 Returns: 

5645 A new feature. 

5646 """ 

5647 

5648 def feature_to_props(self, feature: 'Feature', mc: ModelContext) -> 'FeatureProps': 

5649 """Convert a feature to client props and store them in ``feature.props``. 

5650 

5651 Args: 

5652 feature: The feature. 

5653 mc: The model context. 

5654 

5655 Returns: 

5656 The feature props. 

5657 """ 

5658 

5659 def feature_to_view_props(self, feature: 'Feature', mc: ModelContext) -> 'FeatureProps': 

5660 """Convert a feature to client props for viewing, with a reduced set of attributes. 

5661 

5662 Args: 

5663 feature: The feature. 

5664 mc: The model context. 

5665 

5666 Returns: 

5667 The feature props. 

5668 """ 

5669 

5670 def describe(self) -> Optional['DataSetDescription']: 

5671 """Return the description of the model source. 

5672 

5673 Returns: 

5674 The dataset description, or None if the source cannot be described. 

5675 """ 

5676 

5677 def field(self, name: str) -> Optional['ModelField']: 

5678 """Return a field by name. 

5679 

5680 Args: 

5681 name: The field name. 

5682 

5683 Returns: 

5684 The field, or None if it is not found. 

5685 """ 

5686 

5687 def related_models(self) -> list['Model']: 

5688 """Return the models related to the fields of this model. 

5689 

5690 Returns: 

5691 A list of models without duplicates. 

5692 """ 

5693 

5694 

5695class ModelManager(Node): 

5696 """Model manager. 

5697 

5698 Looks up models and provides the default model. 

5699 """ 

5700 

5701 def get_model(self, uid: str, user: 'User' = None, access: Access = None) -> Optional['Model']: 

5702 """Return a model by uid. 

5703 

5704 Args: 

5705 uid: The model uid. 

5706 user: If given together with ``access``, the user must have this access to the model. 

5707 access: The required access. 

5708 

5709 Returns: 

5710 The model, or None if it is not found or not accessible. 

5711 """ 

5712 

5713 def find_model(self, *objects, user: 'User' = None, access: Access = None) -> Optional['Model']: 

5714 """Return the first model of the given objects. 

5715 

5716 Looks in the ``models`` attribute of each object in turn. 

5717 

5718 Args: 

5719 *objects: Objects with models, e.g. layers. None values are skipped. 

5720 user: If given together with ``access``, the user must have this access to the model. 

5721 access: The required access. 

5722 

5723 Returns: 

5724 The model, or None if none is found. 

5725 """ 

5726 

5727 def editable_models(self, project: 'Project', user: 'User') -> list['Model']: 

5728 """Return the models a user can edit in a project, together with their related models. 

5729 

5730 Args: 

5731 project: The project. 

5732 user: The user. 

5733 

5734 Returns: 

5735 The models, sorted by title. 

5736 """ 

5737 

5738 def default_model(self) -> 'Model': 

5739 """Return the shared default model. 

5740 

5741 Returns: 

5742 The default model. 

5743 """ 

5744################################################################################ 

5745 

5746 

5747################################################################################ 

5748# /base/database/types.pyinc 

5749 

5750 

5751class DatabaseModel(Model): 

5752 """Data model for a database table.""" 

5753 

5754 db: 'DatabaseProvider' 

5755 """Database provider.""" 

5756 sqlFilter: str 

5757 """Literal SQL condition applied when selecting rows.""" 

5758 tableName: str 

5759 """Table name associated with this model.""" 

5760 

5761 def table(self) -> 'sqlalchemy.Table': 

5762 """Return the SQLAlchemy ``Table`` object of the model table. 

5763 

5764 Returns: 

5765 The table object. 

5766 

5767 Raises: 

5768 ``sqlalchemy.exc.SQLAlchemyError``: If the table does not exist. 

5769 """ 

5770 

5771 def column(self, column_name: str) -> 'sqlalchemy.Column': 

5772 """Return the SQLAlchemy ``Column`` object of a column in the model table. 

5773 

5774 Args: 

5775 column_name: Column name. 

5776 

5777 Returns: 

5778 The column object. 

5779 

5780 Raises: 

5781 ``sqlalchemy.exc.SQLAlchemyError``: If the table or the column does not exist. 

5782 """ 

5783 

5784 def uid_column(self) -> 'sqlalchemy.Column': 

5785 """Return the SQLAlchemy ``Column`` object of the primary key column. 

5786 

5787 Returns: 

5788 The column object for ``uidName``. 

5789 

5790 Raises: 

5791 ``gws.Error``: If the model has no primary key or the key column does not exist. 

5792 """ 

5793 

5794 def uid_equals(self, uid: FeatureUid | Iterable[FeatureUid]) -> 'sqlalchemy.ColumnElement[bool]': 

5795 """Return a condition that matches features by uid. 

5796 

5797 The values are bound with the type of the primary key column, so that 

5798 string uids can be compared with columns of other types. 

5799 

5800 Args: 

5801 uid: A feature uid, or an iterable of uids. 

5802 

5803 Returns: 

5804 An ``=`` condition for a single uid, an ``IN`` condition for an iterable. 

5805 

5806 Raises: 

5807 ``gws.Error``: If the model has no primary key or the key column does not exist. 

5808 """ 

5809 

5810 def fetch_features(self, select: 'sqlalchemy.Select') -> list['Feature']: 

5811 """Run a SELECT statement and create a feature for each row. 

5812 

5813 The row values become the attributes of the feature record. 

5814 

5815 Args: 

5816 select: SELECT statement. 

5817 

5818 Returns: 

5819 A list of features. 

5820 """ 

5821 

5822 def build_select(self, mc: 'ModelContext') -> Optional['sqlalchemy.Select']: 

5823 """Build a SELECT statement for a search. 

5824 

5825 Combines the search query in ``mc.search``, the columns and conditions 

5826 collected by the fields in ``mc.dbSelect`` and ``sqlFilter``. 

5827 

5828 Args: 

5829 mc: Model context with ``search`` and ``dbSelect`` set. 

5830 

5831 Returns: 

5832 The SELECT statement, or ``None`` if the search cannot match anything. 

5833 """ 

5834 

5835 

5836class ColumnDescription(Data): 

5837 """Description of a dataset column.""" 

5838 

5839 columnIndex: int 

5840 """The index of the column within the table.""" 

5841 comment: str 

5842 """Column comment or description provided in the database metadata.""" 

5843 geometrySrid: int 

5844 """The Spatial Reference Identifier (SRID) for geometry columns.""" 

5845 geometryType: GeometryType 

5846 """The type of geometry stored in the column (e.g., Point, Polygon).""" 

5847 isAutoincrement: bool 

5848 """Indicates if the column is auto-incremented.""" 

5849 isNullable: bool 

5850 """Specifies if the column permits NULL values.""" 

5851 isPrimaryKey: bool 

5852 """Specifies if the column is part of the primary key.""" 

5853 isUnique: bool 

5854 """Indicates if the column has a unique constraint.""" 

5855 hasDefault: bool 

5856 """Indicates if the column has a database-defined default value.""" 

5857 isIndexed: bool 

5858 """Indicates if the column has an index.""" 

5859 name: str 

5860 """The name of the column.""" 

5861 nativeType: str 

5862 """The database-specific data type of the column.""" 

5863 options: dict 

5864 """Additional options or configurations for the column, if any.""" 

5865 type: AttributeType 

5866 """The abstract type of the column used in higher-level processing.""" 

5867 

5868 

5869class DataSetDescription(Data): 

5870 """Description of a dataset, like a DB table or a GDAL data set.""" 

5871 

5872 columns: list[ColumnDescription] 

5873 """A list of column descriptions.""" 

5874 columnMap: dict[str, ColumnDescription] 

5875 """A dictionary mapping column names to their descriptions.""" 

5876 fullName: str 

5877 """The full name of the dataset, including schema if applicable.""" 

5878 geometryName: str 

5879 """The name of the geometry column, if any.""" 

5880 geometrySrid: int 

5881 """The Spatial Reference Identifier (SRID) for the geometry.""" 

5882 geometryType: GeometryType 

5883 """The type of geometry stored in the dataset.""" 

5884 name: str 

5885 """The name of the dataset or table.""" 

5886 schema: str 

5887 """The schema to which the dataset belongs.""" 

5888 

5889 

5890class DatabaseManager(Node): 

5891 """Database manager.""" 

5892 

5893 providers: list['DatabaseProvider'] 

5894 """A list of database providers managed by this DatabaseManager.""" 

5895 

5896 def create_provider(self, cfg: Config, **kwargs) -> 'DatabaseProvider': 

5897 """Create a database provider and add it to ``providers``. 

5898 

5899 The provider is created as a shared object. A provider with the same uid 

5900 that is already in ``providers`` is replaced. 

5901 

5902 Args: 

5903 cfg: Provider configuration. 

5904 **kwargs: Extra configuration values. 

5905 

5906 Returns: 

5907 The provider. 

5908 """ 

5909 

5910 def find_provider(self, uid: Optional[str] = None, ext_type: Optional[str] = None) -> Optional['DatabaseProvider']: 

5911 """Find a database provider by uid or type. 

5912 

5913 With ``uid``, returns the provider with this uid (and of type ``ext_type``, 

5914 if given). With ``ext_type`` only, returns the first provider of this type. 

5915 Without arguments, returns the first provider. 

5916 

5917 Args: 

5918 uid: Provider uid. 

5919 ext_type: Provider type, e.g. ``postgres``. 

5920 

5921 Returns: 

5922 The provider, or ``None`` if none matches. 

5923 """ 

5924 

5925 

5926DatabaseTableAlike: TypeAlias = Union['sqlalchemy.Table', str] 

5927"""An SQLAlchemy ``Table`` object or a string table name.""" 

5928 

5929 

5930DatabaseStmt: TypeAlias = Union['sqlalchemy.Executable', str] 

5931"""An Executable SQLAlchemy object or a string SQL statement.""" 

5932 

5933 

5934class DatabaseConnection: 

5935 """Database connection. 

5936 

5937 Wraps an SQLAlchemy ``Connection`` and provides some convenience methods. 

5938 Returned by ``DatabaseProvider.begin``. The connection does not control 

5939 the transaction: it is committed or rolled back by ``begin``. 

5940 

5941 Statements can be SQLAlchemy objects or SQL strings with ``:name`` bind 

5942 parameters. 

5943 """ 

5944 

5945 saConn: 'sqlalchemy.Connection' 

5946 """The underlying SQLAlchemy connection.""" 

5947 

5948 def execute(self, stmt: 'DatabaseStmt', params=None, execution_options: dict=None) -> 'sqlalchemy.CursorResult': 

5949 """Execute a statement. 

5950 

5951 Args: 

5952 stmt: Statement or SQL string. 

5953 params: Bind parameters, a dict or a list of dicts. 

5954 execution_options: SQLAlchemy execution options. 

5955 

5956 Returns: 

5957 The result. 

5958 """ 

5959 

5960 def fetch_all(self, stmt: 'DatabaseStmt', **params) -> list[dict]: 

5961 """Execute a statement and return all rows. 

5962 

5963 Args: 

5964 stmt: Statement or SQL string. 

5965 **params: Bind parameters. 

5966 

5967 Returns: 

5968 A list of rows as dicts. 

5969 """ 

5970 

5971 def fetch_first(self, stmt: 'DatabaseStmt', **params) -> dict | None: 

5972 """Execute a statement and return the first row. 

5973 

5974 Args: 

5975 stmt: Statement or SQL string. 

5976 **params: Bind parameters. 

5977 

5978 Returns: 

5979 The first row as a dict, or ``None`` if there are no rows. 

5980 """ 

5981 

5982 def fetch_scalars(self, stmt: 'DatabaseStmt', **params) -> list: 

5983 """Execute a statement and return the first column of all rows. 

5984 

5985 Args: 

5986 stmt: Statement or SQL string. 

5987 **params: Bind parameters. 

5988 

5989 Returns: 

5990 A list of values. 

5991 """ 

5992 

5993 def fetch_strings(self, stmt: 'DatabaseStmt', **params) -> list[str]: 

5994 """Execute a statement and return the first column of all rows as strings. 

5995 

5996 Args: 

5997 stmt: Statement or SQL string. 

5998 **params: Bind parameters. 

5999 

6000 Returns: 

6001 A list of strings, with ``NULL`` values as empty strings. 

6002 """ 

6003 

6004 def fetch_ints(self, stmt: 'DatabaseStmt', **params) -> list[int]: 

6005 """Execute a statement and return the first column of all rows as integers. 

6006 

6007 Args: 

6008 stmt: Statement or SQL string. 

6009 **params: Bind parameters. 

6010 

6011 Returns: 

6012 A list of integers. 

6013 

6014 Raises: 

6015 ``ValueError``: If a value is not an integer. 

6016 """ 

6017 

6018 def fetch_scalar(self, stmt: 'DatabaseStmt', **params) -> Any: 

6019 """Execute a statement and return the first column of the first row. 

6020 

6021 Args: 

6022 stmt: Statement or SQL string. 

6023 **params: Bind parameters. 

6024 

6025 Returns: 

6026 The value, or ``None`` if there are no rows. 

6027 """ 

6028 

6029 def fetch_string(self, stmt: 'DatabaseStmt', **params) -> str | None: 

6030 """Execute a statement and return the first column of the first row as a string. 

6031 

6032 Args: 

6033 stmt: Statement or SQL string. 

6034 **params: Bind parameters. 

6035 

6036 Returns: 

6037 The string, or ``None`` if there are no rows or the value is ``NULL``. 

6038 """ 

6039 

6040 def fetch_int(self, stmt: 'DatabaseStmt', **params) -> int | None: 

6041 """Execute a statement and return the first column of the first row as an integer. 

6042 

6043 Args: 

6044 stmt: Statement or SQL string. 

6045 **params: Bind parameters. 

6046 

6047 Returns: 

6048 The integer, or ``None`` if there are no rows or the value is ``NULL``. 

6049 

6050 Raises: 

6051 ``ValueError``: If the value is not an integer. 

6052 """ 

6053 

6054class DatabaseInspectOptions(Data): 

6055 """Options for database inspection.""" 

6056 

6057 refresh: bool = False 

6058 """Whether to force inspection even if cached information is available.""" 

6059 cacheLifeTime: int = 0 

6060 """Schema cache lifetime in seconds.""" 

6061 

6062 

6063class DatabaseProvider(Node): 

6064 """Database provider. 

6065 

6066 Wraps an SQLAlchemy ``Engine`` and hands out connections. Also reflects 

6067 table structures and describes tables and columns. 

6068 """ 

6069 

6070 def begin(self, nested: bool = False) -> ContextManager['DatabaseConnection']: 

6071 """Begin a transaction, to be used as a context manager. 

6072 

6073 The outermost call opens a connection and begins a transaction, which 

6074 is committed on normal exit and rolled back on an exception. Inner 

6075 calls in the same thread join the open transaction, or create a 

6076 savepoint if ``nested`` is set:: 

6077 

6078 with db.begin() as conn: 

6079 conn.execute('INSERT ...') 

6080 with db.begin() as conn2: # same connection and transaction 

6081 rows = conn2.fetch_all('SELECT ...') 

6082 with db.begin(nested=True) as conn3: # savepoint 

6083 conn3.execute('UPDATE ...') 

6084 # committed, connection closed 

6085 

6086 Unlike SQLAlchemy ``Engine.begin``, an inner call does not open a new 

6087 connection. Each provider keeps its own connection per thread. 

6088 

6089 Args: 

6090 nested: Create a savepoint when joining an open transaction. An 

6091 exception inside the block then rolls back to the savepoint 

6092 only. Has no effect on the outermost call. 

6093 

6094 Returns: 

6095 A context manager that yields the connection. 

6096 """ 

6097 

6098 def connect(self) -> ContextManager['DatabaseConnection']: 

6099 """Deprecated, same as ``begin``.""" 

6100 

6101 def autocommit_connection(self) -> ContextManager['DatabaseConnection']: 

6102 """Open a separate connection in autocommit mode, to be used as a context manager. 

6103 

6104 For statements that cannot run inside a transaction, like ``VACUUM``. 

6105 The connection is not shared with ``begin``. 

6106 

6107 Returns: 

6108 A context manager that yields the connection. 

6109 

6110 Raises: 

6111 ``gws.Error``: If a transaction of this provider is open in the current thread. 

6112 """ 

6113 

6114 def engine_options(self, **kwargs): 

6115 """Add defaults to the SQLAlchemy engine options. 

6116 

6117 Args: 

6118 **kwargs: Engine options. Options passed here take precedence over the defaults. 

6119 

6120 Returns: 

6121 The options dict. 

6122 """ 

6123 

6124 def url(self) -> str: 

6125 """Return the connection URL. 

6126 

6127 Returns: 

6128 An SQLAlchemy connection URL. 

6129 """ 

6130 

6131 def engine(self) -> 'sqlalchemy.Engine': 

6132 """Return the SQLAlchemy ``Engine`` object for this provider, creating it if needed. 

6133 

6134 Returns: 

6135 The engine. 

6136 """ 

6137 

6138 def create_engine(self, **kwargs) -> 'sqlalchemy.Engine': 

6139 """Create a new SQLAlchemy ``Engine`` object for this provider. 

6140 

6141 Args: 

6142 **kwargs: Engine options, see ``engine_options``. 

6143 

6144 Returns: 

6145 The engine. 

6146 """ 

6147 

6148 def describe(self, table: DatabaseTableAlike) -> 'DataSetDescription': 

6149 """Describe a table. 

6150 

6151 Args: 

6152 table: Table object or table name. 

6153 

6154 Returns: 

6155 The table description. The first geometry column becomes the primary geometry. 

6156 

6157 Raises: 

6158 ``sqlalchemy.exc.SQLAlchemyError``: If the table does not exist. 

6159 """ 

6160 

6161 def describe_column(self, table: DatabaseTableAlike, column_name: str) -> ColumnDescription: 

6162 """Describe a column in a table. 

6163 

6164 Args: 

6165 table: Table object or table name. 

6166 column_name: Column name. 

6167 

6168 Returns: 

6169 The column description. 

6170 

6171 Raises: 

6172 ``sqlalchemy.exc.SQLAlchemyError``: If the table or the column does not exist. 

6173 """ 

6174 

6175 def table(self, table: 'DatabaseTableAlike', **kwargs) -> 'sqlalchemy.Table': 

6176 """Return the SQLAlchemy ``Table`` object for a table. 

6177 

6178 Args: 

6179 table: Table object or table name. 

6180 **kwargs: Not used by the base provider. 

6181 

6182 Returns: 

6183 The table object. 

6184 

6185 Raises: 

6186 ``sqlalchemy.exc.SQLAlchemyError``: If the table does not exist. 

6187 """ 

6188 

6189 def column(self, table: DatabaseTableAlike, column_name: str) -> 'sqlalchemy.Column': 

6190 """Return the SQLAlchemy ``Column`` object for a column. 

6191 

6192 Args: 

6193 table: Table object or table name. 

6194 column_name: Column name. 

6195 

6196 Returns: 

6197 The column object. 

6198 

6199 Raises: 

6200 ``sqlalchemy.exc.SQLAlchemyError``: If the table or the column does not exist. 

6201 """ 

6202 

6203 def count(self, table: DatabaseTableAlike) -> int: 

6204 """Return the number of rows in a table. 

6205 

6206 Args: 

6207 table: Table object or table name. 

6208 

6209 Returns: 

6210 The row count, or 0 if the table does not exist. 

6211 """ 

6212 

6213 def has_schema(self, schema_name: str) -> bool: 

6214 """Check if a schema exists. 

6215 

6216 Args: 

6217 schema_name: Schema name. 

6218 

6219 Returns: 

6220 ``True`` if the schema exists. 

6221 """ 

6222 

6223 def has_table(self, table_name: str) -> bool: 

6224 """Check if a table exists. 

6225 

6226 Args: 

6227 table_name: Table name, optionally schema-qualified. 

6228 

6229 Returns: 

6230 ``True`` if the table exists. 

6231 """ 

6232 

6233 def has_column(self, table: DatabaseTableAlike, column_name: str) -> bool: 

6234 """Check if a column exists. 

6235 

6236 Args: 

6237 table: Table object or table name. 

6238 column_name: Column name. 

6239 

6240 Returns: 

6241 ``True`` if the table and the column exist. 

6242 """ 

6243 

6244 def join_table_name(self, schema: str, name: str) -> str: 

6245 """Create a full table name from the schema and table names. 

6246 

6247 Args: 

6248 schema: Schema name. If empty, the default schema is used. 

6249 name: Table name. 

6250 

6251 Returns: 

6252 The schema-qualified table name. 

6253 """ 

6254 

6255 def split_table_name(self, table_name: str) -> tuple[str, str]: 

6256 """Split a full table name into the schema and table names. 

6257 

6258 Args: 

6259 table_name: Table name, optionally schema-qualified. 

6260 

6261 Returns: 

6262 A tuple of the schema name (the default schema if none is given) and the table name. 

6263 """ 

6264 

6265 def table_bounds(self, table: DatabaseTableAlike) -> Optional[Bounds]: 

6266 """Compute the bounding box of the primary geometry of a table. 

6267 

6268 Args: 

6269 table: Table object or table name. 

6270 

6271 Returns: 

6272 The bounds, or ``None`` if the table has no geometry or no data. 

6273 """ 

6274 

6275 def schema_names(self) -> list[str]: 

6276 """Return the names of the schemas in the database. 

6277 

6278 Returns: 

6279 A list of schema names. 

6280 """ 

6281 

6282 def inspect_schema(self, schema: str, options: Optional[DatabaseInspectOptions] = None): 

6283 """Reflect the tables of a schema and keep the result. 

6284 

6285 A schema that has already been reflected is not reflected again, unless 

6286 ``options.refresh`` is set. The reflected metadata is cached for the 

6287 configured schema cache lifetime. If ``options`` are given, their 

6288 ``cacheLifeTime`` is used instead; 0 means no caching. 

6289 

6290 Args: 

6291 schema: Schema name. 

6292 options: Inspection options. 

6293 """ 

6294################################################################################ 

6295 

6296 

6297 

6298################################################################################ 

6299# /base/job/types.pyinc 

6300 

6301 

6302class JobTerminated(Exception): 

6303 """Raised in a worker when its job is no longer running, e.g. because it was cancelled.""" 

6304 

6305 pass 

6306 

6307 

6308class JobState(Enum): 

6309 """Background job state.""" 

6310 

6311 init = 'init' 

6312 """The job is being created.""" 

6313 open = 'open' 

6314 """The job is just created and waiting for start.""" 

6315 running = 'running' 

6316 """The job is running.""" 

6317 complete = 'complete' 

6318 """The job has been completed successfully.""" 

6319 error = 'error' 

6320 """There was an error.""" 

6321 cancel = 'cancel' 

6322 """The job was cancelled.""" 

6323 

6324 

6325class Job(Data): 

6326 """Background job data.""" 

6327 

6328 uid: str 

6329 """Job uid.""" 

6330 user: 'User' 

6331 """User who created the job.""" 

6332 worker: str 

6333 """Worker class, as ``<module path>:<class name>``.""" 

6334 state: JobState 

6335 """Job state.""" 

6336 error: str 

6337 """Error message, if the job failed.""" 

6338 numSteps: int 

6339 """Total number of steps, for progress reporting.""" 

6340 step: int 

6341 """Current step.""" 

6342 stepName: str 

6343 """Name of the current step.""" 

6344 payload: dict 

6345 """Input data for the worker.""" 

6346 result: dict 

6347 """Result data from the worker.""" 

6348 timeCreated: datetime.datetime 

6349 """Creation time.""" 

6350 timeUpdated: datetime.datetime 

6351 """Time of the last update.""" 

6352 

6353 

6354class JobRequest(Request): 

6355 """Request that refers to a job.""" 

6356 

6357 jobUid: str 

6358 """Job uid.""" 

6359 

6360 

6361class JobStatusResponse(Response): 

6362 """Job status.""" 

6363 

6364 jobUid: str 

6365 """Job uid.""" 

6366 state: JobState 

6367 """Job state.""" 

6368 progress: int 

6369 """Progress in percent.""" 

6370 stepName: str 

6371 """Name of the current step.""" 

6372 output: dict 

6373 """Job-specific output, e.g. a download URL when the job is complete.""" 

6374 

6375 

6376class JobManager(Node): 

6377 """Job manager.""" 

6378 

6379 def create_job(self, worker: type, user: User, payload: dict | Data = None) -> Job: 

6380 """Create a job in the ``open`` state. 

6381 

6382 Args: 

6383 worker: Worker class. It must have a ``run(root, job)`` class method. 

6384 user: User the job runs for. 

6385 payload: Input data for the worker, must be JSON-serializable. 

6386 

6387 Returns: 

6388 The new job. 

6389 """ 

6390 

6391 def get_job(self, job_uid: str, user: User = None, state: JobState = None) -> Optional[Job]: 

6392 """Read a job. 

6393 

6394 Args: 

6395 job_uid: Job uid. 

6396 user: If given, the job must belong to this user. 

6397 state: If given, the job must be in this state. 

6398 

6399 Returns: 

6400 The job, or ``None`` if it does not exist or does not match. The reason is logged. 

6401 """ 

6402 

6403 def update_job(self, job: Job, **kwargs) -> Optional[Job]: 

6404 """Update fields of a job. 

6405 

6406 Args: 

6407 job: The job. 

6408 **kwargs: Job fields to update. 

6409 

6410 Returns: 

6411 The updated job, or ``None`` if the job does not exist. 

6412 """ 

6413 

6414 def run_job(self, job: Job) -> Optional[Job]: 

6415 """Run an open job in the current process. 

6416 

6417 Marks the job as running, so that it runs only once, and calls the 

6418 ``run`` method of its worker. If the worker raises an exception, the 

6419 job goes into the ``error`` state. 

6420 

6421 Args: 

6422 job: The job. 

6423 

6424 Returns: 

6425 The job after the run. 

6426 

6427 Raises: 

6428 ``gws.Error``: If the job is not open or is already taken by another process. 

6429 """ 

6430 

6431 def cancel_job(self, job: Job) -> Optional[Job]: 

6432 """Set a job to the ``cancel`` state. 

6433 

6434 The worker notices the change on its next job update and stops. 

6435 

6436 Args: 

6437 job: The job. 

6438 

6439 Returns: 

6440 The updated job, or ``None`` if the job does not exist. 

6441 """ 

6442 

6443 def remove_job(self, job: Job): 

6444 """Delete a job record. 

6445 

6446 Args: 

6447 job: The job. 

6448 """ 

6449 

6450 def schedule_job(self, job: Job) -> Job: 

6451 """Start an open job. 

6452 

6453 The job is passed to the uWSGI spooler if it is available, otherwise it 

6454 runs at once in the current process. 

6455 

6456 Args: 

6457 job: The job. 

6458 

6459 Returns: 

6460 The job. 

6461 

6462 Raises: 

6463 ``gws.Error``: If the job is not open. 

6464 """ 

6465 

6466 def require_job(self, req: 'WebRequester', p: JobRequest) -> Job: 

6467 """Return the job of a request, if it belongs to the requesting user. 

6468 

6469 Args: 

6470 req: Web request. 

6471 p: Job request. 

6472 

6473 Returns: 

6474 The job. 

6475 

6476 Raises: 

6477 ``gws.NotFoundError``: If the job does not exist or belongs to another user. 

6478 """ 

6479 

6480 def require_result(self, req: 'WebRequester', p: JobRequest) -> dict: 

6481 """Return the result of a completed job of the requesting user. 

6482 

6483 Args: 

6484 req: Web request. 

6485 p: Job request. 

6486 

6487 Returns: 

6488 The job result. 

6489 

6490 Raises: 

6491 ``gws.NotFoundError``: If the job does not exist, belongs to another user, 

6492 is not complete or has no result. 

6493 """ 

6494 

6495 def handle_status_request(self, req: 'WebRequester', p: JobRequest) -> JobStatusResponse: 

6496 """Return the status of a job of the requesting user. 

6497 

6498 Args: 

6499 req: Web request. 

6500 p: Job request. 

6501 

6502 Returns: 

6503 The job status. 

6504 

6505 Raises: 

6506 ``gws.NotFoundError``: If the job does not exist or belongs to another user. 

6507 """ 

6508 

6509 def handle_cancel_request(self, req: 'WebRequester', p: JobRequest) -> JobStatusResponse: 

6510 """Cancel a job of the requesting user. 

6511 

6512 Args: 

6513 req: Web request. 

6514 p: Job request. 

6515 

6516 Returns: 

6517 The job status after cancelling. 

6518 

6519 Raises: 

6520 ``gws.NotFoundError``: If the job does not exist or belongs to another user. 

6521 """ 

6522 

6523 def job_status_response(self, job: Job, **kwargs) -> 'JobStatusResponse': 

6524 """Create a status response for a job. 

6525 

6526 Args: 

6527 job: The job. 

6528 **kwargs: Extra or overriding response fields. 

6529 

6530 Returns: 

6531 The status response. 

6532 """ 

6533################################################################################ 

6534 

6535 

6536################################################################################ 

6537# /base/ows/types.pyinc 

6538 

6539 

6540import gws 

6541 

6542 

6543class OwsProtocol(Enum): 

6544 """Supported OWS protocols.""" 

6545 

6546 WMS = 'WMS' 

6547 WMTS = 'WMTS' 

6548 WCS = 'WCS' 

6549 WFS = 'WFS' 

6550 CSW = 'CSW' 

6551 

6552 

6553class OwsAuthorization(Data): 

6554 """Credentials for accessing an OWS service.""" 

6555 

6556 type: str 

6557 """Authorization type, ``basic`` or ``token``.""" 

6558 username: str 

6559 """User name.""" 

6560 password: str 

6561 """Password.""" 

6562 header: str 

6563 """HTTP header that carries the token.""" 

6564 prefix: str 

6565 """Prefix expected before the token in the header value.""" 

6566 token: str 

6567 """Authorization token.""" 

6568 

6569 

6570 

6571class OwsVerb(Enum): 

6572 """OWS request type.""" 

6573 

6574 CreateStoredQuery = 'CreateStoredQuery' 

6575 DescribeCoverage = 'DescribeCoverage' 

6576 DescribeFeatureType = 'DescribeFeatureType' 

6577 DescribeLayer = 'DescribeLayer' 

6578 DescribeRecord = 'DescribeRecord' 

6579 DescribeStoredQueries = 'DescribeStoredQueries' 

6580 DropStoredQuery = 'DropStoredQuery' 

6581 GetCapabilities = 'GetCapabilities' 

6582 GetFeature = 'GetFeature' 

6583 GetFeatureInfo = 'GetFeatureInfo' 

6584 GetFeatureWithLock = 'GetFeatureWithLock' 

6585 GetLegendGraphic = 'GetLegendGraphic' 

6586 GetMap = 'GetMap' 

6587 GetPrint = 'GetPrint' 

6588 GetPropertyValue = 'GetPropertyValue' 

6589 GetRecordById = 'GetRecordById' 

6590 GetRecords = 'GetRecords' 

6591 GetTile = 'GetTile' 

6592 ListStoredQueries = 'ListStoredQueries' 

6593 LockFeature = 'LockFeature' 

6594 Transaction = 'Transaction' 

6595 

6596 

6597class OwsOperation(Data): 

6598 """OWS operation, as offered by a remote service or by our own service.""" 

6599 

6600 allowedParameters: dict[str, list[str]] 

6601 """Allowed values for parameters, keyed by the upper-cased parameter name.""" 

6602 constraints: dict[str, list[str]] 

6603 """Operation constraints.""" 

6604 defaultMimeType: str 

6605 """Output MIME type to use in requests that do not specify one (client side).""" 

6606 handlerName: str 

6607 """Name of the service method that handles this operation (server side).""" 

6608 mimeTypeMap: dict[str, str] 

6609 """Normalized MIME types mapped to the spelling of the remote service, if it differs (client side).""" 

6610 mimeTypes: list[str] 

6611 """Supported output MIME types, normalized.""" 

6612 params: dict[str, str] 

6613 """Extra parameters for GET requests (client side).""" 

6614 postUrl: Url 

6615 """URL for POST requests.""" 

6616 url: Url 

6617 """URL for GET requests.""" 

6618 verb: OwsVerb 

6619 """Request type.""" 

6620 

6621 

6622class OwsCapabilities(Data): 

6623 """Parsed capabilities of a remote OWS service.""" 

6624 

6625 metadata: 'Metadata' 

6626 """Service metadata.""" 

6627 operations: list['OwsOperation'] 

6628 """Operations offered by the service.""" 

6629 sourceLayers: list['SourceLayer'] 

6630 """Layers or feature types of the service.""" 

6631 tileMatrixSets: list['TileMatrixSet'] 

6632 """Tile matrix sets (WMTS).""" 

6633 version: str 

6634 """Service version.""" 

6635 

6636 

6637class OwsService(Node): 

6638 """OWS service provided by GBD WebSuite.""" 

6639 

6640 isRasterService: bool = False 

6641 """Service provides raster services.""" 

6642 isVectorService: bool = False 

6643 """Service provides vector services.""" 

6644 isOwsCommon: bool = False 

6645 """Conforms to OGC Web Services Common Standard.""" 

6646 

6647 alwaysXY: bool 

6648 """Force lon/lat order for geographic projections.""" 

6649 metadata: 'Metadata' 

6650 """Service metadata.""" 

6651 name: str 

6652 """Service name.""" 

6653 project: Optional['Project'] 

6654 """Project this service is configured for.""" 

6655 rootLayer: Optional['Layer'] 

6656 """Root layer of the service.""" 

6657 protocol: OwsProtocol 

6658 """Supported protocol.""" 

6659 defaultFeatureCount: int 

6660 """Default limit of features per page.""" 

6661 maxFeatureCount: int 

6662 """Max limit of features per page.""" 

6663 searchTolerance: UomValue 

6664 """Default tolerance for spatial search.""" 

6665 supportedBounds: list[Bounds] 

6666 """Supported bounds.""" 

6667 supportedVersions: list[str] 

6668 """Supported versions.""" 

6669 supportedOperations: list['OwsOperation'] 

6670 """Supported operations.""" 

6671 templates: list['Template'] 

6672 """Service templates.""" 

6673 imageFormats: list[ImageFormat] 

6674 """Supported image formats.""" 

6675 updateSequence: str 

6676 """Service update sequence.""" 

6677 withInspireMeta: bool 

6678 """Include INSPIRE metadata.""" 

6679 withStrictParams: bool 

6680 """Strict parameter checking.""" 

6681 

6682 def handle_request(self, req: 'WebRequester') -> ContentResponse: 

6683 """Handle a service request. 

6684 

6685 Errors are returned as OWS exception documents, not raised. 

6686 

6687 Args: 

6688 req: Web request. 

6689 

6690 Returns: 

6691 The service response. 

6692 """ 

6693 

6694 def layer_is_compatible(self, layer: 'Layer') -> bool: 

6695 """Check if a layer can be used in this service. 

6696 

6697 Args: 

6698 layer: Layer object. 

6699 

6700 Returns: 

6701 ``True`` if the layer can be published by this service. 

6702 """ 

6703 

6704 

6705class OwsServiceProvider(Node): 

6706 """Remote OWS service used as a data provider.""" 

6707 

6708 alwaysXY: bool 

6709 """Force XY axis order for CRSs with lat/lon axis order.""" 

6710 authorization: Optional['OwsAuthorization'] 

6711 """Credentials for the service.""" 

6712 bounds: Optional[Bounds] 

6713 """Service bounds, if known.""" 

6714 forceCrs: 'Crs' 

6715 """CRS to use for requests, if configured.""" 

6716 maxRequests: int 

6717 """Max. number of concurrent requests to the service.""" 

6718 metadata: 'Metadata' 

6719 """Service metadata.""" 

6720 operations: list['OwsOperation'] 

6721 """Operations offered by the service.""" 

6722 protocol: 'OwsProtocol' 

6723 """Service protocol.""" 

6724 sourceLayers: list['SourceLayer'] 

6725 """Layers or feature types of the service.""" 

6726 url: Url 

6727 """Service URL.""" 

6728 version: str 

6729 """Service version.""" 

6730 wgsExtent: Optional[Extent] 

6731 """Service extent in WGS84, if known.""" 

6732 

6733 def get_operation(self, verb: 'OwsVerb', method: Optional['RequestMethod'] = None) -> Optional['OwsOperation']: 

6734 """Find an operation by its verb. 

6735 

6736 Args: 

6737 verb: Request type. 

6738 method: Request method. For ``POST``, the operation must have a POST URL, 

6739 otherwise a GET URL. 

6740 

6741 Returns: 

6742 The operation, or ``None`` if the service does not support it. 

6743 """ 

6744 

6745 def get_features(self, args: 'SearchQuery', source_layers: list['SourceLayer'], mime: MimeType = '') -> list['FeatureRecord']: 

6746 """Search for features in the given source layers. 

6747 

6748 Args: 

6749 args: Search query. 

6750 source_layers: Source layers to search. 

6751 mime: Response MIME type to request, the default of the operation if empty. 

6752 

6753 Returns: 

6754 Found feature records. 

6755 """ 

6756################################################################################ 

6757 

6758 

6759################################################################################ 

6760# /base/printer/types.pyinc 

6761 

6762 

6763class PrintPlaneType(Enum): 

6764 """Print plane type.""" 

6765 

6766 bitmap = 'bitmap' 

6767 """Raw bitmap data.""" 

6768 url = 'url' 

6769 """Image given as a data URL.""" 

6770 features = 'features' 

6771 """Features sent by the client.""" 

6772 raster = 'raster' 

6773 """Raster layer.""" 

6774 vector = 'vector' 

6775 """Vector layer, rendered as SVG.""" 

6776 soup = 'soup' 

6777 """SVG soup: points and SVG tags.""" 

6778 

6779 

6780class PrintPlane(Data): 

6781 """Print plane, a single map layer in a print request.""" 

6782 

6783 type: PrintPlaneType 

6784 """Plane type.""" 

6785 

6786 opacity: Optional[float] 

6787 """Plane opacity, from 0 to 1.""" 

6788 cssSelector: Optional[str] 

6789 """CSS selector of the style for vector layers and features.""" 

6790 

6791 bitmapData: Optional[bytes] 

6792 """Raw pixel data, for bitmap planes.""" 

6793 bitmapMode: Optional[str] 

6794 """Pixel mode of the bitmap, ``RGBA`` or ``RGB``.""" 

6795 bitmapWidth: Optional[int] 

6796 """Bitmap width in pixels.""" 

6797 bitmapHeight: Optional[int] 

6798 """Bitmap height in pixels.""" 

6799 

6800 url: Optional[str] 

6801 """Data URL of the image, for url planes.""" 

6802 

6803 features: Optional[list['FeatureProps']] 

6804 """Features, for features planes.""" 

6805 

6806 layerUid: Optional[str] 

6807 """Layer uid, for raster and vector planes.""" 

6808 compositeLayerUids: Optional[list[str]] 

6809 """Uids of the sub-layers to render, for composite raster layers.""" 

6810 

6811 soupPoints: Optional[list[Point]] 

6812 """Points, for soup planes.""" 

6813 soupTags: Optional[list[Any]] 

6814 """SVG tags, for soup planes.""" 

6815 

6816 

6817class PrintMap(Data): 

6818 """Map properties for printing.""" 

6819 

6820 backgroundColor: Optional[int] 

6821 """Background color.""" 

6822 bbox: Optional[Extent] 

6823 """Map extent.""" 

6824 center: Optional[Point] 

6825 """Map center.""" 

6826 planes: list[PrintPlane] 

6827 """Map planes.""" 

6828 rotation: Optional[int] 

6829 """Map rotation in degrees.""" 

6830 scale: int 

6831 """Map scale denominator.""" 

6832 styles: Optional[list['StyleProps']] 

6833 """Styles used by the planes.""" 

6834 visibleLayers: Optional[list[str]] 

6835 """Uids of the visible layers.""" 

6836 

6837 

6838class PrintRequestType(Enum): 

6839 """Type of the print request.""" 

6840 

6841 template = 'template' 

6842 map = 'map' 

6843 

6844 

6845class PrintRequest(Request): 

6846 """Print request.""" 

6847 

6848 type: PrintRequestType 

6849 """Request type.""" 

6850 

6851 args: Optional[dict] 

6852 """Template arguments.""" 

6853 crs: Optional[CrsName] 

6854 """CRS of the maps, the project CRS by default.""" 

6855 outputFormat: Optional[str] 

6856 """Output format, ``pdf`` (default) or ``png``, or the mime type.""" 

6857 maps: Optional[list[PrintMap]] 

6858 """Maps to print.""" 

6859 

6860 printerUid: Optional[str] 

6861 """Printer uid, for template requests.""" 

6862 dpi: Optional[int] 

6863 """Output resolution.""" 

6864 outputSize: Optional[Size] 

6865 """Output size in screen pixels, for map requests.""" 

6866 

6867 

6868class PrintResult(Data): 

6869 """Print result.""" 

6870 

6871 path: str 

6872 """Path of the output file.""" 

6873 mimeType: str 

6874 """Mime type of the output file.""" 

6875 

6876 

6877class Printer(Node): 

6878 """Printer, a print template offered to users.""" 

6879 

6880 title: str 

6881 """Printer title.""" 

6882 template: 'Template' 

6883 """Template that renders the print output.""" 

6884 models: list['Model'] 

6885 """Models whose fields are shown as input fields in the print dialog.""" 

6886 qualityLevels: list['TemplateQualityLevel'] 

6887 """Quality levels users can choose from.""" 

6888 

6889 

6890class PrinterManager(Node): 

6891 """Print manager.""" 

6892 

6893 def start_print_job(self, request: PrintRequest, user: 'User') -> 'JobStatusResponse': 

6894 """Start a background print job. 

6895 

6896 Args: 

6897 request: Print request. 

6898 user: User who requested the print. 

6899 

6900 Returns: 

6901 The status of the new job. 

6902 """ 

6903 

6904 def exec_print(self, request: PrintRequest, out_path: str): 

6905 """Execute a print request synchronously, as the system user. 

6906 

6907 Args: 

6908 request: Print request. 

6909 out_path: Path to copy the output file to. 

6910 """ 

6911################################################################################ 

6912 

6913 

6914################################################################################ 

6915# /base/project/types.pyinc 

6916 

6917 

6918class Client(Node): 

6919 """Settings for the browser client: UI elements and client options.""" 

6920 

6921 options: dict 

6922 """Client options.""" 

6923 elements: list 

6924 """Client UI elements.""" 

6925 

6926 

6927class Project(Node): 

6928 """Project: a map application with its own map, actions, templates and services.""" 

6929 

6930 assetsRoot: Optional['WebDocumentRoot'] 

6931 """Project assets directory, checked before the global assets directory.""" 

6932 client: 'Client' 

6933 """Project client settings, replacing the application client.""" 

6934 

6935 localeUids: list[str] 

6936 """Locales of the project.""" 

6937 map: 'Map' 

6938 """Main map of the project.""" 

6939 metadata: 'Metadata' 

6940 """Project metadata.""" 

6941 title: str 

6942 """Project title.""" 

6943 

6944 actions: list['Action'] 

6945 """Actions available only in this project.""" 

6946 finders: list['Finder'] 

6947 """Search providers of the project.""" 

6948 models: list['Model'] 

6949 """Data models of the project.""" 

6950 exporters: list['Exporter'] 

6951 """Exporters of the project.""" 

6952 printers: list['Printer'] 

6953 """Printers of the project.""" 

6954 templates: list['Template'] 

6955 """Templates of the project.""" 

6956 owsServices: list['OwsService'] 

6957 """OWS services published for the project.""" 

6958 

6959 vars: dict 

6960 """Custom variables.""" 

6961################################################################################ 

6962 

6963 

6964################################################################################ 

6965# /base/search/types.pyinc 

6966 

6967 

6968class SearchSort(Data): 

6969 """Search sort specification.""" 

6970 

6971 fieldName: str 

6972 """Field name to sort by.""" 

6973 reverse: bool 

6974 """Sort in descending order.""" 

6975 

6976 

6977class SearchFilterOperator(Enum): 

6978 """Search filter operator, as defined in OGC Filter Encoding 2.0.""" 

6979 

6980 And = 'And' 

6981 """All sub-filters match.""" 

6982 Or = 'Or' 

6983 """At least one sub-filter matches.""" 

6984 Not = 'Not' 

6985 """The sub-filter does not match.""" 

6986 

6987 PropertyIsEqualTo = 'PropertyIsEqualTo' 

6988 """Property is equal to the value.""" 

6989 PropertyIsNotEqualTo = 'PropertyIsNotEqualTo' 

6990 """Property is not equal to the value.""" 

6991 PropertyIsLessThan = 'PropertyIsLessThan' 

6992 """Property is less than the value.""" 

6993 PropertyIsGreaterThan = 'PropertyIsGreaterThan' 

6994 """Property is greater than the value.""" 

6995 PropertyIsLessThanOrEqualTo = 'PropertyIsLessThanOrEqualTo' 

6996 """Property is less than or equal to the value.""" 

6997 PropertyIsGreaterThanOrEqualTo = 'PropertyIsGreaterThanOrEqualTo' 

6998 """Property is greater than or equal to the value.""" 

6999 PropertyIsLike = 'PropertyIsLike' 

7000 """Property matches a pattern.""" 

7001 PropertyIsNull = 'PropertyIsNull' 

7002 """Property is null.""" 

7003 PropertyIsNil = 'PropertyIsNil' 

7004 """Property is nil.""" 

7005 PropertyIsBetween = 'PropertyIsBetween' 

7006 """Property is between two values.""" 

7007 

7008 Equals = 'Equals' 

7009 """Geometry is equal to the shape.""" 

7010 Disjoint = 'Disjoint' 

7011 """Geometry does not intersect the shape.""" 

7012 Touches = 'Touches' 

7013 """Geometry touches the shape.""" 

7014 Within = 'Within' 

7015 """Geometry is within the shape.""" 

7016 Overlaps = 'Overlaps' 

7017 """Geometry overlaps the shape.""" 

7018 Crosses = 'Crosses' 

7019 """Geometry crosses the shape.""" 

7020 Intersects = 'Intersects' 

7021 """Geometry intersects the shape.""" 

7022 Contains = 'Contains' 

7023 """Geometry contains the shape.""" 

7024 DWithin = 'DWithin' 

7025 """Geometry is within a distance of the shape.""" 

7026 Beyond = 'Beyond' 

7027 """Geometry is beyond a distance of the shape.""" 

7028 BBOX = 'BBOX' 

7029 """Geometry intersects the bounding box.""" 

7030 

7031 

7032class SearchFilterMatchAction(Enum): 

7033 """How a filter is applied to a multi-valued property.""" 

7034 

7035 All = 'All' 

7036 """All values must match.""" 

7037 Any = 'Any' 

7038 """At least one value must match.""" 

7039 One = 'One' 

7040 """Exactly one value must match.""" 

7041 

7042 

7043class SearchFilter(Data): 

7044 """Search filter, a tree of filter operators.""" 

7045 

7046 operator: SearchFilterOperator 

7047 """Filter operator.""" 

7048 property: str 

7049 """Property name for comparison and spatial operators.""" 

7050 value: str 

7051 """Value for comparison operators.""" 

7052 shape: 'Shape' 

7053 """Shape for spatial operators.""" 

7054 subFilters: list['SearchFilter'] 

7055 """Operands of logical operators.""" 

7056 matchCase: bool 

7057 """Compare strings case-sensitively.""" 

7058 matchAction: SearchFilterMatchAction 

7059 """How to match multi-valued properties.""" 

7060 wildCard: str 

7061 """Wildcard character for ``PropertyIsLike``.""" 

7062 singleChar: str 

7063 """Single character placeholder for ``PropertyIsLike``.""" 

7064 escapeChar: str 

7065 """Escape character for ``PropertyIsLike``.""" 

7066 

7067 

7068class SearchQuery(Data): 

7069 """Search query.""" 

7070 

7071 bounds: Bounds 

7072 """Search bounds.""" 

7073 extraArgs: dict 

7074 """Extra arguments for custom searches.""" 

7075 extraColumns: list 

7076 """Extra columns to select.""" 

7077 extraParams: dict 

7078 """Extra parameters to pass to a provider.""" 

7079 extraWhere: list 

7080 """Extra where clauses.""" 

7081 keyword: str 

7082 """Keyword to search for.""" 

7083 layers: list['Layer'] 

7084 """Layers to search in.""" 

7085 limit: int 

7086 """Limit the number of results.""" 

7087 filter: SearchFilter 

7088 """Search filter.""" 

7089 project: 'Project' 

7090 """Project to search in.""" 

7091 resolution: float 

7092 """Pixel resolution for geometry search.""" 

7093 shape: 'Shape' 

7094 """Shape to search in.""" 

7095 sort: list[SearchSort] 

7096 """Sort options.""" 

7097 tolerance: 'UomValue' 

7098 """Tolerance for geometry search.""" 

7099 uids: list[str] 

7100 """UIDs to search for.""" 

7101 

7102 

7103class SearchResult(Data): 

7104 """Search result.""" 

7105 

7106 feature: 'Feature' 

7107 """Found feature.""" 

7108 layer: 'Layer' 

7109 """Layer whose finder found the feature, or ``None`` for project and application finders.""" 

7110 finder: 'Finder' 

7111 """Finder that found the feature.""" 

7112 

7113 

7114class TextSearchType(Enum): 

7115 """Text search type.""" 

7116 

7117 exact = 'exact' 

7118 """Match the whole string.""" 

7119 begin = 'begin' 

7120 """Match the beginning of the string.""" 

7121 end = 'end' 

7122 """Match the end of the string.""" 

7123 any = 'any' 

7124 """Match any substring.""" 

7125 like = 'like' 

7126 """Use the percent sign as a placeholder.""" 

7127 

7128 

7129class TextSearchOptions(Data): 

7130 """How keywords are matched against a text field.""" 

7131 

7132 type: TextSearchType 

7133 """Type of the search.""" 

7134 minLength: int = 0 

7135 """Min. keyword length.""" 

7136 caseSensitive: bool = False 

7137 """Use case-sensitive search.""" 

7138 

7139 

7140class SortOptions(Data): 

7141 """Sort order for features.""" 

7142 

7143 fieldName: str 

7144 """Field name to sort by.""" 

7145 reverse: bool = False 

7146 """Sort in descending order.""" 

7147 

7148 

7149class SearchManager(Node): 

7150 """Search manager, runs search queries through the finders.""" 

7151 

7152 def run_search(self, search: 'SearchQuery', user: 'User') -> list['SearchResult']: 

7153 """Run a search query. 

7154 

7155 Runs the finders of the query layers, the project finders and the application 

7156 finders the user may use and which can run the query. 

7157 

7158 Args: 

7159 search: Search query. 

7160 user: User running the search. 

7161 

7162 Returns: 

7163 Search results, at most ``search.limit`` if a limit is given. 

7164 """ 

7165 

7166 

7167class Finder(Node): 

7168 """Search provider, finds features for search queries.""" 

7169 

7170 title: str 

7171 """Finder title.""" 

7172 category: str 

7173 """Category assigned to the results.""" 

7174 

7175 supportsFilterSearch: bool = False 

7176 """The finder supports filter searches.""" 

7177 supportsGeometrySearch: bool = False 

7178 """The finder supports geometry searches.""" 

7179 supportsKeywordSearch: bool = False 

7180 """The finder supports keyword searches.""" 

7181 

7182 withFilter: bool 

7183 """Filter searches are enabled.""" 

7184 withGeometry: bool 

7185 """Geometry searches are enabled.""" 

7186 withKeyword: bool 

7187 """Keyword searches are enabled.""" 

7188 

7189 templates: list['Template'] 

7190 """Templates to format the found features.""" 

7191 models: list['Model'] 

7192 """Models used to read the features.""" 

7193 sourceLayers: list['SourceLayer'] 

7194 """Source layers to search in, for finders of OWS and QGIS sources.""" 

7195 

7196 tolerance: 'UomValue' 

7197 """Tolerance for geometry searches.""" 

7198 

7199 def run(self, search: SearchQuery, user: 'User', layer: Optional['Layer'] = None) -> list['Feature']: 

7200 """Run a search query. 

7201 

7202 Args: 

7203 search: Search query. 

7204 user: User running the search. 

7205 layer: Layer the finder belongs to, if any. 

7206 

7207 Returns: 

7208 Found features. 

7209 """ 

7210 

7211 def can_run(self, search: SearchQuery, user: 'User') -> bool: 

7212 """Check if the finder can run a search query. 

7213 

7214 Args: 

7215 search: Search query. 

7216 user: User running the search. 

7217 

7218 Returns: 

7219 ``True`` if the finder can run the query. 

7220 """ 

7221################################################################################ 

7222 

7223 

7224################################################################################ 

7225# /base/storage/types.pyinc 

7226 

7227 

7228class StorageManager(Node): 

7229 """Storage manager, holds the storage providers.""" 

7230 

7231 providers: list['StorageProvider'] 

7232 """Configured storage providers.""" 

7233 

7234 def create_provider(self, cfg: Config, **kwargs) -> 'StorageProvider': 

7235 """Create a storage provider and add it to the manager. 

7236 

7237 A provider with the same uid replaces the existing one. 

7238 

7239 Args: 

7240 cfg: Provider configuration. 

7241 **kwargs: Extra configuration values. 

7242 

7243 Returns: 

7244 The new provider. 

7245 """ 

7246 

7247 def find_provider(self, uid: Optional[str] = None) -> Optional['StorageProvider']: 

7248 """Find a storage provider. 

7249 

7250 Args: 

7251 uid: Provider uid. If not given, the first provider is returned. 

7252 

7253 Returns: 

7254 The provider, or ``None`` if not found. 

7255 """ 

7256 

7257 

7258 

7259class StorageRecord(Data): 

7260 """Storage record.""" 

7261 

7262 name: str 

7263 """Record name.""" 

7264 userUid: str 

7265 """Uid of the user who last wrote the record.""" 

7266 data: str 

7267 """Serialized record data.""" 

7268 created: 'datetime.datetime' 

7269 """Record create time.""" 

7270 updated: 'datetime.datetime' 

7271 """Record update time.""" 

7272 

7273 

7274class StorageProvider(Node): 

7275 """Storage provider, stores named records grouped by category.""" 

7276 

7277 def list_names(self, category: str) -> list[str]: 

7278 """List the record names in a category. 

7279 

7280 Args: 

7281 category: Category name. 

7282 

7283 Returns: 

7284 Record names. 

7285 """ 

7286 

7287 def read(self, category: str, name: str) -> Optional['StorageRecord']: 

7288 """Read a record. 

7289 

7290 Args: 

7291 category: Category name. 

7292 name: Record name. 

7293 

7294 Returns: 

7295 The record, or ``None`` if not found. 

7296 """ 

7297 

7298 def write(self, category: str, name: str, data: str, user_uid: str): 

7299 """Create a record or update an existing one. 

7300 

7301 Args: 

7302 category: Category name. 

7303 name: Record name. 

7304 data: Serialized record data. 

7305 user_uid: Uid of the user who writes the record. 

7306 """ 

7307 

7308 def delete(self, category: str, name: str): 

7309 """Delete a record. 

7310 

7311 Args: 

7312 category: Category name. 

7313 name: Record name. 

7314 """ 

7315################################################################################ 

7316 

7317 

7318################################################################################ 

7319# /base/template/types.pyinc 

7320 

7321 

7322class TemplateArgs(Data): 

7323 """Template arguments.""" 

7324 

7325 app: 'Application' 

7326 """Application object.""" 

7327 locale: 'Locale' 

7328 """Current locale.""" 

7329 date: 'DateFormatter' 

7330 """Locale-aware date formatter.""" 

7331 time: 'TimeFormatter' 

7332 """Locale-aware time formatter.""" 

7333 number: 'NumberFormatter' 

7334 """Locale-aware number formatter.""" 

7335 

7336 

7337class TemplateRenderInput(Data): 

7338 """Template render input.""" 

7339 

7340 args: dict | Data 

7341 """Template arguments.""" 

7342 crs: 'Crs' 

7343 """CRS for maps.""" 

7344 dpi: int 

7345 """Output resolution in dots per inch.""" 

7346 locale: 'Locale' 

7347 """Locale for the output.""" 

7348 maps: list[MapRenderInput] 

7349 """Maps to render, for print templates.""" 

7350 mimeOut: str 

7351 """Requested output MIME type.""" 

7352 notify: Callable 

7353 """Callback for progress messages.""" 

7354 project: 'Project' 

7355 """Current project.""" 

7356 user: 'User' 

7357 """Current user.""" 

7358 

7359 

7360class TemplateQualityLevel(Config): 

7361 """Print quality level users can choose.""" 

7362 

7363 name: str 

7364 """Quality level name shown to users.""" 

7365 dpi: int 

7366 """Print resolution in dots per inch.""" 

7367 

7368 

7369class Template(Node): 

7370 """Template, generates content from data.""" 

7371 

7372 mapSize: UomSize 

7373 """Default map size for the template.""" 

7374 mimeTypes: list[str] 

7375 """MIME types the template can generate.""" 

7376 pageSize: UomSize 

7377 """Default page size for printing.""" 

7378 pageMargin: UomExtent 

7379 """Default page margin for printing.""" 

7380 subject: str 

7381 """Template subject, the purpose the template serves, like ``feature.description``.""" 

7382 title: str 

7383 """Template title.""" 

7384 

7385 def render(self, tri: TemplateRenderInput) -> ContentResponse: 

7386 """Render the template. 

7387 

7388 Args: 

7389 tri: Render input. 

7390 

7391 Returns: 

7392 A response with the generated content. 

7393 """ 

7394 

7395 

7396class TemplateManager(Node): 

7397 """Template manager, finds templates by subject and creates them from files.""" 

7398 

7399 def find_templates(self, subjects: list[str], where: list[Node], user: 'User' = None, mime: MimeType = None) -> list['Template']: 

7400 """Find templates for several subjects. 

7401 

7402 Args: 

7403 subjects: Template subjects. 

7404 where: Objects whose templates are searched, in this order. 

7405 user: If given, only templates this user can use. 

7406 mime: If given, only templates which can produce this MIME type. 

7407 

7408 Returns: 

7409 Found templates, one per subject at most. 

7410 """ 

7411 

7412 def find_template(self, subject: str, where: list[Node], user: 'User' = None, mime: MimeType = None) -> Optional['Template']: 

7413 """Find a template for a subject. 

7414 

7415 The templates of the objects in ``where`` are searched in the given order, 

7416 then the application templates. A template without ``mimeTypes`` matches any 

7417 MIME type. 

7418 

7419 Args: 

7420 subject: Template subject. 

7421 where: Objects whose templates are searched, in this order. 

7422 user: If given, only templates this user can use. 

7423 mime: If given, only templates which can produce this MIME type. 

7424 

7425 Returns: 

7426 The first matching template, or ``None``. 

7427 """ 

7428 

7429 def template_from_path(self, path: str) -> Optional['Template']: 

7430 """Create a template from a file. 

7431 

7432 The template type is derived from the file extension. 

7433 

7434 Args: 

7435 path: File path. 

7436 

7437 Returns: 

7438 A template, or ``None`` if the file is not a template. 

7439 """ 

7440################################################################################ 

7441 

7442 

7443################################################################################ 

7444# /base/web/types.pyinc 

7445 

7446 

7447class RequestMethod(Enum): 

7448 """Web request method.""" 

7449 

7450 GET = 'GET' 

7451 HEAD = 'HEAD' 

7452 POST = 'POST' 

7453 PUT = 'PUT' 

7454 DELETE = 'DELETE' 

7455 CONNECT = 'CONNECT' 

7456 OPTIONS = 'OPTIONS' 

7457 TRACE = 'TRACE' 

7458 PATCH = 'PATCH' 

7459 

7460 

7461class WebRequester: 

7462 """Web requester, gives access to an incoming web request.""" 

7463 

7464 environ: dict 

7465 """Request environment.""" 

7466 method: RequestMethod 

7467 """Request method.""" 

7468 contentType: str 

7469 """Request content type.""" 

7470 root: 'Root' 

7471 """Object tree root.""" 

7472 site: 'WebSite' 

7473 """Website the request is processed for.""" 

7474 

7475 session: 'AuthSession' 

7476 """Current session.""" 

7477 user: 'User' 

7478 """Current user.""" 

7479 

7480 isGet: bool 

7481 """The request is a GET request.""" 

7482 isPost: bool 

7483 """The request is a POST request.""" 

7484 isApi: bool 

7485 """The request provides json data in the POST body.""" 

7486 isForm: bool 

7487 """The request provides form data in the POST body.""" 

7488 isSecure: bool 

7489 """The request is made over https.""" 

7490 

7491 scheme: str 

7492 """Request scheme, http or https.""" 

7493 host: str 

7494 """Request host name, without the port, empty if the host is invalid.""" 

7495 port: int 

7496 """Request port, 0 if not given.""" 

7497 ip: str 

7498 """Client address.""" 

7499 

7500 def parse(self): 

7501 """Parse the request path, the parameters and the structured payload. 

7502 

7503 Also determines the scheme, host, port and client address, taking proxy 

7504 headers into account if the site has proxies. 

7505 

7506 Raises: 

7507 ``gws.base.web.error.HTTPException``: If the request path, the host or the payload is invalid. 

7508 """ 

7509 

7510 def params(self) -> dict: 

7511 """Return the GET parameters. 

7512 

7513 Returns: 

7514 Parameters from the query string and from the request path. 

7515 """ 

7516 

7517 def query_params(self) -> dict: 

7518 """Return the GET parameters from the query string. 

7519 

7520 Returns: 

7521 Query string parameters. 

7522 """ 

7523 

7524 def path(self) -> str: 

7525 """Return the request path after the command. 

7526 

7527 Returns: 

7528 The rest of the path after ``/_/<command>/``. 

7529 """ 

7530 

7531 def struct(self) -> dict: 

7532 """Return the structured payload of an API request. 

7533 

7534 Returns: 

7535 The decoded JSON or MessagePack payload. 

7536 """ 

7537 

7538 def command(self) -> str: 

7539 """Return the command name. 

7540 

7541 Returns: 

7542 The command from the path, or from the ``cmd`` parameter. 

7543 """ 

7544 

7545 def data(self) -> bytes: 

7546 """Return the raw POST data, unzipped if gzip-encoded. 

7547 

7548 Returns: 

7549 POST data, empty for non-POST requests. 

7550 

7551 Raises: 

7552 ``gws.base.web.error.HTTPException``: If the content length is invalid or too large, or the data cannot be unzipped. 

7553 """ 

7554 

7555 def form(self) -> list[tuple[str, Any]]: 

7556 """Return the POST form data. 

7557 

7558 Returns: 

7559 A list of ``(key, value)`` tuples, including uploaded files; empty if the request is not a form. 

7560 

7561 Raises: 

7562 ``gws.base.web.error.HTTPException``: If the form data cannot be decoded. 

7563 """ 

7564 

7565 def text(self) -> str: 

7566 """Return the POST data decoded to text, with the charset of the request. 

7567 

7568 Returns: 

7569 POST data as text. 

7570 

7571 Raises: 

7572 ``gws.base.web.error.HTTPException``: If the data cannot be decoded. 

7573 """ 

7574 

7575 def cookie(self, key: str, default: str = '') -> str: 

7576 """Get a cookie. 

7577 

7578 Args: 

7579 key: Cookie name. 

7580 default: Default value. 

7581 

7582 Returns: 

7583 A cookie value. 

7584 """ 

7585 

7586 def header(self, key: str, default: str = '') -> str: 

7587 """Get a header. 

7588 

7589 Args: 

7590 key: Header name. 

7591 default: Default value. 

7592 

7593 Returns: 

7594 A header value. 

7595 """ 

7596 

7597 def has_param(self, key: str) -> bool: 

7598 """Check if a GET parameter exists, ignoring case. 

7599 

7600 Args: 

7601 key: Parameter name. 

7602 

7603 Returns: 

7604 ``True`` if the parameter exists. 

7605 """ 

7606 

7607 def param(self, key: str, default: str = '') -> str: 

7608 """Get a GET parameter, ignoring case. 

7609 

7610 Args: 

7611 key: Parameter name. 

7612 default: Default value. 

7613 

7614 Returns: 

7615 A parameter value. 

7616 """ 

7617 

7618 def env(self, key: str, default: str = '') -> str: 

7619 """Get a WSGI environment variable. 

7620 

7621 Args: 

7622 key: Variable name. 

7623 default: Default value. 

7624 

7625 Returns: 

7626 A variable value. 

7627 """ 

7628 

7629 def content_responder(self, response: ContentResponse) -> 'WebResponder': 

7630 """Create a responder for a content response. 

7631 

7632 Args: 

7633 response: Response with literal content or a content path. 

7634 

7635 Returns: 

7636 A responder. 

7637 """ 

7638 

7639 def redirect_responder(self, response: RedirectResponse) -> 'WebResponder': 

7640 """Create a responder for a redirect response. 

7641 

7642 Args: 

7643 response: Redirect response. 

7644 

7645 Returns: 

7646 A responder. 

7647 """ 

7648 

7649 def api_responder(self, response: Response) -> 'WebResponder': 

7650 """Create a responder for an API (structured) response. 

7651 

7652 The response is encoded as JSON or MessagePack, depending on the request. 

7653 

7654 Args: 

7655 response: Response object. 

7656 

7657 Returns: 

7658 A responder. 

7659 """ 

7660 

7661 def error_responder(self, exc: Exception) -> 'WebResponder': 

7662 """Create a responder for an exception. 

7663 

7664 Args: 

7665 exc: An exception; anything but an HTTP exception results in a 500 response. 

7666 

7667 Returns: 

7668 A responder. 

7669 """ 

7670 

7671 def absolute_url_for(self, request_path: str, **params) -> str: 

7672 """Create an absolute URL pointing to the requested host. 

7673 

7674 Args: 

7675 request_path: Request path. 

7676 **params: Additional GET parameters. 

7677 

7678 Returns: 

7679 A URL. 

7680 """ 

7681 

7682 def relative_url_for(self, request_path: str, **params) -> str: 

7683 """Create a host-relative URL. 

7684 

7685 Args: 

7686 request_path: Request path. 

7687 **params: Additional GET parameters. 

7688 

7689 Returns: 

7690 A URL. 

7691 """ 

7692 

7693 def canonical_url_for(self, request_path: str, **params) -> str: 

7694 """Create an absolute URL pointing to the canonical host. 

7695 

7696 Args: 

7697 request_path: Request path. 

7698 **params: Additional GET parameters. 

7699 

7700 Returns: 

7701 A URL. 

7702 """ 

7703 

7704 def set_session(self, session: 'AuthSession'): 

7705 """Attach a session to the requester and set the user from it. 

7706 

7707 Args: 

7708 session: A session object. 

7709 """ 

7710 

7711 

7712class WebResponder: 

7713 """Web responder, builds and sends the response to a web request.""" 

7714 

7715 status: int 

7716 """Response status.""" 

7717 

7718 def send_response(self, environ: dict, start_response: Callable): 

7719 """Send the response to the client. 

7720 

7721 Args: 

7722 environ: WSGI environment. 

7723 start_response: WSGI ``start_response`` function. 

7724 

7725 Returns: 

7726 The WSGI response iterable. 

7727 """ 

7728 

7729 def set_cookie(self, key: str, value: str, **kwargs): 

7730 """Set a cookie. 

7731 

7732 Args: 

7733 key: Cookie name. 

7734 value: Cookie value. 

7735 **kwargs: Cookie options. 

7736 """ 

7737 

7738 def delete_cookie(self, key: str, **kwargs): 

7739 """Delete a cookie. 

7740 

7741 Args: 

7742 key: Cookie name. 

7743 **kwargs: Cookie options. 

7744 """ 

7745 

7746 def set_status(self, status: int): 

7747 """Set the response status. 

7748 

7749 Args: 

7750 status: HTTP status code. 

7751 """ 

7752 

7753 def add_header(self, key: str, value: str): 

7754 """Add a header. 

7755 

7756 Args: 

7757 key: Header name. 

7758 value: Header value. 

7759 """ 

7760 

7761 def set_body(self, body: str | bytes): 

7762 """Set the response body. 

7763 

7764 Args: 

7765 body: New response body; strings are encoded as UTF-8. 

7766 """ 

7767 

7768 

7769class WebDocumentRoot(Data): 

7770 """Directory served over the web.""" 

7771 

7772 dir: DirPath 

7773 """Local directory.""" 

7774 allowMime: list[str] 

7775 """Allowed mime types.""" 

7776 denyMime: list[str] 

7777 """Restricted mime types.""" 

7778 

7779 

7780class WebRewriteRule(Data): 

7781 """URL rewrite rule.""" 

7782 

7783 pattern: Regex 

7784 """URL matching pattern.""" 

7785 target: str 

7786 """Rule target, with ``$1``, ``$2`` etc. placeholders for the pattern groups.""" 

7787 reversed: bool 

7788 """The rule rewrites URLs generated by the server, not incoming URLs.""" 

7789 

7790 

7791class WebCors(Data): 

7792 """CORS options.""" 

7793 

7794 allowCredentials: bool 

7795 """Allow credentials in cross-origin requests.""" 

7796 allowHeaders: str 

7797 """Headers allowed in cross-origin requests.""" 

7798 allowMethods: str 

7799 """Methods allowed in cross-origin requests.""" 

7800 allowOrigin: str 

7801 """Origins allowed to make cross-origin requests.""" 

7802 

7803 

7804class WebManager(Node): 

7805 """Web manager, holds the web site.""" 

7806 

7807 site: 'WebSite' 

7808 """Configured web site.""" 

7809 

7810 

7811class WebSite(Node): 

7812 """Web site the server responds to.""" 

7813 

7814 assetsRoot: Optional[WebDocumentRoot] 

7815 """Root directory for assets.""" 

7816 canonicalHost: str 

7817 """Host name for absolute canonical URLs.""" 

7818 corsOptions: WebCors 

7819 """CORS options.""" 

7820 hostnames: list[str] 

7821 """Host names this site responds to.""" 

7822 rewriteRules: list[WebRewriteRule] 

7823 """URL rewrite rules.""" 

7824 proxyCount: int 

7825 """Number of proxies in front of the server.""" 

7826 ssl: bool 

7827 """The site is served over https.""" 

7828 staticRoot: WebDocumentRoot 

7829 """Root directory for static files.""" 

7830 

7831 def url_for(self, req: 'WebRequester', path: str, mode: str, **params) -> str: 

7832 """Create a URL for a request path, applying the reversed rewrite rules. 

7833 

7834 If the path, or the rewritten path, is an absolute URL, only the parameters 

7835 are added. In the ``absolute`` and ``canonical`` modes, the URL gets the scheme 

7836 of the request. The host is the canonical host in the ``canonical`` mode, and 

7837 the request host and port otherwise or if there is no canonical host. 

7838 

7839 Args: 

7840 req: Web requester. 

7841 path: Request path. 

7842 mode: ``absolute``, ``relative`` or ``canonical``. 

7843 **params: Extra GET parameters. 

7844 

7845 Returns: 

7846 A URL. 

7847 

7848 Raises: 

7849 ``gws.BadRequestError``: If an absolute URL is requested and there is no host. 

7850 """ 

7851################################################################################ 

7852 

7853 

7854################################################################################ 

7855# /base/exporter/types.pyinc 

7856 

7857 

7858class ExportArgs(Data): 

7859 """Arguments passed to ``Exporter.run``.""" 

7860 

7861 exporter: 'Exporter' 

7862 """The exporter.""" 

7863 features: Optional[list['Feature']] 

7864 """Features to export.""" 

7865 shape: Optional['Shape'] 

7866 """Shape from the export request.""" 

7867 project: 'Project' 

7868 """Project of the export request.""" 

7869 user: 'User' 

7870 """User the export runs for.""" 

7871 notify: Callable 

7872 """Progress callback, called with an event name.""" 

7873 maxErrors: int = 100 

7874 """Maximum number of errors collected in the result.""" 

7875 

7876 

7877class ExportTarget(Enum): 

7878 """Export target.""" 

7879 

7880 file = 'file' 

7881 """Save the export result to a file on the server.""" 

7882 download = 'download' 

7883 """Return the export result for download.""" 

7884 

7885 

7886class ExportResult(Data): 

7887 """Export result.""" 

7888 

7889 path: str 

7890 """Path of the result file, empty if nothing was exported.""" 

7891 mimeType: str 

7892 """Mime type of the result file.""" 

7893 numFiles: int 

7894 """Number of files written.""" 

7895 numFeaturesTotal: int 

7896 """Number of requested features.""" 

7897 numFeaturesExported: int 

7898 """Number of exported features.""" 

7899 errors: list[str] 

7900 """Error messages for features that were not exported.""" 

7901 

7902 

7903class FeatureExportStrategy(Enum): 

7904 """How exported features are obtained.""" 

7905 

7906 load = 'load' 

7907 """Load features by ids from the source model.""" 

7908 client = 'client' 

7909 """Export features using properties as received from the client.""" 

7910 

7911 

7912class ExportRequestType(Enum): 

7913 """Kind of data to export.""" 

7914 

7915 vector = 'vector' 

7916 """Vector features.""" 

7917 raster = 'raster' 

7918 """Raster data.""" 

7919 

7920 

7921class ExportRequest(Request): 

7922 """Export request from the client.""" 

7923 

7924 type: ExportRequestType 

7925 """Kind of data to export.""" 

7926 exporterUid: str 

7927 """Uid of the exporter.""" 

7928 features: Optional[list['FeatureProps']] 

7929 """Features to export.""" 

7930 shape: Optional['ShapeProps'] 

7931 """Shape passed to the exporter.""" 

7932 

7933 

7934class ExportResponse(Response): 

7935 """Export response with the content of the result file.""" 

7936 

7937 content: str | bytes 

7938 """File content.""" 

7939 contentFilename: str 

7940 """File name.""" 

7941 mimeType: str 

7942 """Mime type.""" 

7943 

7944 

7945class ExporterManager(Node): 

7946 """Exporter manager.""" 

7947 

7948 def start_export_job(self, request: ExportRequest, user: 'User') -> 'JobStatusResponse': 

7949 """Create and schedule a background export job. 

7950 

7951 Args: 

7952 request: Export request. 

7953 user: User the export runs for. 

7954 

7955 Returns: 

7956 The status of the new job. 

7957 """ 

7958 

7959 def exec_export(self, request: ExportRequest, out_path: str): 

7960 """Run an export directly, as the system user, and copy the result file. 

7961 

7962 Args: 

7963 request: Export request. 

7964 out_path: Path to copy the result file to. 

7965 

7966 Returns: 

7967 The export result. 

7968 

7969 Raises: 

7970 ``gws.Error``: If no features were exported. 

7971 """ 

7972 

7973 def list_exporters(self, where: list['Node'], user: 'User') -> list['Exporter']: 

7974 """List the exporters of the given objects that the user can use. 

7975 

7976 Of several exporters with the same title, only the first one is listed. 

7977 

7978 Args: 

7979 where: Objects with an ``exporters`` list, e.g. a project and the application. 

7980 ``None`` entries are ignored. 

7981 user: User. 

7982 

7983 Returns: 

7984 A list of exporters. 

7985 """ 

7986 

7987 def get_exporter(self, where: list['Node'], uid: str, user: 'User') -> Optional['Exporter']: 

7988 """Find an exporter by uid among the exporters the user can use. 

7989 

7990 Args: 

7991 where: Objects with an ``exporters`` list, e.g. a project and the application. 

7992 uid: Exporter uid. 

7993 user: User. 

7994 

7995 Returns: 

7996 The exporter, or ``None`` if it is not found. 

7997 """ 

7998 

7999 

8000class Exporter(Node): 

8001 """Exporter. 

8002 

8003 Writes features to files in a specific format. 

8004 """ 

8005 

8006 title: str 

8007 """Exporter title, shown in the client.""" 

8008 options: dict 

8009 """Format-specific options, passed to the GDAL driver.""" 

8010 

8011 supportsVector: bool 

8012 """The exporter can export vector features.""" 

8013 supportsRaster: bool 

8014 """The exporter can export raster data.""" 

8015 supportsMultiLayer: bool 

8016 """The format can hold several layers in one file.""" 

8017 

8018 withNoGeometry: bool 

8019 """Export features without geometry instead of skipping them.""" 

8020 withMixedGeometry: bool 

8021 """Allow different geometry types in one layer instead of skipping features.""" 

8022 withMixedCrs: bool 

8023 """Allow different CRS in one layer instead of skipping features.""" 

8024 withMultiLayer: bool 

8025 """Write all layers to one file.""" 

8026 

8027 supportedAttributeTypes: Optional[list[gws.AttributeType]] 

8028 """Attribute types the exporter can write. If empty, the types supported by GDAL are used.""" 

8029 

8030 def run(self, ea: ExportArgs, er: ExportResult): 

8031 """Export the features. 

8032 

8033 Writes the result file and sets its path, the mime type, the counts 

8034 and errors in the export result. 

8035 

8036 Args: 

8037 ea: Export arguments. 

8038 er: Export result, filled by the exporter. 

8039 """ 

8040################################################################################ 

8041 

8042 

8043 

8044################################################################################ 

8045# /base/application/types.pyinc 

8046 

8047 

8048class MiddlewareManager(Node): 

8049 """Middleware manager. 

8050 

8051 Middleware objects process every web request: the web server calls 

8052 ``enter_middleware`` on each of them in dependency order before the action, 

8053 and ``exit_middleware`` in reverse order after it. 

8054 """ 

8055 

8056 def register(self, obj: Node, name: str, depends_on: Optional[list[str]] = None): 

8057 """Register an object as a middleware. 

8058 

8059 Args: 

8060 obj: The middleware object. 

8061 name: Middleware name, for example ``db`` or ``auth``. 

8062 depends_on: Names of middleware that must run before this one. 

8063 """ 

8064 

8065 def objects(self) -> list[Node]: 

8066 """Return the registered middleware objects in dependency order. 

8067 

8068 Returns: 

8069 A list of middleware objects, dependencies first. 

8070 

8071 Raises: 

8072 Error: If the dependencies are cyclic or refer to an unknown name. 

8073 """ 

8074 

8075 

8076class TemplateOptions(Data): 

8077 """Options for the built-in application and project home pages.""" 

8078 

8079 withLogin: bool = True 

8080 """Show the login form on the home page.""" 

8081 footerText: Optional[str] 

8082 """HTML text for the home page footer.""" 

8083 withGws: bool = True 

8084 """Show the GWS logo in the home page footer.""" 

8085 homeResources: Optional[list[str]] 

8086 """Extra resource URLs for the home page.""" 

8087 projectResources: Optional[list[str]] 

8088 """Extra resource URLs for the project page.""" 

8089 

8090 

8091class Application(Node): 

8092 """Application object. 

8093 

8094 The top-level node of the configuration tree. It holds the managers, the 

8095 global objects and the projects, and is available as ``root.app``. 

8096 """ 

8097 

8098 client: 'Client' 

8099 """Default client, used by projects without their own client configuration.""" 

8100 

8101 localeUids: list[str] 

8102 """Default locale uids for all projects.""" 

8103 

8104 metadata: 'Metadata' 

8105 """Application metadata.""" 

8106 

8107 monitor: 'ServerMonitor' 

8108 """Server monitor, watches configuration files and runs periodic tasks.""" 

8109 

8110 templateOptions: TemplateOptions 

8111 """Options for the built-in home page templates.""" 

8112 

8113 title: str 

8114 """Application title.""" 

8115 

8116 vars: dict 

8117 """Custom variables from the configuration.""" 

8118 

8119 version: str 

8120 """Application version, for example ``8.5.3``.""" 

8121 

8122 versionString: str 

8123 """Version string for display, with the revision if known.""" 

8124 

8125 def supported_crs(self) -> list['Crs']: 

8126 """Return all CRS supported by the application. 

8127 

8128 These are the CRS of all maps and the CRS supported by OWS services, 

8129 plus the registered ones. The list is computed on the first call. 

8130 

8131 Returns: 

8132 A list of CRS objects, sorted by srid. 

8133 """ 

8134 

8135 def register_supported_crs(self, crs: 'Crs'): 

8136 """Register an additional supported CRS. 

8137 

8138 Must be called during configuration. 

8139 

8140 Args: 

8141 crs: The CRS object. 

8142 """ 

8143 

8144 defaultPrinter: 'Printer' 

8145 """Default printer, used when no printer is configured.""" 

8146 

8147 actionMgr: 'ActionManager' 

8148 """Action manager.""" 

8149 

8150 authMgr: 'AuthManager' 

8151 """Authorization manager.""" 

8152 

8153 databaseMgr: 'DatabaseManager' 

8154 """Database manager.""" 

8155 

8156 exporterMgr: 'ExporterManager' 

8157 """Exporter manager.""" 

8158 

8159 jobMgr: 'JobManager' 

8160 """Job manager.""" 

8161 

8162 middlewareMgr: 'MiddlewareManager' 

8163 """Middleware manager.""" 

8164 

8165 modelMgr: 'ModelManager' 

8166 """Model manager.""" 

8167 

8168 printerMgr: 'PrinterManager' 

8169 """Printer manager.""" 

8170 

8171 searchMgr: 'SearchManager' 

8172 """Search manager.""" 

8173 

8174 serverMgr: 'ServerManager' 

8175 """Server manager.""" 

8176 

8177 storageMgr: 'StorageManager' 

8178 """Storage manager.""" 

8179 

8180 templateMgr: 'TemplateManager' 

8181 """Template manager.""" 

8182 

8183 webMgr: 'WebManager' 

8184 """Web manager.""" 

8185 

8186 actions: list['Action'] 

8187 """Actions available in all projects.""" 

8188 

8189 projects: list['Project'] 

8190 """Configured projects.""" 

8191 

8192 exporters: list['Exporter'] 

8193 """Global exporters.""" 

8194 

8195 finders: list['Finder'] 

8196 """Finders available in all projects.""" 

8197 

8198 templates: list['Template'] 

8199 """Global templates, including the built-in ones.""" 

8200 

8201 printers: list['Printer'] 

8202 """Global printers.""" 

8203 

8204 models: list['Model'] 

8205 """Global models.""" 

8206 

8207 owsServices: list['OwsService'] 

8208 """OWS services provided by the server.""" 

8209 

8210 def project(self, uid: str) -> Optional['Project']: 

8211 """Find a project by its uid. 

8212 

8213 Args: 

8214 uid: Project uid. 

8215 

8216 Returns: 

8217 The project, or ``None`` if not found. 

8218 """ 

8219 

8220 def helper(self, ext_type: str) -> Optional['Node']: 

8221 """Return a helper object by its type. 

8222 

8223 A helper that is not configured is created with default options on the first call. 

8224 

8225 Args: 

8226 ext_type: Helper type, for example ``upload``. 

8227 

8228 Returns: 

8229 The helper object. 

8230 

8231 Raises: 

8232 Error: If the helper type does not exist. 

8233 """ 

8234 

8235 def developer_option(self, key: str): 

8236 """Return the value of a developer option. 

8237 

8238 Developer options are configured in the ``developer`` property of the 

8239 application config and are meant for development and debugging only. 

8240 

8241 Args: 

8242 key: Option name, for example ``template.always_reload``. 

8243 

8244 Returns: 

8245 The option value, or ``None`` if it is not set. 

8246 """ 

8247################################################################################