Skip to content

Interface

dispatcher

RedisQueue

Source code in src/qgis_server_light/interface/dispatcher.py
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
class RedisQueue:
    def __init__(
        self, pool: redis.BlockingConnectionPool, redis_client: redis.Redis
    ) -> None:
        # we use this to hold connections to redis in a pool, this way we are
        # event loop safe and when creating the redis client for every call of
        # post, we only instantiate a minimal wrapper object which is cheap.
        self.pool = pool
        self.client = redis_client

    @classmethod
    async def create(cls, url: str):
        pool = redis.BlockingConnectionPool.from_url(url)
        redis_client = await redis.Redis(connection_pool=pool)
        return cls(pool, redis_client)

    async def post(
        self,
        job: QslGetMapJob | QslGetFeatureInfoJob | QslLegendJob | QslGetFeatureJob,
        timeout: float = 10,
    ) -> JobResult:
        """
        Posts a new `job` to the job queue and waits maximum `timeout` seconds to complete.
        Will return a JobResult if successful or raise an error.
        """
        job_id = str(uuid4())
        creation_time = datetime.datetime.now().isoformat()
        start_time = time.time()
        if isinstance(job, QslGetMapJob):
            job = JobRunnerInfoQslGetMapJob(
                id=job_id, type=JobRunnerInfoQslGetMapJob.__name__, job=job
            )
        elif isinstance(job, QslGetFeatureInfoJob):
            job = JobRunnerInfoQslGetFeatureInfoJob(
                id=job_id, type=JobRunnerInfoQslGetFeatureInfoJob.__name__, job=job
            )
        elif isinstance(job, QslLegendJob):
            job = JobRunnerInfoQslLegendJob(
                id=job_id, type=JobRunnerInfoQslLegendJob.__name__, job=job
            )
        elif isinstance(job, QslGetFeatureJob):
            job = JobRunnerInfoQslGetFeatureJob(
                id=job_id, type=JobRunnerInfoQslGetFeatureJob.__name__, job=job
            )
        else:
            raise TypeError(f"Unsupported job type: {type(job)}")
        async with self.client.pipeline() as p:
            logging.info(f"{job_id} pushed")
            await p.rpush("jobs", JsonSerializer().render(job))
            await p.hset(job_id, "status", Status.QUEUED.value)
            await p.hset(job_id, f"timestamp.{Status.QUEUED.value}", creation_time)
            await p.hset(job_id, "timestamp", creation_time)
            await p.execute()

            async with self.client.pubsub() as ps:
                await ps.subscribe(f"notifications:{job_id}")
                try:
                    async with async_to(timeout):
                        while True:
                            message = await ps.get_message(
                                timeout=timeout, ignore_subscribe_messages=True
                            )
                            if not message:
                                continue  # https://github.com/redis/redis-py/issues/733
                            status_binary = await self.client.hget(job_id, "status")
                            status = status_binary.decode()
                            logging.info(f"Job {job_id} {status}")
                            if status == Status.SUCCESS.value:
                                result = pickle.loads(message["data"])
                                await asyncio.create_task(self.client.delete(job_id))
                                duration = time.time() - start_time
                                logging.debug(f"duration of job execution: {duration}")
                                return result
                            elif status == Status.FAILURE.value:
                                error = await self.client.hget(job_id, "error")
                                logging.error(
                                    f"Job {job_id} {status} with: {error.decode()}"
                                )
                                raise RuntimeError()
                except (asyncio.TimeoutError, asyncio.exceptions.CancelledError) as err:
                    logging.info(f"{job_id} timeout")
                    await self.client.delete(job_id)
                    raise

client = redis_client instance-attribute

pool = pool instance-attribute

__init__(pool, redis_client)

Source code in src/qgis_server_light/interface/dispatcher.py
37
38
39
40
41
42
43
44
def __init__(
    self, pool: redis.BlockingConnectionPool, redis_client: redis.Redis
) -> None:
    # we use this to hold connections to redis in a pool, this way we are
    # event loop safe and when creating the redis client for every call of
    # post, we only instantiate a minimal wrapper object which is cheap.
    self.pool = pool
    self.client = redis_client

create(url) async classmethod

Source code in src/qgis_server_light/interface/dispatcher.py
46
47
48
49
50
@classmethod
async def create(cls, url: str):
    pool = redis.BlockingConnectionPool.from_url(url)
    redis_client = await redis.Redis(connection_pool=pool)
    return cls(pool, redis_client)

post(job, timeout=10) async

Posts a new job to the job queue and waits maximum timeout seconds to complete. Will return a JobResult if successful or raise an error.

Source code in src/qgis_server_light/interface/dispatcher.py
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
async def post(
    self,
    job: QslGetMapJob | QslGetFeatureInfoJob | QslLegendJob | QslGetFeatureJob,
    timeout: float = 10,
) -> JobResult:
    """
    Posts a new `job` to the job queue and waits maximum `timeout` seconds to complete.
    Will return a JobResult if successful or raise an error.
    """
    job_id = str(uuid4())
    creation_time = datetime.datetime.now().isoformat()
    start_time = time.time()
    if isinstance(job, QslGetMapJob):
        job = JobRunnerInfoQslGetMapJob(
            id=job_id, type=JobRunnerInfoQslGetMapJob.__name__, job=job
        )
    elif isinstance(job, QslGetFeatureInfoJob):
        job = JobRunnerInfoQslGetFeatureInfoJob(
            id=job_id, type=JobRunnerInfoQslGetFeatureInfoJob.__name__, job=job
        )
    elif isinstance(job, QslLegendJob):
        job = JobRunnerInfoQslLegendJob(
            id=job_id, type=JobRunnerInfoQslLegendJob.__name__, job=job
        )
    elif isinstance(job, QslGetFeatureJob):
        job = JobRunnerInfoQslGetFeatureJob(
            id=job_id, type=JobRunnerInfoQslGetFeatureJob.__name__, job=job
        )
    else:
        raise TypeError(f"Unsupported job type: {type(job)}")
    async with self.client.pipeline() as p:
        logging.info(f"{job_id} pushed")
        await p.rpush("jobs", JsonSerializer().render(job))
        await p.hset(job_id, "status", Status.QUEUED.value)
        await p.hset(job_id, f"timestamp.{Status.QUEUED.value}", creation_time)
        await p.hset(job_id, "timestamp", creation_time)
        await p.execute()

        async with self.client.pubsub() as ps:
            await ps.subscribe(f"notifications:{job_id}")
            try:
                async with async_to(timeout):
                    while True:
                        message = await ps.get_message(
                            timeout=timeout, ignore_subscribe_messages=True
                        )
                        if not message:
                            continue  # https://github.com/redis/redis-py/issues/733
                        status_binary = await self.client.hget(job_id, "status")
                        status = status_binary.decode()
                        logging.info(f"Job {job_id} {status}")
                        if status == Status.SUCCESS.value:
                            result = pickle.loads(message["data"])
                            await asyncio.create_task(self.client.delete(job_id))
                            duration = time.time() - start_time
                            logging.debug(f"duration of job execution: {duration}")
                            return result
                        elif status == Status.FAILURE.value:
                            error = await self.client.hget(job_id, "error")
                            logging.error(
                                f"Job {job_id} {status} with: {error.decode()}"
                            )
                            raise RuntimeError()
            except (asyncio.TimeoutError, asyncio.exceptions.CancelledError) as err:
                logging.info(f"{job_id} timeout")
                await self.client.delete(job_id)
                raise

Status

Bases: Enum

Source code in src/qgis_server_light/interface/dispatcher.py
29
30
31
32
33
class Status(Enum):
    SUCCESS = "succeed"
    FAILURE = "failed"
    RUNNING = "running"
    QUEUED = "queued"

FAILURE = 'failed' class-attribute instance-attribute

QUEUED = 'queued' class-attribute instance-attribute

RUNNING = 'running' class-attribute instance-attribute

SUCCESS = 'succeed' class-attribute instance-attribute

job

log = logging.getLogger(__name__) module-attribute

AbstractJobRunnerInfo dataclass

Source code in src/qgis_server_light/interface/job.py
205
206
207
208
@dataclass
class AbstractJobRunnerInfo:
    id: str = field(metadata={"type": "Element", "required": True})
    type: str = field(metadata={"type": "Element", "required": True})

id: str = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

type: str = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(id, type)

AbstractWmsParams dataclass

Source code in src/qgis_server_light/interface/job.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@dataclass
class AbstractWmsParams:
    BBOX: str = field(metadata={"type": "Element", "required": True})
    CRS: str = field(metadata={"type": "Element", "required": True})
    WIDTH: str = field(metadata={"type": "Element", "required": True})
    HEIGHT: str = field(metadata={"type": "Element", "required": True})
    # optional parameters
    DPI: str = field(default=None, metadata={"type": "Element", "required": False})
    FORMAT_OPTIONS: str = field(
        default=None, metadata={"type": "Element", "required": False}
    )

    @property
    def dpi(self) -> int | None:
        if self.DPI is not None:
            return int(self.DPI)
        elif self.FORMAT_OPTIONS is not None:
            return int(self.FORMAT_OPTIONS.split(":")[-1])
        else:
            return None

    @property
    def bbox(self) -> List[str]:
        return self.BBOX.split(",")

    @classmethod
    def from_overloaded_dict(cls, params: dict):
        return cls(
            **{
                k: v
                for k, v in params.items()
                if k in inspect.signature(cls).parameters
            }
        )

BBOX: str = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

CRS: str = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

DPI: str = field(default=None, metadata={'type': 'Element', 'required': False}) class-attribute instance-attribute

FORMAT_OPTIONS: str = field(default=None, metadata={'type': 'Element', 'required': False}) class-attribute instance-attribute

HEIGHT: str = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

WIDTH: str = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

bbox: List[str] property

dpi: int | None property

__init__(BBOX, CRS, WIDTH, HEIGHT, DPI=None, FORMAT_OPTIONS=None)

from_overloaded_dict(params) classmethod

Source code in src/qgis_server_light/interface/job.py
41
42
43
44
45
46
47
48
49
@classmethod
def from_overloaded_dict(cls, params: dict):
    return cls(
        **{
            k: v
            for k, v in params.items()
            if k in inspect.signature(cls).parameters
        }
    )

FeatureQuery dataclass

Represents definitions of a query to obtain features.

Attributes:

Name Type Description
datasets List[Vector]

A list vector datasets which should be queried (and the filter will be applied to).

alias Optional[List[str]]

An optional list of alias names. This has to be the same length as the list of datasets.

filter Optional[str]

An optional filter. It is a String which can be interpreted as a OgcFilter consumable by qgis.core.QgsOgcUtils.expressionFromOgcFilter.

Source code in src/qgis_server_light/interface/job.py
156
157
158
159
160
161
162
163
164
165
166
167
168
169
@dataclass
class FeatureQuery:
    """Represents definitions of a query to obtain features.

    Attributes:
        datasets: A list vector datasets which should be queried (and the filter will be applied to).
        alias: An optional list of alias names. This has to be the same length as the list of datasets.
        filter: An optional filter. It is a String which can be interpreted as a OgcFilter consumable by
            `qgis.core.QgsOgcUtils.expressionFromOgcFilter`.
    """

    datasets: List[Vector] = field(metadata={"type": "Element", "required": True})
    alias: Optional[List[str]] = field(default=None, metadata={"type": "Element"})
    filter: Optional[str] = field(default=None, metadata={"type": "Element"})

alias: Optional[List[str]] = field(default=None, metadata={'type': 'Element'}) class-attribute instance-attribute

datasets: List[Vector] = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

filter: Optional[str] = field(default=None, metadata={'type': 'Element'}) class-attribute instance-attribute

__init__(datasets, alias=None, filter=None)

JobResult dataclass

Source code in src/qgis_server_light/interface/job.py
199
200
201
202
@dataclass
class JobResult:
    data: Any = field(metadata={"type": "Element", "required": True})
    content_type: str = field(metadata={"type": "Element", "required": True})

content_type: str = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

data: Any = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(data, content_type)

JobRunnerInfoQslGetFeatureInfoJob dataclass

Bases: AbstractJobRunnerInfo

Source code in src/qgis_server_light/interface/job.py
216
217
218
@dataclass
class JobRunnerInfoQslGetFeatureInfoJob(AbstractJobRunnerInfo):
    job: QslGetFeatureInfoJob = field(metadata={"type": "Element", "required": True})

job: QslGetFeatureInfoJob = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(id, type, job)

JobRunnerInfoQslGetFeatureJob dataclass

Bases: AbstractJobRunnerInfo

Source code in src/qgis_server_light/interface/job.py
226
227
228
@dataclass
class JobRunnerInfoQslGetFeatureJob(AbstractJobRunnerInfo):
    job: QslGetFeatureJob = field(metadata={"type": "Element", "required": True})

job: QslGetFeatureJob = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(id, type, job)

JobRunnerInfoQslGetMapJob dataclass

Bases: AbstractJobRunnerInfo

Source code in src/qgis_server_light/interface/job.py
211
212
213
@dataclass
class JobRunnerInfoQslGetMapJob(AbstractJobRunnerInfo):
    job: QslGetMapJob = field(metadata={"type": "Element", "required": True})

job: QslGetMapJob = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(id, type, job)

JobRunnerInfoQslLegendJob dataclass

Bases: AbstractJobRunnerInfo

Source code in src/qgis_server_light/interface/job.py
221
222
223
@dataclass
class JobRunnerInfoQslLegendJob(AbstractJobRunnerInfo):
    job: QslLegendJob = field(metadata={"type": "Element", "required": True})

job: QslLegendJob = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(id, type, job)

QslAbstractMapJob dataclass

Source code in src/qgis_server_light/interface/job.py
110
111
112
113
114
@dataclass
class QslAbstractMapJob:
    svg_paths: List[str] = field(
        default_factory=list, metadata={"type": "Element", "required": True}
    )

svg_paths: List[str] = field(default_factory=list, metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(svg_paths=list())

QslGetFeatureInfoJob dataclass

Bases: QslAbstractMapJob

A job to extract feature info

Source code in src/qgis_server_light/interface/job.py
142
143
144
145
146
147
148
@dataclass(kw_only=True)
class QslGetFeatureInfoJob(QslAbstractMapJob):
    """A job to extract feature info"""

    service_params: WmsGetFeatureInfoParams = field(
        metadata={"type": "Element", "required": True}
    )

service_params: WmsGetFeatureInfoParams = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(svg_paths=list(), *, service_params)

QslGetFeatureJob dataclass

As defined in WFS 2.0 specs, a request can be subdivided in a list of queries. This class is representing that.

Attributes:

Name Type Description
queries List[FeatureQuery]

A list of FeatureQuery objects.

start_index Optional[int]

The offset for paging

count Optional[int]

The number of results to return.

Source code in src/qgis_server_light/interface/job.py
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
@dataclass
class QslGetFeatureJob:
    """As defined in WFS 2.0 specs, a request can be subdivided in a list of queries.
    This class is representing that.

    Attributes:
        queries: A list of `FeatureQuery` objects.
        start_index: The offset for paging
        count: The number of results to return.
    """

    queries: List[FeatureQuery] = field(metadata={"type": "Element", "required": True})
    start_index: Optional[int] = field(
        default=0,
        metadata={
            "name": "startIndex",
            "type": "Attribute",
        },
    )
    count: Optional[int] = field(
        default=None,
        metadata={
            "type": "Attribute",
        },
    )

count: Optional[int] = field(default=None, metadata={'type': 'Attribute'}) class-attribute instance-attribute

queries: List[FeatureQuery] = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

start_index: Optional[int] = field(default=0, metadata={'name': 'startIndex', 'type': 'Attribute'}) class-attribute instance-attribute

__init__(queries, start_index=0, count=None)

QslGetMapJob dataclass

Bases: QslAbstractMapJob

A job to be rendered as an image

Source code in src/qgis_server_light/interface/job.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
@dataclass(kw_only=True)
class QslGetMapJob(QslAbstractMapJob):
    """A job to be rendered as an image"""

    service_params: WmsGetMapParams = field(
        metadata={"type": "Element", "required": True}
    )

    raster_layers: List[Raster] = field(metadata={"type": "Element", "required": True})

    vector_layers: List[Vector] = field(metadata={"type": "Element", "required": True})

    custom_layers: List[Custom] = field(metadata={"type": "Element", "required": True})

    extent_buffer: Optional[float] = field(
        default=0.0, metadata={"type": "Element", "required": False}
    )

    def get_dataset_by_name(self, name: str) -> Raster | Vector | Custom:
        for layer in self.raster_layers + self.vector_layers + self.custom_layers:
            if layer.name == name:
                return layer
        raise AttributeError(f'No layer with name "{name} was found."')

custom_layers: List[Custom] = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

extent_buffer: Optional[float] = field(default=0.0, metadata={'type': 'Element', 'required': False}) class-attribute instance-attribute

raster_layers: List[Raster] = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

service_params: WmsGetMapParams = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

vector_layers: List[Vector] = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(svg_paths=list(), *, service_params, raster_layers, vector_layers, custom_layers, extent_buffer=0.0)

get_dataset_by_name(name)

Source code in src/qgis_server_light/interface/job.py
135
136
137
138
139
def get_dataset_by_name(self, name: str) -> Raster | Vector | Custom:
    for layer in self.raster_layers + self.vector_layers + self.custom_layers:
        if layer.name == name:
            return layer
    raise AttributeError(f'No layer with name "{name} was found."')

QslLegendJob dataclass

Bases: QslAbstractMapJob

Render legend

Source code in src/qgis_server_light/interface/job.py
151
152
153
@dataclass(kw_only=True)
class QslLegendJob(QslAbstractMapJob):
    """Render legend"""

__init__(svg_paths=list())

WmsGetFeatureInfoParams dataclass

Bases: AbstractWmsParams

Source code in src/qgis_server_light/interface/job.py
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
class WmsGetFeatureInfoParams(AbstractWmsParams):
    X: str = field(default=None, metadata={"type": "Element", "required": True})
    Y: str = field(default=None, metadata={"type": "Element", "required": True})
    I: str = field(default=None, metadata={"type": "Element", "required": True})
    J: str = field(default=None, metadata={"type": "Element", "required": True})
    INFO_FORMAT: str = field(metadata={"type": "Element", "required": True})

    # mime type, only application/json supported
    QUERY_LAYERS: str = field(metadata={"type": "Element", "required": True})

    def __post_init__(self):
        x = int(self.I or self.X)
        y = int(self.J or self.Y)
        if x is None or y is None:
            raise KeyError(
                "Parameter `I` or `X` and `J` or `Y`  are mandatory for GetFeatureInfo"
            )
        if self.QUERY_LAYERS is None:
            raise KeyError("QUERY_LAYERS is mandatory in this request")

    @property
    def x(self) -> int:
        return int(self.I or self.X)

    @property
    def y(self) -> int:
        return int(self.J or self.Y)

    @property
    def query_layers(self):
        return self.QUERY_LAYERS.split(",")

I: str = field(default=None, metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

INFO_FORMAT: str = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

J: str = field(default=None, metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

QUERY_LAYERS: str = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

X: str = field(default=None, metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

Y: str = field(default=None, metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

query_layers property

x: int property

y: int property

__post_init__()

Source code in src/qgis_server_light/interface/job.py
87
88
89
90
91
92
93
94
95
def __post_init__(self):
    x = int(self.I or self.X)
    y = int(self.J or self.Y)
    if x is None or y is None:
        raise KeyError(
            "Parameter `I` or `X` and `J` or `Y`  are mandatory for GetFeatureInfo"
        )
    if self.QUERY_LAYERS is None:
        raise KeyError("QUERY_LAYERS is mandatory in this request")

WmsGetMapParams dataclass

Bases: AbstractWmsParams

Represents query parameters from the original WMS request

Source code in src/qgis_server_light/interface/job.py
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
@dataclass(kw_only=True)
class WmsGetMapParams(AbstractWmsParams):
    """Represents query parameters from the original WMS request"""

    LAYERS: str = field(metadata={"type": "Element", "required": True})

    # mime type of the requested image
    FORMAT: str = field(default="image/png", metadata={"type": "Element"})

    @property
    def layers(self) -> List[str]:
        return self.LAYERS.split(",")

    @property
    def styles(self) -> None:
        """
        Compatibility method for WMS request, can be removed after WFS work was merged.

        IMPORTANT: This means we currently only render style 'default'!

        Returns: Nothing since we only want that method for backwards compatibility.
        """
        return None

FORMAT: str = field(default='image/png', metadata={'type': 'Element'}) class-attribute instance-attribute

LAYERS: str = field(metadata={'type': 'Element', 'required': True}) class-attribute instance-attribute

layers: List[str] property

styles: None property

Compatibility method for WMS request, can be removed after WFS work was merged.

IMPORTANT: This means we currently only render style 'default'!

Returns: Nothing since we only want that method for backwards compatibility.

__init__(BBOX, CRS, WIDTH, HEIGHT, DPI=None, FORMAT_OPTIONS=None, *, LAYERS, FORMAT='image/png')

qgis

AbstractDataset dataclass

Bases: LayerLike

Source code in src/qgis_server_light/interface/qgis.py
134
135
136
@dataclass
class AbstractDataset(LayerLike):
    title: str = field(metadata={"name": "Title", "type": "Element", "required": True})

title: str = field(metadata={'name': 'Title', 'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(name, title)

AbstractFilter dataclass

Source code in src/qgis_server_light/interface/qgis.py
307
308
309
@dataclass
class AbstractFilter:
    definition: str = field(metadata={"name": "Definition", "type": "Element"})

definition: str = field(metadata={'name': 'Definition', 'type': 'Element'}) class-attribute instance-attribute

__init__(definition)

Attribute dataclass

An attribute belonging to a feature. The aim here is to drill down to simple types which can be used in consuming applications without further handling. This does not include the geometry attribute!

Attributes:

Name Type Description
name str

The name of the attribute. Has to match with the name used for exported fields with Field class.

value Union[int, float, str, bool, None]

Value as simple as possible. It has to be pickleable

Source code in src/qgis_server_light/interface/qgis.py
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
@dataclass
class Attribute:
    """An attribute belonging to a feature. The aim here is to drill down to simple types which can be used
    in consuming applications without further handling. This does not include the geometry attribute!

    Attributes:
        name: The name of the attribute. Has to match with the name used for exported fields with `Field`
            class.
        value: Value as simple as possible. It has to be
            [pickleable](https://docs.python.org/3/library/pickle.html#what-can-be-pickled-and-unpickled)

    """

    name: str = field(metadata={"name": "Name", "type": "Element", "required": True})
    value: Union[int, float, str, bool, None] = field(
        metadata={"name": "Value", "type": "Element", "required": True}
    )

name: str = field(metadata={'name': 'Name', 'type': 'Element', 'required': True}) class-attribute instance-attribute

value: Union[int, float, str, bool, None] = field(metadata={'name': 'Value', 'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(name, value)

BBox dataclass

Source code in src/qgis_server_light/interface/qgis.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
@dataclass
class BBox:
    x_min: float = field(metadata={"name": "XMin", "type": "Element", "required": True})
    x_max: float = field(metadata={"name": "XMax", "type": "Element", "required": True})
    y_min: float = field(metadata={"name": "YMin", "type": "Element", "required": True})
    y_max: float = field(metadata={"name": "YMax", "type": "Element", "required": True})
    z_min: Optional[float] = field(
        default=0.0, metadata={"name": "ZMin", "type": "Element", "required": False}
    )
    z_max: Optional[float] = field(
        default=0.0, metadata={"name": "ZMax", "type": "Element", "required": False}
    )

    def to_list(self) -> list:
        return [self.x_min, self.y_min, self.z_min, self.x_max, self.y_max, self.z_max]

    def to_string(self) -> str:
        return ",".join([str(item) for item in self.to_list()])

    def to_2d_list(self) -> list:
        return [self.x_min, self.y_min, self.x_max, self.y_max]

    def to_2d_string(self) -> str:
        return ",".join([str(item) for item in self.to_2d_list()])

    @staticmethod
    def from_string(bbox_string: str) -> "BBox":
        """
        Takes a CSV string representation of a BBox in the form:
            '<x_min>,<y_min>,<x_max>,<y_max>' or
            '<x_min>,<y_min>,<z_min>,<x_max>,<y_max>,<z_max>'
        """
        coordinates = bbox_string.split(",")
        if len(coordinates) == 4:
            return BBox(
                    x_min=float(coordinates[0]),
                    y_min=float(coordinates[1]),
                    x_max=float(coordinates[2]),
                    y_max=float(coordinates[3]),
            )
        elif len(coordinates) == 6:
            return BBox(
                x_min=float(coordinates[0]),
                y_min=float(coordinates[1]),
                z_min=float(coordinates[2]),
                x_max=float(coordinates[3]),
                y_max=float(coordinates[4]),
                z_max=float(coordinates[5]),
            )
        else:
            raise ValueError(f"Invalid bbox string: {bbox_string}")

    @staticmethod
    def from_list(bbox_list: List[float]) -> "BBox":
        """
        Takes a list representation of a BBox in the form:
            [<x_min>,<y_min>,<x_max>,<y_max>] or
            [<x_min>,<y_min>,<z_min>,<x_max>,<y_max>,<z_max>]
        """
        if len(bbox_list) == 4:
            return BBox(
                    x_min=bbox_list[0],
                    y_min=bbox_list[1],
                    x_max=bbox_list[3],
                    y_max=bbox_list[4],
            )
        elif len(bbox_list) == 6:
            return BBox(
                x_min=bbox_list[0],
                y_min=bbox_list[1],
                z_min=bbox_list[2],
                x_max=bbox_list[3],
                y_max=bbox_list[4],
                z_max=bbox_list[5],
            )
        else:
            raise ValueError(f"Invalid bbox list: {bbox_list}")

x_max: float = field(metadata={'name': 'XMax', 'type': 'Element', 'required': True}) class-attribute instance-attribute

x_min: float = field(metadata={'name': 'XMin', 'type': 'Element', 'required': True}) class-attribute instance-attribute

y_max: float = field(metadata={'name': 'YMax', 'type': 'Element', 'required': True}) class-attribute instance-attribute

y_min: float = field(metadata={'name': 'YMin', 'type': 'Element', 'required': True}) class-attribute instance-attribute

z_max: Optional[float] = field(default=0.0, metadata={'name': 'ZMax', 'type': 'Element', 'required': False}) class-attribute instance-attribute

z_min: Optional[float] = field(default=0.0, metadata={'name': 'ZMin', 'type': 'Element', 'required': False}) class-attribute instance-attribute

__init__(x_min, x_max, y_min, y_max, z_min=0.0, z_max=0.0)

from_list(bbox_list) staticmethod

Takes a list representation of a BBox in the form

[,,,] or [,,,,,]

Source code in src/qgis_server_light/interface/qgis.py
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
@staticmethod
def from_list(bbox_list: List[float]) -> "BBox":
    """
    Takes a list representation of a BBox in the form:
        [<x_min>,<y_min>,<x_max>,<y_max>] or
        [<x_min>,<y_min>,<z_min>,<x_max>,<y_max>,<z_max>]
    """
    if len(bbox_list) == 4:
        return BBox(
                x_min=bbox_list[0],
                y_min=bbox_list[1],
                x_max=bbox_list[3],
                y_max=bbox_list[4],
        )
    elif len(bbox_list) == 6:
        return BBox(
            x_min=bbox_list[0],
            y_min=bbox_list[1],
            z_min=bbox_list[2],
            x_max=bbox_list[3],
            y_max=bbox_list[4],
            z_max=bbox_list[5],
        )
    else:
        raise ValueError(f"Invalid bbox list: {bbox_list}")

from_string(bbox_string) staticmethod

Takes a CSV string representation of a BBox in the form

',,,' or ',,,,,'

Source code in src/qgis_server_light/interface/qgis.py
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@staticmethod
def from_string(bbox_string: str) -> "BBox":
    """
    Takes a CSV string representation of a BBox in the form:
        '<x_min>,<y_min>,<x_max>,<y_max>' or
        '<x_min>,<y_min>,<z_min>,<x_max>,<y_max>,<z_max>'
    """
    coordinates = bbox_string.split(",")
    if len(coordinates) == 4:
        return BBox(
                x_min=float(coordinates[0]),
                y_min=float(coordinates[1]),
                x_max=float(coordinates[2]),
                y_max=float(coordinates[3]),
        )
    elif len(coordinates) == 6:
        return BBox(
            x_min=float(coordinates[0]),
            y_min=float(coordinates[1]),
            z_min=float(coordinates[2]),
            x_max=float(coordinates[3]),
            y_max=float(coordinates[4]),
            z_max=float(coordinates[5]),
        )
    else:
        raise ValueError(f"Invalid bbox string: {bbox_string}")

to_2d_list()

Source code in src/qgis_server_light/interface/qgis.py
31
32
def to_2d_list(self) -> list:
    return [self.x_min, self.y_min, self.x_max, self.y_max]

to_2d_string()

Source code in src/qgis_server_light/interface/qgis.py
34
35
def to_2d_string(self) -> str:
    return ",".join([str(item) for item in self.to_2d_list()])

to_list()

Source code in src/qgis_server_light/interface/qgis.py
25
26
def to_list(self) -> list:
    return [self.x_min, self.y_min, self.z_min, self.x_max, self.y_max, self.z_max]

to_string()

Source code in src/qgis_server_light/interface/qgis.py
28
29
def to_string(self) -> str:
    return ",".join([str(item) for item in self.to_list()])

Config dataclass

Source code in src/qgis_server_light/interface/qgis.py
530
531
532
533
534
535
536
537
538
539
@dataclass
class Config:
    project: Project = field(
        metadata={"name": "Project", "type": "Element", "required": True}
    )
    meta_data: MetaData = field(
        metadata={"name": "MetaData", "type": "Element", "required": True}
    )
    tree: Tree = field(metadata={"name": "Tree", "type": "Element"})
    datasets: Datasets = field(metadata={"name": "DataSet", "type": "Element"})

datasets: Datasets = field(metadata={'name': 'DataSet', 'type': 'Element'}) class-attribute instance-attribute

meta_data: MetaData = field(metadata={'name': 'MetaData', 'type': 'Element', 'required': True}) class-attribute instance-attribute

project: Project = field(metadata={'name': 'Project', 'type': 'Element', 'required': True}) class-attribute instance-attribute

tree: Tree = field(metadata={'name': 'Tree', 'type': 'Element'}) class-attribute instance-attribute

__init__(project, meta_data, tree, datasets)

Contact dataclass

Source code in src/qgis_server_light/interface/qgis.py
409
410
411
412
413
414
415
416
@dataclass
class Contact:
    mail: str
    organization: str
    person: str
    phone: str
    position: str
    url: str

mail: str instance-attribute

organization: str instance-attribute

person: str instance-attribute

phone: str instance-attribute

position: str instance-attribute

url: str instance-attribute

__init__(mail, organization, person, phone, position, url)

Crs dataclass

Source code in src/qgis_server_light/interface/qgis.py
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
@dataclass
class Crs:
    auth_id: str = field(
        default=None, metadata={"name": "AuthId", "type": "Element", "required": False}
    )
    postgis_srid: int = field(
        default=None,
        metadata={"name": "PostgisSrid", "type": "Element", "required": False},
    )
    ogc_uri: str = field(
        default=None, metadata={"name": "OgcUri", "type": "Element", "required": False}
    )
    ogc_urn: str = field(
        default=None, metadata={"name": "OgcUrn", "type": "Element", "required": False}
    )

auth_id: str = field(default=None, metadata={'name': 'AuthId', 'type': 'Element', 'required': False}) class-attribute instance-attribute

ogc_uri: str = field(default=None, metadata={'name': 'OgcUri', 'type': 'Element', 'required': False}) class-attribute instance-attribute

ogc_urn: str = field(default=None, metadata={'name': 'OgcUrn', 'type': 'Element', 'required': False}) class-attribute instance-attribute

postgis_srid: int = field(default=None, metadata={'name': 'PostgisSrid', 'type': 'Element', 'required': False}) class-attribute instance-attribute

__init__(auth_id=None, postgis_srid=None, ogc_uri=None, ogc_urn=None)

Custom dataclass

Bases: DataSet

Source code in src/qgis_server_light/interface/qgis.py
399
400
401
@dataclass
class Custom(DataSet):
    pass

__init__(name, title, id, bbox, bbox_wgs84, path, source, driver, crs, styles, minimum_scale=None, maximum_scale=None, filter=None, style_name='default')

DataSet dataclass

Bases: AbstractDataset

Source code in src/qgis_server_light/interface/qgis.py
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
@dataclass
class DataSet(AbstractDataset):
    id: str = field(metadata={"name": "Id", "type": "Element", "required": False})
    bbox: BBox = field(metadata={"name": "BBox", "type": "Element", "required": True})
    bbox_wgs84: BBox = field(
        metadata={"name": "BBoxWgs84", "type": "Element", "required": True}
    )
    path: str = field(metadata={"name": "Path", "type": "Element", "required": True})
    source: DataSource = field(
        metadata={"name": "Source", "type": "Element", "required": True}
    )
    driver: str = field(
        metadata={"name": "Driver", "type": "Element", "required": True}
    )
    crs: Crs = field(metadata={"name": "Crs", "type": "Element", "required": True})
    styles: List[Style] = field(
        metadata={"name": "Styles", "type": "Element", "required": True}
    )
    minimum_scale: float = field(
        default=None,
        metadata={"name": "MinimumScale", "type": "Element"},
    )
    maximum_scale: float = field(
        default=None,
        metadata={"name": "MaximumScale", "type": "Element"},
    )
    filter: Optional[Union[OgcFilter110, OgcFilterFES20]] = field(
        default=None,
        metadata={"name": "Filter", "type": "Element"},
    )
    style_name: str = field(
        default="default", metadata={"name": "Style", "type": "Element"}
    )

    def get_style_by_name(self, name: str) -> Style | None:
        for style in self.styles:
            if name == style.name:
                return style
        return None

    def style(self) -> Style | None:
        return self.get_style_by_name(self.style_name)

bbox: BBox = field(metadata={'name': 'BBox', 'type': 'Element', 'required': True}) class-attribute instance-attribute

bbox_wgs84: BBox = field(metadata={'name': 'BBoxWgs84', 'type': 'Element', 'required': True}) class-attribute instance-attribute

crs: Crs = field(metadata={'name': 'Crs', 'type': 'Element', 'required': True}) class-attribute instance-attribute

driver: str = field(metadata={'name': 'Driver', 'type': 'Element', 'required': True}) class-attribute instance-attribute

filter: Optional[Union[OgcFilter110, OgcFilterFES20]] = field(default=None, metadata={'name': 'Filter', 'type': 'Element'}) class-attribute instance-attribute

id: str = field(metadata={'name': 'Id', 'type': 'Element', 'required': False}) class-attribute instance-attribute

maximum_scale: float = field(default=None, metadata={'name': 'MaximumScale', 'type': 'Element'}) class-attribute instance-attribute

minimum_scale: float = field(default=None, metadata={'name': 'MinimumScale', 'type': 'Element'}) class-attribute instance-attribute

path: str = field(metadata={'name': 'Path', 'type': 'Element', 'required': True}) class-attribute instance-attribute

source: DataSource = field(metadata={'name': 'Source', 'type': 'Element', 'required': True}) class-attribute instance-attribute

style_name: str = field(default='default', metadata={'name': 'Style', 'type': 'Element'}) class-attribute instance-attribute

styles: List[Style] = field(metadata={'name': 'Styles', 'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(name, title, id, bbox, bbox_wgs84, path, source, driver, crs, styles, minimum_scale=None, maximum_scale=None, filter=None, style_name='default')

get_style_by_name(name)

Source code in src/qgis_server_light/interface/qgis.py
360
361
362
363
364
def get_style_by_name(self, name: str) -> Style | None:
    for style in self.styles:
        if name == style.name:
            return style
    return None

style()

Source code in src/qgis_server_light/interface/qgis.py
366
367
def style(self) -> Style | None:
    return self.get_style_by_name(self.style_name)

DataSource dataclass

Source code in src/qgis_server_light/interface/qgis.py
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
@dataclass
class DataSource:
    postgres: PostgresSource = field(
        default=None,
        metadata={"name": "Postgres", "type": "Element", "required": False},
    )
    wmts: WmtsSource = field(
        default=None, metadata={"name": "Wmts", "type": "Element", "required": False}
    )
    wms: WmsSource = field(
        default=None, metadata={"name": "Wms", "type": "Element", "required": False}
    )
    ogr: OgrSource = field(
        default=None, metadata={"name": "Ogr", "type": "Element", "required": False}
    )
    gdal: GdalSource = field(
        default=None, metadata={"name": "Gdal", "type": "Element", "required": False}
    )
    wfs: WfsSource = field(
        default=None, metadata={"name": "Wfs", "type": "Element", "required": False}
    )
    vector_tile: VectorTileSource = field(
        default=None,
        metadata={"name": "VectorTile", "type": "Element", "required": False},
    )

gdal: GdalSource = field(default=None, metadata={'name': 'Gdal', 'type': 'Element', 'required': False}) class-attribute instance-attribute

ogr: OgrSource = field(default=None, metadata={'name': 'Ogr', 'type': 'Element', 'required': False}) class-attribute instance-attribute

postgres: PostgresSource = field(default=None, metadata={'name': 'Postgres', 'type': 'Element', 'required': False}) class-attribute instance-attribute

vector_tile: VectorTileSource = field(default=None, metadata={'name': 'VectorTile', 'type': 'Element', 'required': False}) class-attribute instance-attribute

wfs: WfsSource = field(default=None, metadata={'name': 'Wfs', 'type': 'Element', 'required': False}) class-attribute instance-attribute

wms: WmsSource = field(default=None, metadata={'name': 'Wms', 'type': 'Element', 'required': False}) class-attribute instance-attribute

wmts: WmtsSource = field(default=None, metadata={'name': 'Wmts', 'type': 'Element', 'required': False}) class-attribute instance-attribute

__init__(postgres=None, wmts=None, wms=None, ogr=None, gdal=None, wfs=None, vector_tile=None)

Datasets dataclass

Source code in src/qgis_server_light/interface/qgis.py
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
@dataclass
class Datasets:
    vector: list[Vector] = field(
        default_factory=list,
        metadata={"name": "VectorDataset", "type": "Element", "required": False},
    )
    raster: list[Raster] = field(
        default_factory=list,
        metadata={"name": "RasterDataset", "type": "Element", "required": False},
    )
    custom: list[Custom] = field(
        default_factory=list,
        metadata={"name": "Custom", "type": "Element", "required": False},
    )
    group: list[Group] = field(
        default_factory=list,
        metadata={"name": "GroupDataset", "type": "Element", "required": False},
    )

custom: list[Custom] = field(default_factory=list, metadata={'name': 'Custom', 'type': 'Element', 'required': False}) class-attribute instance-attribute

group: list[Group] = field(default_factory=list, metadata={'name': 'GroupDataset', 'type': 'Element', 'required': False}) class-attribute instance-attribute

raster: list[Raster] = field(default_factory=list, metadata={'name': 'RasterDataset', 'type': 'Element', 'required': False}) class-attribute instance-attribute

vector: list[Vector] = field(default_factory=list, metadata={'name': 'VectorDataset', 'type': 'Element', 'required': False}) class-attribute instance-attribute

__init__(vector=list(), raster=list(), custom=list(), group=list())

Feature dataclass

Feature to hold information of extracted QgsFeature.

Attributes:

Name Type Description
attributes Optional[List[Attribute]]

List of attributes definined in this feature.

geometry Optional[Attribute]

The geometry representing the feature.

Source code in src/qgis_server_light/interface/qgis.py
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
@dataclass
class Feature:
    """Feature to hold information of extracted QgsFeature.

    Attributes:
        attributes: List of attributes definined in this feature.
        geometry: The geometry representing the feature.
    """

    geometry: Optional[Attribute] = field(
        default=None, metadata={"name": "Geometry", "type": "Element"}
    )
    attributes: Optional[List[Attribute]] = field(
        default_factory=list,
        metadata={"name": "Attributes", "type": "Element"},
    )

    def __post_init__(self):
        """We always make geometry part a string (+base64 +compression)"""
        if isinstance(self.geometry.value, (bytes, bytearray)):
            self.geometry.value = urlsafe_b64encode(
                zlib.compress(self.geometry.value)
            ).decode()

    def geometry_as_bytes(self) -> bytes:
        return zlib.decompress(urlsafe_b64decode(self.geometry.value.encode()))

attributes: Optional[List[Attribute]] = field(default_factory=list, metadata={'name': 'Attributes', 'type': 'Element'}) class-attribute instance-attribute

geometry: Optional[Attribute] = field(default=None, metadata={'name': 'Geometry', 'type': 'Element'}) class-attribute instance-attribute

__init__(geometry=None, attributes=list())

__post_init__()

We always make geometry part a string (+base64 +compression)

Source code in src/qgis_server_light/interface/qgis.py
578
579
580
581
582
583
def __post_init__(self):
    """We always make geometry part a string (+base64 +compression)"""
    if isinstance(self.geometry.value, (bytes, bytearray)):
        self.geometry.value = urlsafe_b64encode(
            zlib.compress(self.geometry.value)
        ).decode()

geometry_as_bytes()

Source code in src/qgis_server_light/interface/qgis.py
585
586
def geometry_as_bytes(self) -> bytes:
    return zlib.decompress(urlsafe_b64decode(self.geometry.value.encode()))

FeatureCollection dataclass

This construction is used to abstract the content of extracted features for pickelable transportation from QSL to the queue. This way we ensure how things are constructed and transported.

Attributes:

Name Type Description
name str

The name of the feature collection. This is the key to match it to requested layers.

features List[Feature]

The features belonging to the feature collection.

Source code in src/qgis_server_light/interface/qgis.py
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
@dataclass
class FeatureCollection:
    """This construction is used to abstract the content of extracted features for pickelable transportation
    from QSL to the queue. This way we ensure how things are constructed and transported.

    Attributes:
        name: The name of the feature collection. This is the key to match it to requested layers.
        features: The features belonging to the feature collection.
    """

    name: str = field(metadata={"name": "Name", "type": "Element", "required": True})
    features: List[Feature] = field(
        default_factory=list,
        metadata={"name": "Features", "type": "Element", "required": True},
    )

features: List[Feature] = field(default_factory=list, metadata={'name': 'Features', 'type': 'Element', 'required': True}) class-attribute instance-attribute

name: str = field(metadata={'name': 'Name', 'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(name, features=list())

Field dataclass

Attributes:

Name Type Description
name str

Machine readable name of the field

type str

Original type as defined by data source (PostGIS, GPKG, etc.)

type_simple Optional[str]

Translated type for further usage. Based on the simple types of XSD spec.

alias Optional[str]

Human readable name.

nullable bool

If this field can be NULL or not.

Source code in src/qgis_server_light/interface/qgis.py
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
@dataclass
class Field:
    """
    Attributes:
        name: Machine readable name of the field
        type: Original type as defined by data source (PostGIS, GPKG, etc.)
        type_simple: Translated type for further usage. Based on the simple types of
            [XSD spec](https://www.w3.org/TR/xmlschema11-2/#built-in-primitive-datatypes).
        alias: Human readable name.
        nullable: If this field can be NULL or not.
    """

    name: str = field(metadata={"name": "Name", "type": "Element", "required": True})
    type: str = field(metadata={"name": "Type", "type": "Element", "required": True})
    type_simple: Optional[str] = field(
        default=None, metadata={"name": "SimpleType", "type": "Element"}
    )
    alias: Optional[str] = field(
        default=None, metadata={"name": "Alias", "type": "Element"}
    )
    nullable: bool = field(
        default=True, metadata={"name": "Nullable", "type": "Element"}
    )

alias: Optional[str] = field(default=None, metadata={'name': 'Alias', 'type': 'Element'}) class-attribute instance-attribute

name: str = field(metadata={'name': 'Name', 'type': 'Element', 'required': True}) class-attribute instance-attribute

nullable: bool = field(default=True, metadata={'name': 'Nullable', 'type': 'Element'}) class-attribute instance-attribute

type: str = field(metadata={'name': 'Type', 'type': 'Element', 'required': True}) class-attribute instance-attribute

type_simple: Optional[str] = field(default=None, metadata={'name': 'SimpleType', 'type': 'Element'}) class-attribute instance-attribute

__init__(name, type, type_simple=None, alias=None, nullable=True)

GdalSource dataclass

Bases: Source

Source code in src/qgis_server_light/interface/qgis.py
146
147
148
149
150
151
152
153
154
155
156
@dataclass
class GdalSource(Source):
    path: str = field(metadata={"name": "Path", "type": "Element", "required": True})
    layer_name: Optional[str] = field(
        default=None,
        metadata={"name": "LayerName", "type": "Element", "required": False},
    )

    @property
    def remote(self):
        return self.decide_remote(self.path)

layer_name: Optional[str] = field(default=None, metadata={'name': 'LayerName', 'type': 'Element', 'required': False}) class-attribute instance-attribute

path: str = field(metadata={'name': 'Path', 'type': 'Element', 'required': True}) class-attribute instance-attribute

remote property

__init__(path, layer_name=None)

Group dataclass

Bases: AbstractDataset

Source code in src/qgis_server_light/interface/qgis.py
404
405
406
@dataclass
class Group(AbstractDataset):
    pass

__init__(name, title)

LayerLike dataclass

Source code in src/qgis_server_light/interface/qgis.py
91
92
93
@dataclass
class LayerLike:
    name: str = field(metadata={"name": "Name", "type": "Element", "required": True})

name: str = field(metadata={'name': 'Name', 'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(name)

MetaData dataclass

Source code in src/qgis_server_light/interface/qgis.py
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
@dataclass
class MetaData:
    service: Service = field(
        metadata={"name": "Service", "type": "Element", "required": True}
    )
    links: Optional[List[str]] = field(
        default_factory=list,
        metadata={"name": "Links", "type": "Element", "required": False},
    )
    language: Optional[str] = field(
        default=None,
        metadata={"name": "Language", "type": "Element", "required": False},
    )
    categories: Optional[List[str]] = field(
        default_factory=list,
        metadata={"name": "Categories", "type": "Element", "required": False},
    )
    creationDateTime: datetime = field(
        default_factory=datetime.utcnow,
        metadata={"name": "CreationDateTime", "type": "Element", "required": False},
    )
    author: Optional[Contact] = field(
        default=None, metadata={"name": "Author", "type": "Element", "required": False}
    )

author: Optional[Contact] = field(default=None, metadata={'name': 'Author', 'type': 'Element', 'required': False}) class-attribute instance-attribute

categories: Optional[List[str]] = field(default_factory=list, metadata={'name': 'Categories', 'type': 'Element', 'required': False}) class-attribute instance-attribute

creationDateTime: datetime = field(default_factory=(datetime.utcnow), metadata={'name': 'CreationDateTime', 'type': 'Element', 'required': False}) class-attribute instance-attribute

language: Optional[str] = field(default=None, metadata={'name': 'Language', 'type': 'Element', 'required': False}) class-attribute instance-attribute

service: Service = field(metadata={'name': 'Service', 'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(service, links=list(), language=None, categories=list(), creationDateTime=datetime.utcnow(), author=None)

OgcFilter110 dataclass

Bases: AbstractFilter

A filter conforming to https://schemas.opengis.net/filter/1.1.0/filter.xsd

Source code in src/qgis_server_light/interface/qgis.py
312
313
314
315
316
@dataclass
class OgcFilter110(AbstractFilter):
    """
    A filter conforming to https://schemas.opengis.net/filter/1.1.0/filter.xsd
    """

__init__(definition)

OgcFilterFES20 dataclass

Bases: AbstractFilter

A filter conforming to http://www.opengis.net/fes/2.0

Source code in src/qgis_server_light/interface/qgis.py
319
320
321
322
323
@dataclass
class OgcFilterFES20(AbstractFilter):
    """
    A filter conforming to http://www.opengis.net/fes/2.0
    """

__init__(definition)

OgrSource dataclass

Bases: GdalSource

Source code in src/qgis_server_light/interface/qgis.py
159
160
161
162
163
@dataclass
class OgrSource(GdalSource):
    layer_id: Optional[str] = field(
        default=None, metadata={"name": "LayerId", "type": "Element", "required": False}
    )

layer_id: Optional[str] = field(default=None, metadata={'name': 'LayerId', 'type': 'Element', 'required': False}) class-attribute instance-attribute

__init__(path, layer_name=None, layer_id=None)

PostgresSource dataclass

Bases: Source

Source code in src/qgis_server_light/interface/qgis.py
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
@dataclass
class PostgresSource(Source):
    dbname: str = field(
        metadata={"name": "Dbname", "type": "Element", "required": True}
    )
    geometry_column: str = field(
        metadata={"name": "GeometryColumn", "type": "Element", "required": True}
    )
    host: str = field(metadata={"name": "Host", "type": "Element", "required": True})
    key: str = field(metadata={"name": "Key", "type": "Element", "required": True})
    password: str = field(
        metadata={"name": "Password", "type": "Element", "required": True}
    )
    port: str = field(metadata={"name": "Port", "type": "Element", "required": True})
    schema: str = field(
        metadata={"name": "Schema", "type": "Element", "required": True}
    )
    table: str = field(metadata={"name": "Table", "type": "Element", "required": True})
    type: str = field(metadata={"name": "Type", "type": "Element", "required": True})
    username: str = field(
        metadata={"name": "Username", "type": "Element", "required": True}
    )
    srid: str = field(
        default=None, metadata={"name": "Srid", "type": "Element", "required": True}
    )
    sslmode: str = field(default=None)

dbname: str = field(metadata={'name': 'Dbname', 'type': 'Element', 'required': True}) class-attribute instance-attribute

geometry_column: str = field(metadata={'name': 'GeometryColumn', 'type': 'Element', 'required': True}) class-attribute instance-attribute

host: str = field(metadata={'name': 'Host', 'type': 'Element', 'required': True}) class-attribute instance-attribute

key: str = field(metadata={'name': 'Key', 'type': 'Element', 'required': True}) class-attribute instance-attribute

password: str = field(metadata={'name': 'Password', 'type': 'Element', 'required': True}) class-attribute instance-attribute

port: str = field(metadata={'name': 'Port', 'type': 'Element', 'required': True}) class-attribute instance-attribute

schema: str = field(metadata={'name': 'Schema', 'type': 'Element', 'required': True}) class-attribute instance-attribute

srid: str = field(default=None, metadata={'name': 'Srid', 'type': 'Element', 'required': True}) class-attribute instance-attribute

sslmode: str = field(default=None) class-attribute instance-attribute

table: str = field(metadata={'name': 'Table', 'type': 'Element', 'required': True}) class-attribute instance-attribute

type: str = field(metadata={'name': 'Type', 'type': 'Element', 'required': True}) class-attribute instance-attribute

username: str = field(metadata={'name': 'Username', 'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(dbname, geometry_column, host, key, password, port, schema, table, type, username, srid=None, sslmode=None)

Project dataclass

Source code in src/qgis_server_light/interface/qgis.py
489
490
491
492
493
494
@dataclass
class Project:
    version: str = field(
        metadata={"name": "Version", "type": "Element", "required": True}
    )
    name: str = field(metadata={"name": "Name", "type": "Element", "required": True})

name: str = field(metadata={'name': 'Name', 'type': 'Element', 'required': True}) class-attribute instance-attribute

version: str = field(metadata={'name': 'Version', 'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(version, name)

QueryCollection dataclass

Holds all feature collections which are bound to the passed queries. The order in the list has to be not changed, so that consuming applications can map the response to the passed queries.

Attributes:

Name Type Description
feature_collections List[FeatureCollection]

The feature collections belonging to the passed queries.

Source code in src/qgis_server_light/interface/qgis.py
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
@dataclass
class QueryCollection:
    """Holds all feature collections which are bound to the passed queries. The order in the list has to be
    not changed, so that consuming applications can map the response to the passed queries.

    Attributes:
        feature_collections: The feature collections belonging to the passed queries.
    """

    numbers_matched: Optional[str | int] = field(
        default="unknown",
        metadata={"name": "NumbersMatched", "type": "Element", "required": True},
    )
    feature_collections: List[FeatureCollection] = field(
        default_factory=list,
        metadata={"name": "FeatureCollections", "type": "Element", "required": True},
    )

feature_collections: List[FeatureCollection] = field(default_factory=list, metadata={'name': 'FeatureCollections', 'type': 'Element', 'required': True}) class-attribute instance-attribute

numbers_matched: Optional[str | int] = field(default='unknown', metadata={'name': 'NumbersMatched', 'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(numbers_matched='unknown', feature_collections=list())

Raster dataclass

Bases: DataSet

A real QGIS Raster dataset. That are usually all QgsRasterLayer (in opposition to QgsVectorTileLayer which is not a real QgsRasterLayer.

Source code in src/qgis_server_light/interface/qgis.py
370
371
372
373
374
375
@dataclass
class Raster(DataSet):
    """
    A real QGIS Raster dataset. That are usually all `QgsRasterLayer` (in opposition to `QgsVectorTileLayer`
    which is not a real `QgsRasterLayer`.
    """

__init__(name, title, id, bbox, bbox_wgs84, path, source, driver, crs, styles, minimum_scale=None, maximum_scale=None, filter=None, style_name='default')

Service dataclass

Source code in src/qgis_server_light/interface/qgis.py
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
@dataclass
class Service:
    contact_organization: Optional[str] = field(
        metadata={"name": "WMSContactOrganization", "type": "Element", "required": True}
    )
    contact_mail: Optional[str] = field(
        metadata={"name": "WMSContactMail", "type": "Element", "required": True}
    )
    contact_person: Optional[str] = field(
        default=None,
        metadata={"name": "WMSContactPerson", "type": "Element", "required": False},
    )
    contact_phone: Optional[str] = field(
        default=None,
        metadata={"name": "WMSContactPhone", "type": "Element", "required": False},
    )
    contact_position: Optional[str] = field(
        default=None,
        metadata={"name": "WMSContactPosition", "type": "Element", "required": False},
    )
    fees: Optional[str] = field(
        default=None, metadata={"name": "WMSFees", "type": "Element", "required": False}
    )
    keyword_list: Optional[str] = field(
        default=None,
        metadata={"name": "WMSKeywordList", "type": "Element", "required": False},
    )
    online_resource: Optional[str] = field(
        default=None,
        metadata={"name": "WMSOnlineResource", "type": "Element", "required": False},
    )
    service_abstract: Optional[str] = field(
        default=None,
        metadata={"name": "WMSServiceAbstract", "type": "Element", "required": False},
    )
    service_title: Optional[str] = field(
        default=None,
        metadata={"name": "WMSServiceTitle", "type": "Element", "required": False},
    )
    resource_url: Optional[str] = field(
        default=None, metadata={"name": "WMSUrl", "type": "Element", "required": False}
    )

contact_mail: Optional[str] = field(metadata={'name': 'WMSContactMail', 'type': 'Element', 'required': True}) class-attribute instance-attribute

contact_organization: Optional[str] = field(metadata={'name': 'WMSContactOrganization', 'type': 'Element', 'required': True}) class-attribute instance-attribute

contact_person: Optional[str] = field(default=None, metadata={'name': 'WMSContactPerson', 'type': 'Element', 'required': False}) class-attribute instance-attribute

contact_phone: Optional[str] = field(default=None, metadata={'name': 'WMSContactPhone', 'type': 'Element', 'required': False}) class-attribute instance-attribute

contact_position: Optional[str] = field(default=None, metadata={'name': 'WMSContactPosition', 'type': 'Element', 'required': False}) class-attribute instance-attribute

fees: Optional[str] = field(default=None, metadata={'name': 'WMSFees', 'type': 'Element', 'required': False}) class-attribute instance-attribute

keyword_list: Optional[str] = field(default=None, metadata={'name': 'WMSKeywordList', 'type': 'Element', 'required': False}) class-attribute instance-attribute

online_resource: Optional[str] = field(default=None, metadata={'name': 'WMSOnlineResource', 'type': 'Element', 'required': False}) class-attribute instance-attribute

resource_url: Optional[str] = field(default=None, metadata={'name': 'WMSUrl', 'type': 'Element', 'required': False}) class-attribute instance-attribute

service_abstract: Optional[str] = field(default=None, metadata={'name': 'WMSServiceAbstract', 'type': 'Element', 'required': False}) class-attribute instance-attribute

service_title: Optional[str] = field(default=None, metadata={'name': 'WMSServiceTitle', 'type': 'Element', 'required': False}) class-attribute instance-attribute

__init__(contact_organization, contact_mail, contact_person=None, contact_phone=None, contact_position=None, fees=None, keyword_list=None, online_resource=None, service_abstract=None, service_title=None, resource_url=None)

Source dataclass

Source code in src/qgis_server_light/interface/qgis.py
139
140
141
142
143
@dataclass
class Source:
    @staticmethod
    def decide_remote(path: str) -> bool:
        return path.startswith("http")

__init__()

decide_remote(path) staticmethod

Source code in src/qgis_server_light/interface/qgis.py
141
142
143
@staticmethod
def decide_remote(path: str) -> bool:
    return path.startswith("http")

Style dataclass

Source code in src/qgis_server_light/interface/qgis.py
301
302
303
304
@dataclass
class Style:
    name: str = field(metadata={"name": "Name", "type": "Element"})
    definition: str = field(metadata={"name": "Definition", "type": "Element"})

definition: str = field(metadata={'name': 'Definition', 'type': 'Element'}) class-attribute instance-attribute

name: str = field(metadata={'name': 'Name', 'type': 'Element'}) class-attribute instance-attribute

__init__(name, definition)

Tree dataclass

Source code in src/qgis_server_light/interface/qgis.py
497
498
499
500
501
502
503
504
505
506
507
@dataclass
class Tree:
    members: list[TreeGroup] = field(
        default_factory=list,
        metadata={"name": "Member", "type": "Element", "required": False},
    )

    def find_by_name(self, name: str) -> TreeGroup | None:
        for member in self.members:
            if member.name == name:
                return member

members: list[TreeGroup] = field(default_factory=list, metadata={'name': 'Member', 'type': 'Element', 'required': False}) class-attribute instance-attribute

__init__(members=list())

find_by_name(name)

Source code in src/qgis_server_light/interface/qgis.py
504
505
506
507
def find_by_name(self, name: str) -> TreeGroup | None:
    for member in self.members:
        if member.name == name:
            return member

TreeGroup dataclass

Bases: TreeLayer

Source code in src/qgis_server_light/interface/qgis.py
101
102
103
104
105
106
@dataclass
class TreeGroup(TreeLayer):
    children: List[str] = field(
        default_factory=list,
        metadata={"name": "Child", "type": "Element", "required": False},
    )

children: List[str] = field(default_factory=list, metadata={'name': 'Child', 'type': 'Element', 'required': False}) class-attribute instance-attribute

__init__(name, children=list())

TreeLayer dataclass

Bases: LayerLike

Source code in src/qgis_server_light/interface/qgis.py
96
97
98
@dataclass
class TreeLayer(LayerLike):
    pass

__init__(name)

Vector dataclass

Bases: DataSet

A real QGIS Vector dataset. That are usually all QgsVectorLayer (in opposition to QgsVectorTileLayer which is not a real QgsVectorLayer.

Source code in src/qgis_server_light/interface/qgis.py
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
@dataclass
class Vector(DataSet):
    """
    A real QGIS Vector dataset. That are usually all `QgsVectorLayer` (in opposition to `QgsVectorTileLayer`
    which is not a real `QgsVectorLayer`.
    """

    fields: Optional[List[Field]] = field(
        default_factory=list,
        metadata={"name": "Fields", "type": "Element", "required": True},
    )
    geometry_type_simple: Optional[str] = field(
        default=None,
        metadata={"name": "GeometryTypeSimple", "type": "Element"},
    )
    geometry_type_wkb: Optional[str] = field(
        default=None,
        metadata={"name": "GeometryTypeWkb", "type": "Element"},
    )

fields: Optional[List[Field]] = field(default_factory=list, metadata={'name': 'Fields', 'type': 'Element', 'required': True}) class-attribute instance-attribute

geometry_type_simple: Optional[str] = field(default=None, metadata={'name': 'GeometryTypeSimple', 'type': 'Element'}) class-attribute instance-attribute

geometry_type_wkb: Optional[str] = field(default=None, metadata={'name': 'GeometryTypeWkb', 'type': 'Element'}) class-attribute instance-attribute

__init__(name, title, id, bbox, bbox_wgs84, path, source, driver, crs, styles, minimum_scale=None, maximum_scale=None, filter=None, style_name='default', fields=list(), geometry_type_simple=None, geometry_type_wkb=None)

VectorTileSource dataclass

Bases: Source

Source code in src/qgis_server_light/interface/qgis.py
242
243
244
245
246
247
248
249
250
251
252
253
254
@dataclass
class VectorTileSource(Source):
    styleUrl: str = field(
        metadata={"name": "styleUrl", "type": "Element", "required": True}
    )
    type: str = field(metadata={"name": "Type", "type": "Element", "required": True})
    url: str = field(metadata={"name": "Url", "type": "Element", "required": True})
    zmax: str = field(metadata={"name": "Zmax", "type": "Element", "required": True})
    zmin: str = field(metadata={"name": "Zmin", "type": "Element", "required": True})

    @property
    def remote(self):
        return self.decide_remote(self.url)

remote property

styleUrl: str = field(metadata={'name': 'styleUrl', 'type': 'Element', 'required': True}) class-attribute instance-attribute

type: str = field(metadata={'name': 'Type', 'type': 'Element', 'required': True}) class-attribute instance-attribute

url: str = field(metadata={'name': 'Url', 'type': 'Element', 'required': True}) class-attribute instance-attribute

zmax: str = field(metadata={'name': 'Zmax', 'type': 'Element', 'required': True}) class-attribute instance-attribute

zmin: str = field(metadata={'name': 'Zmin', 'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(styleUrl, type, url, zmax, zmin)

WfsSource dataclass

Source code in src/qgis_server_light/interface/qgis.py
166
167
168
169
170
@dataclass
class WfsSource:
    # currently not implemented because qgis does not allow to
    # use the decode uri approach on that URI
    pass

__init__()

WmsSource dataclass

Bases: Source

Source code in src/qgis_server_light/interface/qgis.py
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
@dataclass
class WmsSource(Source):
    crs: str = field(metadata={"name": "Crs", "type": "Element", "required": True})
    format: str = field(
        metadata={"name": "Format", "type": "Element", "required": True}
    )
    layers: str = field(
        metadata={"name": "Layers", "type": "Element", "required": True}
    )
    url: str = field(metadata={"name": "Url", "type": "Element", "required": True})
    dpi_mode: str = field(
        default=None, metadata={"name": "DpiMode", "type": "Element", "required": True}
    )
    feature_count: int = field(
        default=None,
        metadata={"name": "FeatureCount", "type": "Element", "required": True},
    )
    contextual_wms_legend: str = field(
        default=None,
        metadata={"name": "ContextualWMSLegend", "type": "Element", "required": True},
    )

contextual_wms_legend: str = field(default=None, metadata={'name': 'ContextualWMSLegend', 'type': 'Element', 'required': True}) class-attribute instance-attribute

crs: str = field(metadata={'name': 'Crs', 'type': 'Element', 'required': True}) class-attribute instance-attribute

dpi_mode: str = field(default=None, metadata={'name': 'DpiMode', 'type': 'Element', 'required': True}) class-attribute instance-attribute

feature_count: int = field(default=None, metadata={'name': 'FeatureCount', 'type': 'Element', 'required': True}) class-attribute instance-attribute

format: str = field(metadata={'name': 'Format', 'type': 'Element', 'required': True}) class-attribute instance-attribute

layers: str = field(metadata={'name': 'Layers', 'type': 'Element', 'required': True}) class-attribute instance-attribute

url: str = field(metadata={'name': 'Url', 'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(crs, format, layers, url, dpi_mode=None, feature_count=None, contextual_wms_legend=None)

WmtsSource dataclass

Bases: WmsSource

Source code in src/qgis_server_light/interface/qgis.py
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
@dataclass(kw_only=True)
class WmtsSource(WmsSource):
    styles: str = field(
        metadata={"name": "Styles", "type": "Element", "required": True}
    )
    tile_dimensions: str = field(
        default=None,
        metadata={"name": "TileDimensions", "type": "Element", "required": True},
    )
    tile_matrix_set: str = field(
        metadata={"name": "TileMatrixSet", "type": "Element", "required": True}
    )
    tile_pixel_ratio: str = field(
        default=None,
        metadata={"name": "TilePixelRatio", "type": "Element", "required": True},
    )

styles: str = field(metadata={'name': 'Styles', 'type': 'Element', 'required': True}) class-attribute instance-attribute

tile_dimensions: str = field(default=None, metadata={'name': 'TileDimensions', 'type': 'Element', 'required': True}) class-attribute instance-attribute

tile_matrix_set: str = field(metadata={'name': 'TileMatrixSet', 'type': 'Element', 'required': True}) class-attribute instance-attribute

tile_pixel_ratio: str = field(default=None, metadata={'name': 'TilePixelRatio', 'type': 'Element', 'required': True}) class-attribute instance-attribute

__init__(crs, format, layers, url, dpi_mode=None, feature_count=None, contextual_wms_legend=None, *, styles, tile_dimensions=None, tile_matrix_set, tile_pixel_ratio=None)