1+ from decimal import Decimal
12from re import Pattern
23from typing import Any , Optional
34
@@ -34,7 +35,14 @@ class Lng(BaseModel):
3435 (Coordinate (latitude = 0 , longitude = 0 ), (0 , 0 ), None ),
3536 (ArgsKwargs (args = ()), (0 , 0 ), None ),
3637 (ArgsKwargs (args = (1 , 0.0 )), (1.0 , 0 ), None ),
37- # # Invalid coordinates
38+ # Decimal test cases
39+ ((Decimal ('20.0' ), Decimal ('10.0' )), (Decimal ('20.0' ), Decimal ('10.0' )), None ),
40+ ((Decimal ('-90.0' ), Decimal ('0.0' )), (Decimal ('-90.0' ), Decimal ('0.0' )), None ),
41+ ((Decimal ('45.678' ), Decimal ('-123.456' )), (Decimal ('45.678' ), Decimal ('-123.456' )), None ),
42+ (Coordinate (Decimal ('20.0' ), Decimal ('10.0' )), (Decimal ('20.0' ), Decimal ('10.0' )), None ),
43+ (Coordinate (latitude = Decimal ('0' ), longitude = Decimal ('0' )), (Decimal ('0' ), Decimal ('0' )), None ),
44+ (ArgsKwargs (args = (Decimal ('1' ), Decimal ('0.0' ))), (Decimal ('1.0' ), Decimal ('0.0' )), None ),
45+ # Invalid coordinates
3846 ((), None , 'Field required' ), # Empty tuple
3947 ((10.0 ,), None , 'Field required' ), # Tuple with only one value
4048 (('ten, ' ), None , 'string is not recognized as a valid coordinate' ),
@@ -49,10 +57,9 @@ class Lng(BaseModel):
4957 (2 , None , 'Input should be a dictionary or an instance of Coordinate' ), # Wrong type
5058 ],
5159)
52- def test_format_for_coordinate (coord : (Any , Any ), result : (float , float ), error : Optional [Pattern ]):
60+ def test_format_for_coordinate (coord : (Any , Any ), result : (float | Decimal , float | Decimal ), error : Optional [Pattern ]):
5361 if error is None :
5462 _coord : Coordinate = Coord (coord = coord ).coord
55- print ('vars(_coord)' , vars (_coord ))
5663 assert _coord .latitude == result [0 ]
5764 assert _coord .longitude == result [1 ]
5865 else :
@@ -69,6 +76,16 @@ def test_format_for_coordinate(coord: (Any, Any), result: (float, float), error:
6976 # Invalid coordinates
7077 ((- 91.0 , 0.0 ), 'Input should be greater than or equal to -90' ),
7178 ((50.0 , 181.0 ), 'Input should be less than or equal to 180' ),
79+ # Valid Decimal coordinates
80+ ((Decimal ('-90.0' ), Decimal ('0.0' )), None ),
81+ ((Decimal ('50.0' ), Decimal ('180.0' )), None ),
82+ ((Decimal ('-89.999999' ), Decimal ('179.999999' )), None ),
83+ ((Decimal ('0.0' ), Decimal ('0.0' )), None ),
84+ # Invalid Decimal coordinates
85+ ((Decimal ('-90.1' ), Decimal ('0.0' )), 'Input should be greater than or equal to -90' ),
86+ ((Decimal ('50.0' ), Decimal ('180.1' )), 'Input should be less than or equal to 180' ),
87+ ((Decimal ('90.1' ), Decimal ('0.0' )), 'Input should be less than or equal to 90' ),
88+ ((Decimal ('0.0' ), Decimal ('-180.1' )), 'Input should be greater than or equal to -180' ),
7289 ],
7390)
7491def test_limit_for_coordinate (coord : (Any , Any ), error : Optional [Pattern ]):
@@ -91,17 +108,21 @@ def test_limit_for_coordinate(coord: (Any, Any), error: Optional[Pattern]):
91108 ('90.0' , True ),
92109 (- 90.0 , True ),
93110 ('-90.0' , True ),
111+ (Decimal ('90.0' ), True ),
112+ (Decimal ('-90.0' ), True ),
94113 # Unvalid latitude
95114 (91.0 , False ),
96115 (- 91.0 , False ),
116+ (Decimal ('91.0' ), False ),
117+ (Decimal ('-91.0' ), False ),
97118 ],
98119)
99120def test_format_latitude (latitude : float , valid : bool ):
100121 if valid :
101122 _lat = Lat (lat = latitude ).lat
102123 assert _lat == float (latitude )
103124 else :
104- with pytest .raises (ValidationError , match = '1 validation error for Lat' ):
125+ with pytest .raises (ValidationError , match = '2 validation errors for Lat' ):
105126 Lat (lat = latitude )
106127
107128
@@ -119,46 +140,89 @@ def test_format_latitude(latitude: float, valid: bool):
119140 (- 91.0 , True ),
120141 (180.0 , True ),
121142 (- 180.0 , True ),
143+ (Decimal ('180.0' ), True ),
144+ (Decimal ('-180.0' ), True ),
122145 # Unvalid latitude
123146 (181.0 , False ),
124147 (- 181.0 , False ),
148+ (Decimal ('181.0' ), False ),
149+ (Decimal ('-181.0' ), False ),
125150 ],
126151)
127152def test_format_longitude (longitude : float , valid : bool ):
128153 if valid :
129154 _lng = Lng (lng = longitude ).lng
130155 assert _lng == float (longitude )
131156 else :
132- with pytest .raises (ValidationError , match = '1 validation error for Lng' ):
157+ with pytest .raises (ValidationError , match = '2 validation errors for Lng' ):
133158 Lng (lng = longitude )
134159
135160
136161def test_str_repr ():
162+ # Float tests
137163 assert str (Coord (coord = (20.0 , 10.0 )).coord ) == '20.0,10.0'
138164 assert str (Coord (coord = ('20.0, 10.0' )).coord ) == '20.0,10.0'
139165 assert repr (Coord (coord = (20.0 , 10.0 )).coord ) == 'Coordinate(latitude=20.0, longitude=10.0)'
166+ # Decimal tests
167+ assert str (Coord (coord = (Decimal ('20.0' ), Decimal ('10.0' ))).coord ) == '20.0,10.0'
168+ assert str (Coord (coord = (Decimal ('20.000' ), Decimal ('10.000' ))).coord ) == '20.000,10.000'
169+ assert (
170+ repr (Coord (coord = (Decimal ('20.0' ), Decimal ('10.0' ))).coord )
171+ == "Coordinate(latitude=Decimal('20.0'), longitude=Decimal('10.0'))"
172+ )
140173
141174
142175def test_eq ():
176+ # Float tests
143177 assert Coord (coord = (20.0 , 10.0 )).coord != Coord (coord = '20.0,11.0' ).coord
144178 assert Coord (coord = ('20.0, 10.0' )).coord != Coord (coord = '20.0,11.0' ).coord
145179 assert Coord (coord = ('20.0, 10.0' )).coord != Coord (coord = '20.0,11.0' ).coord
146180 assert Coord (coord = (20.0 , 10.0 )).coord == Coord (coord = '20.0,10.0' ).coord
147181
182+ # Decimal tests
183+ assert Coord (coord = (Decimal ('20.0' ), Decimal ('10.0' ))).coord == Coord (coord = '20.0,10.0' ).coord
184+ assert Coord (coord = (Decimal ('20.0' ), Decimal ('10.0' ))).coord == Coord (coord = (20.0 , 10.0 )).coord
185+ assert (
186+ Coord (coord = (Decimal ('20.0' ), Decimal ('10.0' ))).coord != Coord (coord = (Decimal ('20.0' ), Decimal ('11.0' ))).coord
187+ )
188+ assert (
189+ Coord (coord = (Decimal ('20.000' ), Decimal ('10.000' ))).coord
190+ == Coord (coord = (Decimal ('20.0' ), Decimal ('10.0' ))).coord
191+ )
192+
148193
149194def test_hashable ():
195+ # Float tests
150196 assert hash (Coord (coord = (20.0 , 10.0 )).coord ) == hash (Coord (coord = (20.0 , 10.0 )).coord )
151197 assert hash (Coord (coord = (20.0 , 11.0 )).coord ) != hash (Coord (coord = (20.0 , 10.0 )).coord )
152198
199+ # Decimal tests
200+ assert hash (Coord (coord = (Decimal ('20.0' ), Decimal ('10.0' ))).coord ) == hash (
201+ Coord (coord = (Decimal ('20.0' ), Decimal ('10.0' ))).coord
202+ )
203+ assert hash (Coord (coord = (Decimal ('20.0' ), Decimal ('10.0' ))).coord ) == hash (Coord (coord = (20.0 , 10.0 )).coord )
204+ assert hash (Coord (coord = (Decimal ('20.0' ), Decimal ('11.0' ))).coord ) != hash (
205+ Coord (coord = (Decimal ('20.0' ), Decimal ('10.0' ))).coord
206+ )
207+ assert hash (Coord (coord = (Decimal ('20.000' ), Decimal ('10.000' ))).coord ) == hash (
208+ Coord (coord = (Decimal ('20.0' ), Decimal ('10.0' ))).coord
209+ )
210+
153211
154212def test_json_schema ():
155213 class Model (BaseModel ):
156214 value : Coordinate
157215
158216 assert Model .model_json_schema (mode = 'validation' )['$defs' ]['Coordinate' ] == {
159217 'properties' : {
160- 'latitude' : {'maximum' : 90.0 , 'minimum' : - 90.0 , 'title' : 'Latitude' , 'type' : 'number' },
161- 'longitude' : {'maximum' : 180.0 , 'minimum' : - 180.0 , 'title' : 'Longitude' , 'type' : 'number' },
218+ 'latitude' : {
219+ 'anyOf' : [{'maximum' : 90.0 , 'minimum' : - 90.0 , 'type' : 'number' }, {'type' : 'string' }],
220+ 'title' : 'Latitude' ,
221+ },
222+ 'longitude' : {
223+ 'anyOf' : [{'maximum' : 180.0 , 'minimum' : - 180.0 , 'type' : 'number' }, {'type' : 'string' }],
224+ 'title' : 'Longitude' ,
225+ },
162226 },
163227 'required' : ['latitude' , 'longitude' ],
164228 'title' : 'Coordinate' ,
@@ -170,7 +234,10 @@ class Model(BaseModel):
170234 {
171235 'maxItems' : 2 ,
172236 'minItems' : 2 ,
173- 'prefixItems' : [{'type' : 'number' }, {'type' : 'number' }],
237+ 'prefixItems' : [
238+ {'anyOf' : [{'type' : 'number' }, {'type' : 'string' }]},
239+ {'anyOf' : [{'type' : 'number' }, {'type' : 'string' }]},
240+ ],
174241 'type' : 'array' ,
175242 },
176243 {'type' : 'string' },
@@ -181,8 +248,14 @@ class Model(BaseModel):
181248 '$defs' : {
182249 'Coordinate' : {
183250 'properties' : {
184- 'latitude' : {'maximum' : 90.0 , 'minimum' : - 90.0 , 'title' : 'Latitude' , 'type' : 'number' },
185- 'longitude' : {'maximum' : 180.0 , 'minimum' : - 180.0 , 'title' : 'Longitude' , 'type' : 'number' },
251+ 'latitude' : {
252+ 'anyOf' : [{'maximum' : 90.0 , 'minimum' : - 90.0 , 'type' : 'number' }, {'type' : 'string' }],
253+ 'title' : 'Latitude' ,
254+ },
255+ 'longitude' : {
256+ 'anyOf' : [{'maximum' : 180.0 , 'minimum' : - 180.0 , 'type' : 'number' }, {'type' : 'string' }],
257+ 'title' : 'Longitude' ,
258+ },
186259 },
187260 'required' : ['latitude' , 'longitude' ],
188261 'title' : 'Coordinate' ,
0 commit comments