Skip to content

Commit 0e9db6e

Browse files
committed
Improving docstrings
1 parent 9324aed commit 0e9db6e

File tree

7 files changed

+146
-13
lines changed

7 files changed

+146
-13
lines changed

Diff for: pygml/axisorder.py

+24-8
Original file line numberDiff line numberDiff line change
@@ -196,16 +196,25 @@
196196
def get_crs_code(crs: str) -> Union[int, str]:
197197
""" Extract the CRS code from the given CRS identifier string,
198198
which can be one of:
199-
* EPSG:<EPSG code>
200-
* http://www.opengis.net/def/crs/EPSG/0/<EPSG code> (URI Style 1)
201-
* http://www.opengis.net/gml/srs/epsg.xml#<EPSG code> (URI Style 2)
202-
* urn:EPSG:geographicCRS:<epsg code>
203-
* urn:ogc:def:crs:EPSG::<EPSG code>
204-
* urn:ogc:def:crs:OGC::<EPSG code>
205-
* urn:ogc:def:crs:EPSG:<EPSG code>
199+
* ``EPSG:<EPSG code>``
200+
* ``http://www.opengis.net/def/crs/EPSG/0/<EPSG code>``
201+
* ``http://www.opengis.net/gml/srs/epsg.xml#<EPSG code>``
202+
* ``urn:EPSG:geographicCRS:<epsg code>``
203+
* ``urn:ogc:def:crs:EPSG::<EPSG code>``
204+
* ``urn:ogc:def:crs:OGC::<EPSG code>``
205+
* ``urn:ogc:def:crs:EPSG:<EPSG code>``
206206
207207
Returns the code as an integer in case of EPSG code or as the
208-
string 'CRS84'
208+
string ``'CRS84'``.
209+
210+
>>> get_crs_code('EPSG:4326')
211+
4326
212+
>>> get_crs_code('urn:ogc:def:crs:OGC::CRS84')
213+
'CRS84'
214+
>>> get_crs_code('something')
215+
Traceback (most recent call last):
216+
...
217+
ValueError: Failed to retrieve CRS code
209218
"""
210219
match = RE_CRS_CODE.match(crs)
211220
if not match:
@@ -222,6 +231,13 @@ def get_crs_code(crs: str) -> Union[int, str]:
222231
def is_crs_yx(crs: str) -> bool:
223232
""" Determines whether the given CRS uses Y/X (or latitude/longitude)
224233
axis order.
234+
235+
>>> is_crs_yx('EPSG:4326')
236+
True
237+
>>> is_crs_yx('EPSG:3857')
238+
False
239+
>>> is_crs_yx('urn:ogc:def:crs:OGC::CRS84')
240+
False
225241
"""
226242
code = get_crs_code(crs)
227243
return code in AXISORDER_YX

Diff for: pygml/basics.py

+41
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,19 @@ def parse_coordinates(value: str, cs: str = ',', ts: str = ' ',
5151
""" Parses the the values of a gml:coordinates node to a list of
5252
lists of floats. Takes the coordinate separator and tuple
5353
separator into account, and also custom decimal separators.
54+
55+
>>> parse_coordinates('12.34 56.7,89.10 11.12')
56+
[(12.34, 56.7), (89.1, 11.12)]
57+
>>> parse_coordinates('12.34 56.7;89.10 11.12', cs=';')
58+
[(12.34, 56.7), (89.1, 11.12)]
59+
>>> parse_coordinates('12.34:56.7,89.10:11.12', ts=':')
60+
[(12.34, 56.7), (89.1, 11.12)]
61+
>>> parse_coordinates('12.34:56.7;89.10:11.12', cs=';', ts=':')
62+
[(12.34, 56.7), (89.1, 11.12)]
63+
>>> parse_coordinates(
64+
... '12,34:56,7;89,10:11,12', cs=';', ts=':', decimal=','
65+
... )
66+
[(12.34, 56.7), (89.1, 11.12)]
5467
"""
5568

5669
number_parser = _make_number_parser(decimal)
@@ -67,6 +80,15 @@ def parse_coordinates(value: str, cs: str = ',', ts: str = ' ',
6780
def parse_poslist(value: str, dimensions: int = 2) -> Coordinates:
6881
""" Parses the value of a single gml:posList to a `Coordinates`
6982
structure.
83+
84+
>>> parse_poslist('12.34 56.7 89.10 11.12')
85+
[(12.34, 56.7), (89.1, 11.12)]
86+
>>> parse_poslist('12.34 56.7 89.10 11.12 13.14 15.16', dimensions=3)
87+
[(12.34, 56.7, 89.1), (11.12, 13.14, 15.16)]
88+
>>> parse_poslist('12.34 56.7 89.10 11.12', dimensions=3)
89+
Traceback (most recent call last):
90+
...
91+
ValueError: Invalid dimensionality of pos list
7092
"""
7193
raw = [float(v) for v in value.split()]
7294
if len(raw) % dimensions > 0:
@@ -80,18 +102,37 @@ def parse_poslist(value: str, dimensions: int = 2) -> Coordinates:
80102

81103
def parse_pos(value: str) -> Coordinate:
82104
""" Parses a single gml:pos to a `Coordinate` structure.
105+
106+
>>> parse_pos('12.34 56.7')
107+
(12.34, 56.7)
108+
>>> parse_pos('12.34 56.7 89.10')
109+
(12.34, 56.7, 89.1)
83110
"""
84111
return tuple(float(v) for v in value.split())
85112

86113

87114
def swap_coordinate_xy(coordinate: Coordinate) -> Coordinate:
88115
""" Swaps the X and Y coordinates of a given coordinate
116+
117+
>>> swap_coordinate_xy((12.34, 56.7))
118+
(56.7, 12.34)
119+
>>> swap_coordinate_xy((12.34, 56.7, 89.10))
120+
(56.7, 12.34, 89.1)
89121
"""
90122
return (coordinate[1], coordinate[0], *coordinate[2:])
91123

92124

93125
def swap_coordinates_xy(coordinates: Coordinates) -> Coordinates:
94126
""" Swaps the X and Y coordinates of a given coordinates list
127+
128+
>>> swap_coordinates_xy(
129+
... [(12.34, 56.7), (89.10, 11.12)]
130+
... )
131+
[(56.7, 12.34), (11.12, 89.1)]
132+
>>> swap_coordinates_xy(
133+
... [(12.34, 56.7, 89.10), (11.12, 13.14, 15.16)]
134+
... )
135+
[(56.7, 12.34, 89.1), (13.14, 11.12, 15.16)]
95136
"""
96137
return [
97138
(coordinate[1], coordinate[0], *coordinate[2:])

Diff for: pygml/dimensionality.py

+38
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,44 @@ def get_dimensionality(geometry: GeomDict) -> Optional[int]:
3737
and using its length.
3838
When no coordinates can be retrieved (e.g: in case of
3939
GeometryCollections) None is returned.
40+
41+
>>> get_dimensionality({
42+
... 'type': 'Polygon',
43+
... 'coordinates': [
44+
... [
45+
... (0.5, 1.0),
46+
... (0.5, 2.0),
47+
... (1.5, 2.0),
48+
... (1.5, 1.0),
49+
... (0.5, 1.0)
50+
... ]
51+
... ]
52+
... })
53+
2
54+
>>> get_dimensionality({
55+
... 'type': 'MultiPoint',
56+
... 'coordinates': [
57+
... (1.0, 1.0, 1.0),
58+
... (2.0, 2.0, 1.0),
59+
... ]
60+
... })
61+
3
62+
>>> get_dimensionality({
63+
... 'type': 'GeometryCollection',
64+
... 'geometries': [
65+
... {
66+
... 'type': 'Point',
67+
... 'coordinates': (1.0, 1.0)
68+
... },
69+
... {
70+
... 'type': 'Polygon',
71+
... 'coordinates': [
72+
... [(1.0, 1.0)],
73+
... [(1.0, 1.0)],
74+
... ]
75+
... },
76+
... ]
77+
... })
4078
"""
4179

4280
coordinates = geometry.get('coordinates')

Diff for: pygml/types.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ class GeomDict(TypedDict, total=True):
4141
GeomDict = dict
4242

4343
# Definition of a coordinate list
44-
Coordinate = List[float]
44+
Coordinate = Tuple[float, ...]
4545
Coordinates = List[Coordinate]
4646

4747

4848
@dataclass(frozen=True)
4949
class Geometry:
5050
""" Simple container class to hold a geometry and expose it via the
51-
`__geo_interface__`
51+
``__geo_interface__`` property
5252
"""
5353
geometry: GeomDict
5454

Diff for: pygml/v32.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ def parse_v32(element: Element) -> GeomDict:
9696
field, a 'coordinates' field and potentially a 'crs' field
9797
when the geometries SRS could be determined. This field
9898
follows the structure laid out in the
99-
[draft for GeoJSON](https://gist.github.com/sgillies/1233327).
99+
`draft for GeoJSON <https://gist.github.com/sgillies/1233327>`_.
100100
"""
101101
qname = etree.QName(element.tag)
102102
if qname.namespace != NAMESPACE:
@@ -389,6 +389,18 @@ def encode_v32(geometry: GeomDict, identifier: str) -> Element:
389389
390390
This function returns an ``lxml.etree._Element`` which can be
391391
altered or serialized.
392+
393+
>>> from pygml.v32 import encode_v32
394+
>>> from lxml import etree
395+
>>> tree = encode_v32({
396+
... 'type': 'Point',
397+
... 'coordinates': (1.0, 1.0)
398+
... }, 'ID')
399+
>>> print(etree.tostring(tree, pretty_print=True).decode())
400+
<gml:Point xmlns:gml="http://www.opengis.net/gml/3.2"
401+
srsName="urn:ogc:def:crs:OGC::CRS84" gml:id="ID">
402+
<gml:pos>1.0 1.0</gml:pos>
403+
</gml:Point>
392404
"""
393405
crs = geometry.get('crs')
394406
srs = None

Diff for: tests/test_axisorder.py

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
import pytest
22

3-
from pygml.axisorder import is_crs_yx
3+
from pygml.axisorder import is_crs_yx, get_crs_code
4+
5+
6+
def test_get_crs_code():
7+
# test with a reversed code
8+
assert get_crs_code('EPSG:4326') == 4326
9+
assert get_crs_code('http://www.opengis.net/def/crs/EPSG/0/4326') == 4326
10+
assert get_crs_code('http://www.opengis.net/gml/srs/epsg.xml#4326') == 4326
11+
assert get_crs_code('urn:EPSG:geographicCRS:4326') == 4326
12+
assert get_crs_code('urn:ogc:def:crs:EPSG::4326') == 4326
13+
assert get_crs_code('urn:ogc:def:crs:EPSG:4326') == 4326
14+
assert get_crs_code('urn:ogc:def:crs:OGC::CRS84') == 'CRS84'
15+
16+
# test with some garbage format
17+
with pytest.raises(ValueError):
18+
get_crs_code('abcd:4326')
419

520

621
def test_is_crs_yx():

Diff for: tests/test_basics.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import pytest
22

33
from pygml.basics import (
4-
parse_coordinates, parse_poslist, parse_pos, swap_coordinates_xy
4+
parse_coordinates, parse_poslist, parse_pos, swap_coordinate_xy,
5+
swap_coordinates_xy
56
)
67

78

@@ -57,6 +58,16 @@ def test_parse_pos():
5758
assert result == (12.34, 56.7, 89.10)
5859

5960

61+
def test_swap_coordinate_xy():
62+
# basic test
63+
swapped = swap_coordinate_xy((12.34, 56.7))
64+
assert swapped == (56.7, 12.34)
65+
66+
# 3D coords, only X/Y are to be swapped
67+
swapped = swap_coordinate_xy((12.34, 56.7, 89.10))
68+
assert swapped == (56.7, 12.34, 89.10)
69+
70+
6071
def test_swap_coordinates_xy():
6172
# basic test
6273
swapped = swap_coordinates_xy(

0 commit comments

Comments
 (0)