ecoscape-utilities 0.0.36__py3-none-any.whl → 0.0.38__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ecoscape-utilities might be problematic. Click here for more details.
- ecoscape_utilities/ebird_db.py +64 -104
- {ecoscape_utilities-0.0.36.dist-info → ecoscape_utilities-0.0.38.dist-info}/METADATA +1 -1
- ecoscape_utilities-0.0.38.dist-info/RECORD +8 -0
- ecoscape_utilities-0.0.36.dist-info/RECORD +0 -8
- {ecoscape_utilities-0.0.36.dist-info → ecoscape_utilities-0.0.38.dist-info}/WHEEL +0 -0
- {ecoscape_utilities-0.0.36.dist-info → ecoscape_utilities-0.0.38.dist-info}/licenses/LICENSE.md +0 -0
- {ecoscape_utilities-0.0.36.dist-info → ecoscape_utilities-0.0.38.dist-info}/top_level.txt +0 -0
ecoscape_utilities/ebird_db.py
CHANGED
|
@@ -11,6 +11,34 @@ from pyproj.crs import CRS
|
|
|
11
11
|
|
|
12
12
|
from scgt import GeoTiff
|
|
13
13
|
|
|
14
|
+
def expand_sqlite_query(query, params):
|
|
15
|
+
"""
|
|
16
|
+
Expands an SQLite query string with named parameters from a dictionary.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
query (str): The SQL query string with :variable placeholders.
|
|
20
|
+
params (dict): A dictionary mapping variable names to their values.
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
str: The expanded SQL query string.
|
|
24
|
+
"""
|
|
25
|
+
expanded_query = query
|
|
26
|
+
for key, value in params.items():
|
|
27
|
+
placeholder = f":{key}"
|
|
28
|
+
if isinstance(value, str):
|
|
29
|
+
# Escape any single quotes within the string
|
|
30
|
+
formatted_value = f"'{value.replace("'", "''")}'"
|
|
31
|
+
elif value is None:
|
|
32
|
+
formatted_value = 'NULL'
|
|
33
|
+
else:
|
|
34
|
+
# For integers, floats, and other types
|
|
35
|
+
formatted_value = str(value)
|
|
36
|
+
|
|
37
|
+
expanded_query = expanded_query.replace(placeholder, formatted_value)
|
|
38
|
+
|
|
39
|
+
return expanded_query
|
|
40
|
+
|
|
41
|
+
|
|
14
42
|
"""
|
|
15
43
|
A module for interaction with a sqlite database. Contains functions for query execution,
|
|
16
44
|
and some common functionality we need to run on the DB
|
|
@@ -72,14 +100,14 @@ class EbirdObservations(Connection):
|
|
|
72
100
|
super().__init__(db_file)
|
|
73
101
|
|
|
74
102
|
def get_all_squares(self, state=None,
|
|
75
|
-
breeding=
|
|
103
|
+
breeding=None, date_range=None,
|
|
76
104
|
lat_range=None, lng_range=None, max_dist=2, min_time=None,
|
|
77
105
|
verbose=False):
|
|
78
106
|
"""
|
|
79
107
|
Gets all squares with bird (any bird) observations, for a certain state,
|
|
80
108
|
and withing certain lat, lng, and date ranges.
|
|
81
109
|
:param state (str): state code
|
|
82
|
-
:param breeding
|
|
110
|
+
:param breeding: None, or pair of months delimiting the breeding season, e.g. ("04", "06").
|
|
83
111
|
:param date_range: tuple of 2 date-strings in format "YYYY-MM-DD" to get only observations in this date range
|
|
84
112
|
:param lat_range: tuple of 2 floats for the lower and upper bounds for latitude
|
|
85
113
|
:param lng_range: tuple of 2 floats for the lower and upper bounds for longitude
|
|
@@ -99,12 +127,12 @@ class EbirdObservations(Connection):
|
|
|
99
127
|
query_string.append('and "STATE CODE" = :state')
|
|
100
128
|
d['state'] = state
|
|
101
129
|
# Adds breeding portion
|
|
102
|
-
if breeding:
|
|
130
|
+
if breeding is not None:
|
|
103
131
|
query_string.extend([
|
|
104
|
-
'and
|
|
105
|
-
'
|
|
106
|
-
'OR substr("OBSERVATION DATE", 6, 2) = "06")'
|
|
132
|
+
'and substr("OBSERVATION DATE", 6, 2) >= ":br1"',
|
|
133
|
+
'and substr("OBSERVATION DATE", 6, 2) <= ":br2"',
|
|
107
134
|
])
|
|
135
|
+
d['br1'], d['br2'] = breeding
|
|
108
136
|
if date_range is not None:
|
|
109
137
|
query_string.append('and "OBSERVATION DATE" >= :min_date')
|
|
110
138
|
query_string.append('and "OBSERVATION DATE" <= :max_date')
|
|
@@ -120,11 +148,12 @@ class EbirdObservations(Connection):
|
|
|
120
148
|
query_string = " ".join(query_string)
|
|
121
149
|
if verbose:
|
|
122
150
|
print("Query:", query_string)
|
|
151
|
+
print("Expanded query:", expand_sqlite_query(query_string, d))
|
|
123
152
|
squares_list = self.execute_query((query_string, d))
|
|
124
153
|
return [sq[0] for sq in squares_list]
|
|
125
154
|
|
|
126
155
|
def get_square_observations(self, square, bird,
|
|
127
|
-
breeding=
|
|
156
|
+
breeding=None, date_range=None,
|
|
128
157
|
lat_range=None, lng_range=None, max_dist=2, min_time=None,
|
|
129
158
|
verbose=False):
|
|
130
159
|
"""
|
|
@@ -132,7 +161,7 @@ class EbirdObservations(Connection):
|
|
|
132
161
|
total time, total distance, and total bird sightings, for a square.
|
|
133
162
|
:param square: tuple of 2 floats, representing (lat, lng) of the square
|
|
134
163
|
:param bird: bird
|
|
135
|
-
:param breeding
|
|
164
|
+
:param breeding: pair of months delimiting breeding season, or None (e.g., ("04", "06")).
|
|
136
165
|
:param date_range: tuple of 2 date-strings in format "YYYY-MM-DD" to get only observations in this date range
|
|
137
166
|
:param lat_range: tuple of 2 floats for the lower and upper bounds for latitude
|
|
138
167
|
:param lng_range: tuple of 2 floats for the lower and upper bounds for longitude
|
|
@@ -153,12 +182,12 @@ class EbirdObservations(Connection):
|
|
|
153
182
|
query_string.append('and "DURATION MINUTES" >= :min_time')
|
|
154
183
|
d["min_time"] = min_time
|
|
155
184
|
# Adds breeding portion
|
|
156
|
-
if breeding:
|
|
185
|
+
if breeding is not None:
|
|
157
186
|
query_string.extend([
|
|
158
|
-
'and
|
|
159
|
-
'
|
|
160
|
-
'OR substr("OBSERVATION DATE", 6, 2) = "06")'
|
|
187
|
+
'and substr("OBSERVATION DATE", 6, 2) >= ":br1"',
|
|
188
|
+
'and substr("OBSERVATION DATE", 6, 2) <= ":br2"',
|
|
161
189
|
])
|
|
190
|
+
d['br1'], d['br2'] = breeding
|
|
162
191
|
if date_range is not None:
|
|
163
192
|
query_string.append('and "OBSERVATION DATE" >= :min_date')
|
|
164
193
|
query_string.append('and "OBSERVATION DATE" <= :max_date')
|
|
@@ -195,12 +224,12 @@ class EbirdObservations(Connection):
|
|
|
195
224
|
query_string.append('and checklist."EFFORT DISTANCE KM" <= :dist')
|
|
196
225
|
d["dist"] = max_dist
|
|
197
226
|
# Adds breeding portion
|
|
198
|
-
if breeding:
|
|
227
|
+
if breeding is not None:
|
|
199
228
|
query_string.extend([
|
|
200
|
-
'and
|
|
201
|
-
'
|
|
202
|
-
'OR substr(checklist."OBSERVATION DATE", 6, 2) = "06")'
|
|
229
|
+
'and substr("OBSERVATION DATE", 6, 2) >= ":br1"',
|
|
230
|
+
'and substr("OBSERVATION DATE", 6, 2) <= ":br2"',
|
|
203
231
|
])
|
|
232
|
+
d['br1'], d['br2'] = breeding
|
|
204
233
|
if date_range is not None:
|
|
205
234
|
query_string.append('and checklist."OBSERVATION DATE" >= :min_date')
|
|
206
235
|
query_string.append('and checklist."OBSERVATION DATE" <= :max_date')
|
|
@@ -220,6 +249,7 @@ class EbirdObservations(Connection):
|
|
|
220
249
|
query_string = " ".join(query_string)
|
|
221
250
|
if verbose:
|
|
222
251
|
print("Query:", query_string)
|
|
252
|
+
print("Expanded query:", expand_sqlite_query(query_string, d))
|
|
223
253
|
r = self.execute_query((query_string, d))
|
|
224
254
|
if r is None:
|
|
225
255
|
num_birds = 0
|
|
@@ -237,7 +267,7 @@ class EbirdObservations(Connection):
|
|
|
237
267
|
)
|
|
238
268
|
|
|
239
269
|
def get_square_individual_checklists(self, square, bird,
|
|
240
|
-
breeding=
|
|
270
|
+
breeding=None, date_range=None,
|
|
241
271
|
lat_range=None, lng_range=None, max_dist=2,
|
|
242
272
|
verbose=False):
|
|
243
273
|
"""
|
|
@@ -247,7 +277,7 @@ class EbirdObservations(Connection):
|
|
|
247
277
|
and total bird sightings, for a square.
|
|
248
278
|
:param square: tuple of 2 floats, representing (lat, lng) of the square
|
|
249
279
|
:param bird (str): name of bird
|
|
250
|
-
:param breeding
|
|
280
|
+
:param breeding: None, or pair of months delimiting breeding season ("04", "06").
|
|
251
281
|
:param date_range: tuple of 2 date-strings in format "YYYY-MM-DD" to get only observations in this date range
|
|
252
282
|
:param lat_range: tuple of 2 floats for the lower and upper bounds for latitude
|
|
253
283
|
:param lng_range: tuple of 2 floats for the lower and upper bounds for longitude
|
|
@@ -264,12 +294,12 @@ class EbirdObservations(Connection):
|
|
|
264
294
|
query_string.append('and "EFFORT DISTANCE KM" <= :dist')
|
|
265
295
|
d["dist"] = max_dist
|
|
266
296
|
# Adds breeding portion
|
|
267
|
-
if breeding:
|
|
297
|
+
if breeding is not None:
|
|
268
298
|
query_string.extend([
|
|
269
|
-
'and
|
|
270
|
-
'
|
|
271
|
-
'OR substr("OBSERVATION DATE", 6, 2) = "06")'
|
|
299
|
+
'and substr("OBSERVATION DATE", 6, 2) >= ":br1"',
|
|
300
|
+
'and substr("OBSERVATION DATE", 6, 2) <= ":br2"',
|
|
272
301
|
])
|
|
302
|
+
d['br1'], d['br2'] = breeding
|
|
273
303
|
if date_range is not None:
|
|
274
304
|
query_string.append('and "OBSERVATION DATE" >= :min_date')
|
|
275
305
|
query_string.append('and "OBSERVATION DATE" <= :max_date')
|
|
@@ -299,12 +329,12 @@ class EbirdObservations(Connection):
|
|
|
299
329
|
query_string.append('and checklist."EFFORT DISTANCE KM" <= :dist')
|
|
300
330
|
d["dist"] = max_dist
|
|
301
331
|
# Adds breeding portion
|
|
302
|
-
if breeding:
|
|
332
|
+
if breeding is not None:
|
|
303
333
|
query_string.extend([
|
|
304
|
-
'and
|
|
305
|
-
'
|
|
306
|
-
'OR substr(checklist."OBSERVATION DATE", 6, 2) = "06")'
|
|
334
|
+
'and substr("OBSERVATION DATE", 6, 2) >= ":br1"',
|
|
335
|
+
'and substr("OBSERVATION DATE", 6, 2) <= ":br2"',
|
|
307
336
|
])
|
|
337
|
+
d['br1'], d['br2'] = breeding
|
|
308
338
|
if date_range is not None:
|
|
309
339
|
query_string.append('and checklist."OBSERVATION DATE" >= :min_date')
|
|
310
340
|
query_string.append('and checklist."OBSERVATION DATE" <= :max_date')
|
|
@@ -324,6 +354,7 @@ class EbirdObservations(Connection):
|
|
|
324
354
|
query_string = " ".join(query_string)
|
|
325
355
|
if verbose:
|
|
326
356
|
print("Query:", query_string)
|
|
357
|
+
print("Expanded query:", expand_sqlite_query(query_string, d))
|
|
327
358
|
rows = self.execute_query((query_string, d))
|
|
328
359
|
counts = defaultdict(int)
|
|
329
360
|
for r in rows:
|
|
@@ -331,14 +362,14 @@ class EbirdObservations(Connection):
|
|
|
331
362
|
checklists_df["Count"] = checklists_df.apply(lambda row : counts[row["SAMPLING EVENT IDENTIFIER"]], axis=1)
|
|
332
363
|
return checklists_df
|
|
333
364
|
|
|
334
|
-
def get_squares_with_bird(self, bird, max_dist=1, breeding=
|
|
365
|
+
def get_squares_with_bird(self, bird, max_dist=1, breeding=None,
|
|
335
366
|
date_range=None, lat_range=None, lng_range=None,
|
|
336
367
|
state=None, verbose=False):
|
|
337
368
|
"""Gets all the squares where a bird has been sighted. This is used
|
|
338
369
|
primarily to refine the terrain resistance.
|
|
339
370
|
:param bird: Common name of the bird
|
|
340
371
|
:param max_dist: max length of the checklist in Km
|
|
341
|
-
:param breeding:
|
|
372
|
+
:param breeding: pair of months delimiting breeding season, or None.
|
|
342
373
|
:param date_range: date range in years, as a string tuple of yyyy-mm-dd dates
|
|
343
374
|
:param lat_range: range of latitudes to consider, as number tuple, optional.
|
|
344
375
|
:param lng_range: range of longitudes to consider, as number tuple, optional.
|
|
@@ -358,12 +389,12 @@ class EbirdObservations(Connection):
|
|
|
358
389
|
query_string.append('and checklist."PROTOCOL TYPE" != "Incidental"')
|
|
359
390
|
query_string.append('and checklist."EFFORT DISTANCE KM" <= :dist')
|
|
360
391
|
# Adds breeding portion
|
|
361
|
-
if breeding:
|
|
392
|
+
if breeding is not None:
|
|
362
393
|
query_string.extend([
|
|
363
|
-
'and
|
|
364
|
-
'
|
|
365
|
-
'OR substr(checklist."OBSERVATION DATE", 6, 2) = "06")'
|
|
394
|
+
'and substr("OBSERVATION DATE", 6, 2) >= ":br1"',
|
|
395
|
+
'and substr("OBSERVATION DATE", 6, 2) <= ":br2"',
|
|
366
396
|
])
|
|
397
|
+
d['br1'], d['br2'] = breeding
|
|
367
398
|
if date_range is not None:
|
|
368
399
|
query_string.append('and checklist."OBSERVATION DATE" >= :min_date')
|
|
369
400
|
query_string.append('and checklist."OBSERVATION DATE" <= :max_date')
|
|
@@ -380,82 +411,11 @@ class EbirdObservations(Connection):
|
|
|
380
411
|
query_string = " ".join(query_string)
|
|
381
412
|
if verbose:
|
|
382
413
|
print("Query:", query_string)
|
|
414
|
+
print("Expanded query:", expand_sqlite_query(query_string, d))
|
|
383
415
|
r = self.execute_query((query_string, d))
|
|
384
416
|
return [row[0] for row in r]
|
|
385
417
|
|
|
386
418
|
|
|
387
|
-
def get_observation_ratios(self, bird, min_checklists, bigsquare=False,
|
|
388
|
-
max_dist=1, verbose=False,
|
|
389
|
-
state=None, breeding=True):
|
|
390
|
-
"""This function is not used now. It was the old, deprecated way of
|
|
391
|
-
doing validation, and we are keeping the code for reference only."""
|
|
392
|
-
# First, I create a dictionary of squares to checklist counts.
|
|
393
|
-
query_string = [
|
|
394
|
-
'select "SAMPLING EVENT IDENTIFIER",',
|
|
395
|
-
'BIGSQUARE' if bigsquare else 'SQUARE',
|
|
396
|
-
'from checklist where',
|
|
397
|
-
'"ALL SPECIES REPORTED" = 1',
|
|
398
|
-
]
|
|
399
|
-
d = {'dist': max_dist}
|
|
400
|
-
query_string.append('and "PROTOCOL TYPE" != "Incidental"')
|
|
401
|
-
query_string.append('and "EFFORT DISTANCE KM" <= :dist')
|
|
402
|
-
if state is not None:
|
|
403
|
-
query_string.append('and "STATE CODE" = :state')
|
|
404
|
-
d['state'] = state
|
|
405
|
-
# Adds breeding portion
|
|
406
|
-
if breeding:
|
|
407
|
-
query_string.extend([
|
|
408
|
-
'and (substr("OBSERVATION DATE", 6, 2) = "04"',
|
|
409
|
-
'OR substr("OBSERVATION DATE", 6, 2) = "05"',
|
|
410
|
-
'OR substr("OBSERVATION DATE", 6, 2) = "06")'
|
|
411
|
-
])
|
|
412
|
-
query_string = " ".join(query_string)
|
|
413
|
-
if verbose:
|
|
414
|
-
print("Query:", query_string)
|
|
415
|
-
observations = self.execute_query((query_string, d))
|
|
416
|
-
checklists_per_square = defaultdict(int)
|
|
417
|
-
for _, sq in observations:
|
|
418
|
-
checklists_per_square[sq] += 1
|
|
419
|
-
# Now I keep only the squares with a minimum of checklists.
|
|
420
|
-
checklists_per_square = {sq: c for sq, c in checklists_per_square.items() if c >= min_checklists}
|
|
421
|
-
# Ok, I care only about these squares.
|
|
422
|
-
# Now I want to know, for each of these squares, how many checklists there are that
|
|
423
|
-
# contain the bird.
|
|
424
|
-
query_string = [
|
|
425
|
-
'select DISTINCT checklist."SAMPLING EVENT IDENTIFIER",',
|
|
426
|
-
'checklist.BIGSQUARE' if bigsquare else 'checklist.SQUARE',
|
|
427
|
-
'from checklist join observation on',
|
|
428
|
-
'checklist."SAMPLING EVENT IDENTIFIER" = observation."SAMPLING EVENT IDENTIFIER"',
|
|
429
|
-
'where observation."COMMON NAME" = :bird',
|
|
430
|
-
'and checklist."ALL SPECIES REPORTED" = 1',
|
|
431
|
-
]
|
|
432
|
-
d = {'dist': max_dist ,'bird': bird}
|
|
433
|
-
query_string.append('and checklist."PROTOCOL TYPE" != "Incidental"')
|
|
434
|
-
query_string.append('and checklist."EFFORT DISTANCE KM" <= :dist')
|
|
435
|
-
if state is not None:
|
|
436
|
-
query_string.append('and checklist."STATE CODE" = :state')
|
|
437
|
-
d['state'] = state
|
|
438
|
-
if breeding:
|
|
439
|
-
query_string.extend([
|
|
440
|
-
'and (substr(checklist."OBSERVATION DATE", 6, 2) = "04"',
|
|
441
|
-
'OR substr(checklist."OBSERVATION DATE", 6, 2) = "05"',
|
|
442
|
-
'OR substr(checklist."OBSERVATION DATE", 6, 2) = "06")',
|
|
443
|
-
])
|
|
444
|
-
query_string = " ".join(query_string)
|
|
445
|
-
if verbose:
|
|
446
|
-
print("Query:", query_string)
|
|
447
|
-
observations = self.execute_query((query_string, d))
|
|
448
|
-
good_checklists_per_square = defaultdict(int)
|
|
449
|
-
for _, sq in observations:
|
|
450
|
-
if sq in checklists_per_square: # Otherwise, too few observations.
|
|
451
|
-
good_checklists_per_square[sq] += 1
|
|
452
|
-
for sq in checklists_per_square:
|
|
453
|
-
if good_checklists_per_square[sq] > checklists_per_square[sq]:
|
|
454
|
-
print("Too many checklists at", sq, good_checklists_per_square[sq], checklists_per_square[sq])
|
|
455
|
-
return {sq: (good_checklists_per_square[sq] / checklists_per_square[sq])
|
|
456
|
-
for sq in checklists_per_square}
|
|
457
|
-
|
|
458
|
-
|
|
459
419
|
def format_coords(coords, bigsquare=False):
|
|
460
420
|
"""
|
|
461
421
|
formats coords from the eBird database format '4406;-12131' to
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ecoscape-utilities
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.38
|
|
4
4
|
Summary: A collection of EcoScape utilities.
|
|
5
5
|
Author-email: Luca de Alfaro <luca@ucsc.edu>, Coen Adler <ctadler@ucsc.edu>, Artie Nazarov <anazarov@ucsc.edu>, Natalia Ocampo-Peñuela <nocampop@ucsc.edu>, Jasmine Tai <cjtai@ucsc.edu>, Natalie Valett <nvalett@ucsc.edu>
|
|
6
6
|
Project-URL: Homepage, https://github.com/ecoscape-earth/ecoscape-utilities
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
ecoscape_utilities/__init__.py,sha256=LXt1rL9JVsjnCmsNZwZ2aoElphIK-koaEDdW6ffZsMQ,50
|
|
2
|
+
ecoscape_utilities/bird_runs.py,sha256=v43PfH_4ojpkTE-EFOJxr0oOW3M9suNm_1zMjZ9P-eI,5409
|
|
3
|
+
ecoscape_utilities/ebird_db.py,sha256=vMezw5AFIrd4RVITWbLpsZlDGBxig5CoVQMzT7XDeNk,28067
|
|
4
|
+
ecoscape_utilities-0.0.38.dist-info/licenses/LICENSE.md,sha256=3vh2mpA_XIR3FJot6a5F9DqktAoq45sEGIRkYjvAEeU,1304
|
|
5
|
+
ecoscape_utilities-0.0.38.dist-info/METADATA,sha256=E9tCnd-2Ipwy9tzDGz30uICoVmJ2mzuxrGUcuuZFGSs,1382
|
|
6
|
+
ecoscape_utilities-0.0.38.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
+
ecoscape_utilities-0.0.38.dist-info/top_level.txt,sha256=jLf7iMlySaJg0Vh8z4lbAaqOc5W5ruMgKFvp797CryQ,19
|
|
8
|
+
ecoscape_utilities-0.0.38.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
ecoscape_utilities/__init__.py,sha256=LXt1rL9JVsjnCmsNZwZ2aoElphIK-koaEDdW6ffZsMQ,50
|
|
2
|
-
ecoscape_utilities/bird_runs.py,sha256=v43PfH_4ojpkTE-EFOJxr0oOW3M9suNm_1zMjZ9P-eI,5409
|
|
3
|
-
ecoscape_utilities/ebird_db.py,sha256=LLd6noS4LJQLOtQEquVuRo1rRKm0XrM4ygba-xV7O88,30656
|
|
4
|
-
ecoscape_utilities-0.0.36.dist-info/licenses/LICENSE.md,sha256=3vh2mpA_XIR3FJot6a5F9DqktAoq45sEGIRkYjvAEeU,1304
|
|
5
|
-
ecoscape_utilities-0.0.36.dist-info/METADATA,sha256=8Jom07zUfpyrfIG4P_h3MnN-IrTp0-4d4bdJnQmQR1E,1382
|
|
6
|
-
ecoscape_utilities-0.0.36.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
7
|
-
ecoscape_utilities-0.0.36.dist-info/top_level.txt,sha256=jLf7iMlySaJg0Vh8z4lbAaqOc5W5ruMgKFvp797CryQ,19
|
|
8
|
-
ecoscape_utilities-0.0.36.dist-info/RECORD,,
|
|
File without changes
|
{ecoscape_utilities-0.0.36.dist-info → ecoscape_utilities-0.0.38.dist-info}/licenses/LICENSE.md
RENAMED
|
File without changes
|
|
File without changes
|