Skip to content

Commit

Permalink
WMS get feature (edits from 697) (#698)
Browse files Browse the repository at this point in the history
* Added a basic WMS GetFeatureInfo capability

* Fixed typo in enum of output formats

* edits

* fix tests

---------

Co-authored-by: Ben Leighton <[email protected]>
Co-authored-by: Ben Leighton <[email protected]>
  • Loading branch information
3 people authored Sep 14, 2023
1 parent 255fd49 commit 448fc7a
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 67 deletions.
41 changes: 23 additions & 18 deletions src/titiler/application/tests/routes/test_cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import os
from io import BytesIO
from unittest.mock import patch
from urllib.parse import parse_qsl, urlencode, urlparse
from urllib.parse import parse_qsl, urlparse

import numpy
import pytest
Expand Down Expand Up @@ -187,36 +187,37 @@ def test_tile(rio, app):
assert response.status_code == 200
assert response.headers["content-type"] == "image/png"

cmap = urlencode(
{
# valid colormap
response = app.get(
"/cog/tiles/8/53/50.png",
params={
"url": "https://myurl.com/above_cog.tif",
"bidx": 1,
"colormap": json.dumps(
{
"1": [58, 102, 24, 255],
"2": [100, 177, 41],
"3": "#b1b129",
"4": "#ddcb9aFF",
}
)
}
)
response = app.get(
f"/cog/tiles/8/53/50.png?url=https://myurl.com/above_cog.tif&bidx=1&{cmap}"
),
},
)
assert response.status_code == 200
assert response.headers["content-type"] == "image/png"

cmap = urlencode({"colormap": json.dumps({"1": [58, 102]})})
response = app.get(
f"/cog/tiles/8/53/50.png?url=https://myurl.com/above_cog.tif&bidx=1&{cmap}"
)
assert response.status_code == 400

cmap = urlencode({"colormap": {"1": "#ddcb9aFF"}})
# invalid colormap shape
response = app.get(
f"/cog/tiles/8/53/50.png?url=https://myurl.com/above_cog.tif&bidx=1&{cmap}"
"/cog/tiles/8/53/50.png",
params={
"url": "https://myurl.com/above_cog.tif",
"bidx": 1,
"colormap": json.dumps({"1": [58, 102]}),
},
)
assert response.status_code == 400

# bad resampling
response = app.get(
"/cog/tiles/8/53/50.png?url=https://myurl.com/above_cog.tif&bidx=1&resampling=somethingwrong"
)
Expand Down Expand Up @@ -269,9 +270,13 @@ def test_tilejson(rio, app):
"3": "#b1b129",
"4": "#ddcb9aFF",
}
cmap = urlencode({"colormap": json.dumps(cmap_dict)})
response = app.get(
f"/cog/tilejson.json?url=https://myurl.com/above_cog.tif&bidx=1&{cmap}"
"/cog/tilejson.json",
params={
"url": "https://myurl.com/above_cog.tif",
"bidx": 1,
"colormap": json.dumps(cmap_dict),
},
)
assert response.status_code == 200
body = response.json()
Expand Down
4 changes: 2 additions & 2 deletions src/titiler/core/tests/test_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def main(cm=Depends(dependencies.ColorMapParams)):
assert response.json()["1"] == [68, 2, 85, 255]

cmap = json.dumps({1: [68, 1, 84, 255]})
response = client.get(f"/?colormap={cmap}")
response = client.get("/", params={"colormap": cmap})
assert response.json()["1"] == [68, 1, 84, 255]

cmap = json.dumps({0: "#000000", 255: "#ffffff"})
Expand All @@ -81,7 +81,7 @@ def main(cm=Depends(dependencies.ColorMapParams)):
([3, 1000], [255, 0, 0, 255]),
]
cmap = json.dumps(intervals)
response = client.get(f"/?colormap={cmap}")
response = client.get("/", params={"colormap": cmap})
assert response.json()[0] == [[1, 2], [0, 0, 0, 255]]
assert response.json()[1] == [[2, 3], [255, 255, 255, 255]]
assert response.json()[2] == [[3, 1000], [255, 0, 0, 255]]
Expand Down
38 changes: 21 additions & 17 deletions src/titiler/core/tests/test_factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,36 +124,40 @@ def test_TilerFactory():
assert response.headers["content-type"] == "image/png"

# Dict
cmap = urlencode(
{
response = client.get(
"/tiles/8/84/47.png",
params={
"url": f"{DATA_DIR}/cog.tif",
"bidx": 1,
"colormap": json.dumps(
{
"1": [58, 102, 24, 255],
"2": [100, 177, 41],
"3": "#b1b129",
"4": "#ddcb9aFF",
}
)
}
),
},
)
response = client.get(f"/tiles/8/84/47.png?url={DATA_DIR}/cog.tif&bidx=1&{cmap}")
assert response.status_code == 200
assert response.headers["content-type"] == "image/png"

# Intervals
cmap = urlencode(
{
response = client.get(
"/tiles/8/84/47.png",
params={
"url": f"{DATA_DIR}/cog.tif",
"bidx": 1,
"colormap": json.dumps(
[
# ([min, max], [r, g, b, a])
([1, 2], [0, 0, 0, 255]),
([2, 3], [255, 255, 255, 255]),
([3, 1000], [255, 0, 0, 255]),
]
)
}
),
},
)
response = client.get(f"/tiles/8/84/47.png?url={DATA_DIR}/cog.tif&bidx=1&{cmap}")
assert response.status_code == 200
assert response.headers["content-type"] == "image/png"

Expand Down Expand Up @@ -1522,21 +1526,21 @@ def test_AutoFormat_Colormap():
app.include_router(cog.router)

with TestClient(app) as client:

cmap = urlencode(
{
response = client.get(
"/preview",
params={
"url": f"{DATA_DIR}/cog.tif",
"bidx": 1,
"colormap": json.dumps(
[
# ([min, max], [r, g, b, a])
([0, 1], [255, 255, 255, 0]), # should be masked
([2, 6000], [255, 0, 0, 255]),
([6001, 300000], [0, 255, 0, 255]),
]
)
}
),
},
)

response = client.get(f"/preview?url={DATA_DIR}/cog.tif&bidx=1&{cmap}")
assert response.status_code == 200
assert response.headers["content-type"] == "image/png"
with MemoryFile(response.content) as mem:
Expand Down
50 changes: 50 additions & 0 deletions src/titiler/extensions/tests/test_wms.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,3 +386,53 @@ def test_wmsExtension_GetMap():
-52.301598718454485,
74.66298001264106,
]


def test_wmsExtension_GetFeatureInfo():
"""Test wmsValidateExtension class for GetFeatureInfo request."""
tiler_plus_wms = TilerFactory(extensions=[wmsExtension()])

app = FastAPI()
app.include_router(tiler_plus_wms.router)

with TestClient(app) as client:
# Setup the basic GetFeatureInfo request
params = {
"VERSION": "1.3.0",
"REQUEST": "GetFeatureInfo",
"LAYERS": cog,
"QUERY_LAYERS": cog,
"BBOX": "500975.102,8182890.453,501830.647,8183959.884",
"CRS": "EPSG:32621",
"WIDTH": 334,
"HEIGHT": 333,
"INFO_FORMAT": "text/html",
"I": "0",
"J": "0",
}

response = client.get("/wms", params=params)

assert response.status_code == 200
assert response.content == b"2800"

params = {
"VERSION": "1.3.0",
"REQUEST": "GetFeatureInfo",
"LAYERS": cog,
"QUERY_LAYERS": cog,
"BBOX": "500975.102,8182890.453,501830.647,8183959.884",
"CRS": "EPSG:32621",
"WIDTH": 334,
"HEIGHT": 333,
"INFO_FORMAT": "text/html",
"I": "333",
"J": "332",
}

response = client.get("/wms", params=params)

assert response.status_code == 200
assert response.content == b"3776"

# Add additional assertions to check the text response
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@
</HTTP>
</DCPType>
</Capabilities>
<FeatureInfo>
<Format><MIME /></Format>
<DCPType>
<HTTP>
<Get onlineResource="{{ request_url }}" />
<Post onlineResource="{{ request_url }}" />
</HTTP>
</DCPType>
</FeatureInfo>
</Request>
<Exception>
<Format><BLANK /><INIMAGE /><WMS_XML /></Format>
Expand Down
17 changes: 13 additions & 4 deletions src/titiler/extensions/titiler/extensions/templates/wms_1.1.1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,34 @@
</HTTP>
</DCPType>
</GetMap>
<GetFeatureInfo>
<Format>text/html</Format>
<DCPType>
<HTTP>
<Get><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="{{ request_url }}"/></Get>
<Post><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="{{ request_url }}"/></Post>
</HTTP>
</DCPType>
</GetFeatureInfo>
</Request>
<Exception>
<Format>application/vnd.ogc.se_xml</Format>
<Format>application/vnd.ogc.se_inimage</Format>
<Format>application/vnd.ogc.se_blank</Format>
</Exception>

<Layer>
<Name>TiTiler WMS</Name>
<Title>TiTiler WMS</Title>
<Abstract>COG URLs specified in the "LAYERS" parameter will show up as available layers</Abstract>

{% for srs in available_epsgs %}
<SRS>{{srs}}</SRS>
{% endfor %}

<LatLonBoundingBox minx="{{service_dict['xmin']}}" miny="{{service_dict['ymin']}}" maxx="{{service_dict['xmax']}}" maxy="{{service_dict['ymax']}}" />
<BoundingBox SRS="EPSG:4326" minx="{{service_dict['xmin']}}" miny="{{service_dict['ymin']}}" maxx="{{service_dict['xmax']}}" maxy="{{service_dict['ymax']}}" />

{% for layer in layers_dict.keys() %}
<Layer queryable="0" opaque="0" cascaded="0">
<Name>{{layer}}</Name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@
</HTTP>
</DCPType>
</GetMap>
<GetFeatureInfo>
<Format>text/html</Format>
<DCPType>
<HTTP>
<Get><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="{{ request_url }}"/></Get>
<Post><OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="{{ request_url }}"/></Post>
</HTTP>
</DCPType>
</GetFeatureInfo>
</Request>
<Exception>
<Format>XML</Format>
Expand Down Expand Up @@ -56,7 +65,7 @@
<BoundingBox CRS="EPSG:4326" minx="{{service_dict['xmin']}}" miny="{{service_dict['ymin']}}" maxx="{{service_dict['xmax']}}" maxy="{{service_dict['ymax']}}" />

{% for layer in layers_dict.keys() %}
<Layer queryable="0" opaque="0" cascaded="0">
<Layer queryable="1" opaque="0" cascaded="0">
<Name>{{layer}}</Name>
<Title>{{layer}}</Title>
<Abstract>{{layers_dict[layer]['abstract']}}</Abstract>
Expand Down
Loading

1 comment on commit 448fc7a

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark 'TiTiler performance Benchmarks'.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.30.

Benchmark suite Current: 448fc7a Previous: 255fd49 Ratio
WebMercator longest_transaction 0.12 s 0.08 s 1.50

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.