ebird-api-data 0.5.0__tar.gz → 0.5.1__tar.gz

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.
Files changed (40) hide show
  1. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/PKG-INFO +2 -2
  2. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/pyproject.toml +3 -3
  3. ebird_api_data-0.5.1/src/ebird/api/data/__init__.py +1 -0
  4. ebird_api_data-0.5.0/src/ebird/api/data/__init__.py +0 -1
  5. ebird_api_data-0.5.0/src/ebird/api/data/factories.py +0 -382
  6. ebird_api_data-0.5.0/src/ebird/api/data/faker_providers.py +0 -345
  7. ebird_api_data-0.5.0/src/ebird/api/data/fixtures/README.md +0 -354
  8. ebird_api_data-0.5.0/src/ebird/api/data/fixtures/generate_portugal_data.py +0 -527
  9. ebird_api_data-0.5.0/src/ebird/api/data/fixtures/portugal_observations.json +0 -139905
  10. ebird_api_data-0.5.0/src/ebird/api/data/models/models.md +0 -192
  11. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/.gitignore +0 -0
  12. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/LICENSE +0 -0
  13. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/README.md +0 -0
  14. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/admin.py +0 -0
  15. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/apps.py +0 -0
  16. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/fields.py +0 -0
  17. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/loaders.py +0 -0
  18. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/locale/en/LC_MESSAGES/django.mo +0 -0
  19. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/locale/en/LC_MESSAGES/django.po +0 -0
  20. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/management/__init__.py +0 -0
  21. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/management/commands/__init__.py +0 -0
  22. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/management/commands/add_checklists.py +0 -0
  23. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/migrations/0001_initial.py +0 -0
  24. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/migrations/0002_expand_filter.py +0 -0
  25. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/migrations/0003_remove_checklist_published_and_more.py +0 -0
  26. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/migrations/0004_remove_observer_multiple.py +0 -0
  27. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/migrations/__init__.py +0 -0
  28. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/models/__init__.py +0 -0
  29. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/models/checklist.py +0 -0
  30. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/models/country.py +0 -0
  31. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/models/county.py +0 -0
  32. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/models/location.py +0 -0
  33. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/models/observation.py +0 -0
  34. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/models/observer.py +0 -0
  35. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/models/species.py +0 -0
  36. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/models/state.py +0 -0
  37. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/templates/admin/data/species/change_list_object_tools.html +0 -0
  38. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/templates/admin/data/species/fetch_species.html +0 -0
  39. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/templates/data/widgets/translation_field.html +0 -0
  40. {ebird_api_data-0.5.0 → ebird_api_data-0.5.1}/src/ebird/api/data/widgets.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ebird-api-data
3
- Version: 0.5.0
3
+ Version: 0.5.1
4
4
  Summary: eBird API Data is a reusable Django app for loading data from eBird into a database.
5
5
  Author-email: Stuart MacKay <smackay@flagstonesoftware.com>
6
6
  License-Expression: MIT
@@ -23,7 +23,7 @@ Classifier: Topic :: Scientific/Engineering :: Information Analysis
23
23
  Requires-Python: >=3.10
24
24
  Requires-Dist: beautifulsoup4>=4.13.3
25
25
  Requires-Dist: django>=4.2
26
- Requires-Dist: ebird-api-requests==4.0.2
26
+ Requires-Dist: ebird-api-requests>=4.1.0
27
27
  Requires-Dist: lxml>=6.0.0
28
28
  Description-Content-Type: text/markdown
29
29
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ebird-api-data"
3
- version = "0.5.0"
3
+ version = "0.5.1"
4
4
  description = "eBird API Data is a reusable Django app for loading data from eBird into a database."
5
5
  keywords = ["checklists", "observations", "species", "Django", "eBird", "models"]
6
6
  license = "MIT"
@@ -13,7 +13,7 @@ requires-python = ">=3.10"
13
13
  dependencies = [
14
14
  "beautifulsoup4>=4.13.3",
15
15
  "django>=4.2",
16
- "ebird-api-requests==4.0.2",
16
+ "ebird-api-requests>=4.1.0",
17
17
  "lxml>=6.0.0",
18
18
  ]
19
19
  classifiers = [
@@ -64,7 +64,7 @@ dev-dependencies = [
64
64
  ]
65
65
 
66
66
  [tool.bumpversion]
67
- current_version = "0.5.0"
67
+ current_version = "0.5.1"
68
68
  parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
69
69
  serialize = ["{major}.{minor}.{patch}"]
70
70
  ignore_missing_version = false
@@ -0,0 +1 @@
1
+ __version__ = "0.5.1"
@@ -1 +0,0 @@
1
- __version__ = "0.5.0"
@@ -1,382 +0,0 @@
1
- """
2
- FactoryBoy factories for eBird API data models.
3
-
4
- These factories provide an easy way to create test data with realistic,
5
- contextually appropriate values using Faker providers.
6
-
7
- Usage:
8
- from ebird.api.data.factories import ChecklistFactory, ObservationFactory
9
-
10
- # Create a single checklist with observations
11
- checklist = ChecklistFactory()
12
-
13
- # Create multiple checklists
14
- checklists = ChecklistFactory.create_batch(10)
15
-
16
- # Create checklist with specific location
17
- checklist = ChecklistFactory(location__name="Ria de Aveiro")
18
-
19
- # Create observation with specific species
20
- observation = ObservationFactory(species__species_code="houspa")
21
- """
22
-
23
- import factory
24
- from factory import fuzzy
25
- from factory.django import DjangoModelFactory
26
- from faker import Faker
27
-
28
- from ebird.api.data.models import (
29
- Country,
30
- State,
31
- County,
32
- Location,
33
- Species,
34
- Observer,
35
- Checklist,
36
- Observation,
37
- )
38
- from ebird.api.data.faker_providers import (
39
- BirdProvider,
40
- LocationProvider,
41
- ObserverProvider,
42
- )
43
-
44
- # Initialize Faker with custom providers
45
- fake = Faker()
46
- fake.add_provider(BirdProvider)
47
- fake.add_provider(LocationProvider)
48
- fake.add_provider(ObserverProvider)
49
-
50
-
51
- class CountryFactory(DjangoModelFactory):
52
- """Factory for Country model."""
53
-
54
- class Meta:
55
- model = Country
56
- django_get_or_create = ("code",)
57
-
58
- code = "PT"
59
- name = "Portugal"
60
- place = "PT"
61
-
62
-
63
- class StateFactory(DjangoModelFactory):
64
- """Factory for State model."""
65
-
66
- class Meta:
67
- model = State
68
- django_get_or_create = ("code",)
69
-
70
- code = factory.LazyFunction(lambda: fake.portuguese_state_code())
71
- name = factory.LazyAttribute(lambda obj: fake.portuguese_state_name())
72
- place = factory.LazyAttribute(lambda obj: f"PT, {obj.name}")
73
-
74
-
75
- class CountyFactory(DjangoModelFactory):
76
- """Factory for County model."""
77
-
78
- class Meta:
79
- model = County
80
-
81
- code = factory.Sequence(lambda n: f"PT-{n:02d}-CTY")
82
- name = factory.Faker("city", locale="pt_PT")
83
- place = factory.LazyAttribute(lambda obj: f"PT, {obj.name}")
84
-
85
-
86
- class LocationFactory(DjangoModelFactory):
87
- """Factory for Location model."""
88
-
89
- class Meta:
90
- model = Location
91
-
92
- identifier = factory.Sequence(lambda n: f"L{n:06d}")
93
- original = factory.LazyFunction(lambda: fake.location_name())
94
- name = factory.LazyAttribute(lambda obj: obj.original)
95
-
96
- country = factory.SubFactory(CountryFactory)
97
- state = factory.SubFactory(StateFactory)
98
- county = factory.SubFactory(CountyFactory)
99
-
100
- latitude = factory.LazyFunction(lambda: fake.portugal_coordinates()[0])
101
- longitude = factory.LazyFunction(lambda: fake.portugal_coordinates()[1])
102
-
103
- url = factory.LazyAttribute(
104
- lambda obj: f"https://ebird.org/hotspot/{obj.identifier}" if obj.hotspot else ""
105
- )
106
- hotspot = factory.LazyFunction(lambda: fake.location_is_hotspot())
107
-
108
- data = factory.LazyFunction(lambda: {"habitat": fake.bird_habitat()})
109
-
110
-
111
- class SpeciesFactory(DjangoModelFactory):
112
- """Factory for Species model."""
113
-
114
- class Meta:
115
- model = Species
116
- django_get_or_create = ("species_code",)
117
-
118
- species_code = factory.LazyFunction(lambda: fake.bird_species_code())
119
- taxon_order = factory.Faker("random_int", min=1, max=5000)
120
- order = "Passeriformes"
121
- category = "species"
122
- family_code = factory.Faker("word")
123
-
124
- common_name = factory.LazyAttribute(
125
- lambda obj: f'{{"en": "{fake.bird_species_name(obj.species_code)}"}}'
126
- )
127
- scientific_name = factory.Faker("sentence", nb_words=2)
128
-
129
- family_common_name = factory.LazyAttribute(
130
- lambda obj: f'{{"en": "{obj.family_code.title()}"}}'
131
- )
132
- family_scientific_name = ""
133
-
134
- data = factory.Dict({"habitats": factory.List([factory.LazyFunction(lambda: fake.bird_habitat())])})
135
-
136
-
137
- class ObserverFactory(DjangoModelFactory):
138
- """Factory for Observer model."""
139
-
140
- class Meta:
141
- model = Observer
142
-
143
- identifier = factory.LazyFunction(lambda: fake.observer_identifier())
144
- name = factory.LazyFunction(lambda: fake.observer_name())
145
- original = factory.LazyAttribute(lambda obj: obj.name)
146
- enabled = True
147
-
148
- data = factory.LazyFunction(
149
- lambda: {"experience": fake.observer_experience_level()}
150
- )
151
-
152
-
153
- class ChecklistFactory(DjangoModelFactory):
154
- """
155
- Factory for Checklist model.
156
-
157
- Creates realistic checklists with appropriate effort metrics based on protocol.
158
- """
159
-
160
- class Meta:
161
- model = Checklist
162
-
163
- identifier = factory.Sequence(lambda n: f"S{n:08d}")
164
-
165
- # Timestamps
166
- added = factory.Faker("date_time_this_year", tzinfo=None)
167
- edited = factory.LazyAttribute(lambda obj: obj.added)
168
-
169
- # Relationships
170
- country = factory.SubFactory(CountryFactory)
171
- state = factory.SubFactory(StateFactory)
172
- county = factory.SubFactory(CountyFactory)
173
- location = factory.SubFactory(LocationFactory)
174
- observer = factory.SubFactory(ObserverFactory)
175
-
176
- # Counts (will be set by post_generation for observations)
177
- observer_count = 1
178
- species_count = factory.Faker("random_int", min=3, max=20)
179
-
180
- # Date/Time
181
- date = factory.LazyAttribute(lambda obj: obj.started.date() if obj.started else fake.date_this_year())
182
- time = factory.LazyAttribute(lambda obj: obj.started.time() if obj.started else fake.time())
183
- started = factory.Faker("date_time_this_year", tzinfo=None)
184
-
185
- # Protocol and effort
186
- protocol_code = factory.LazyFunction(lambda: fake.checklist_protocol_code())
187
- project_code = "EBIRD"
188
-
189
- duration = factory.LazyAttribute(
190
- lambda obj: fake.checklist_duration(obj.protocol_code)
191
- )
192
- distance = factory.LazyAttribute(
193
- lambda obj: fake.checklist_distance(obj.protocol_code)
194
- )
195
- area = None
196
-
197
- complete = True
198
- comments = ""
199
-
200
- url = factory.LazyAttribute(
201
- lambda obj: f"https://ebird.org/checklist/{obj.identifier}"
202
- )
203
-
204
- data = factory.Dict({})
205
-
206
- @factory.post_generation
207
- def with_observations(self, create, extracted, **kwargs):
208
- """
209
- Post-generation hook to create observations for the checklist.
210
-
211
- Usage:
212
- ChecklistFactory(with_observations=5) # Creates 5 observations
213
- ChecklistFactory(with_observations=True) # Creates 3-10 observations
214
- """
215
- if not create:
216
- return
217
-
218
- if extracted:
219
- # If boolean True, create random number of observations
220
- if extracted is True:
221
- num_observations = fake.random_int(min=3, max=10)
222
- else:
223
- num_observations = extracted
224
-
225
- # Get habitat from location
226
- habitat = self.location.data.get("habitat", "urban")
227
-
228
- # Get appropriate species for habitat
229
- species_codes = fake.bird_species_list_for_habitat(
230
- habitat, min_species=num_observations, max_species=num_observations
231
- )
232
-
233
- for species_code in species_codes:
234
- species, _ = Species.objects.get_or_create(
235
- species_code=species_code,
236
- defaults={
237
- "common_name": f'{{"en": "{fake.bird_species_name(species_code)}"}}',
238
- "scientific_name": f"Species {species_code}",
239
- "taxon_order": fake.random_int(min=1, max=5000),
240
- "order": "Passeriformes",
241
- "category": "species",
242
- "family_code": "family1",
243
- }
244
- )
245
-
246
- ObservationFactory(
247
- checklist=self,
248
- species=species,
249
- observer=self.observer,
250
- country=self.country,
251
- state=self.state,
252
- county=self.county,
253
- location=self.location,
254
- date=self.date,
255
- time=self.time,
256
- started=self.started,
257
- )
258
-
259
- # Update species count
260
- self.species_count = num_observations
261
- self.save()
262
-
263
-
264
- class ObservationFactory(DjangoModelFactory):
265
- """
266
- Factory for Observation model.
267
-
268
- Creates realistic observations with appropriate counts and media flags.
269
- """
270
-
271
- class Meta:
272
- model = Observation
273
-
274
- identifier = factory.Sequence(lambda n: f"OBS{n:09d}")
275
-
276
- # Timestamps
277
- edited = factory.Faker("date_time_this_year", tzinfo=None)
278
-
279
- # Relationships
280
- checklist = factory.SubFactory(ChecklistFactory)
281
- species = factory.SubFactory(SpeciesFactory)
282
- observer = factory.SubFactory(ObserverFactory)
283
-
284
- country = factory.LazyAttribute(lambda obj: obj.checklist.country)
285
- state = factory.LazyAttribute(lambda obj: obj.checklist.state)
286
- county = factory.LazyAttribute(lambda obj: obj.checklist.county)
287
- location = factory.LazyAttribute(lambda obj: obj.checklist.location)
288
-
289
- # Date/Time (inherit from checklist)
290
- date = factory.LazyAttribute(lambda obj: obj.checklist.date)
291
- time = factory.LazyAttribute(lambda obj: obj.checklist.time)
292
- started = factory.LazyAttribute(lambda obj: obj.checklist.started)
293
-
294
- # Count based on species
295
- count = factory.LazyAttribute(
296
- lambda obj: fake.bird_count(obj.species.species_code)
297
- )
298
-
299
- # Media flags (realistic probabilities)
300
- audio = factory.LazyFunction(lambda: fake.observation_has_media()["audio"])
301
- photo = factory.LazyFunction(lambda: fake.observation_has_media()["photo"])
302
- video = factory.LazyFunction(lambda: fake.observation_has_media()["video"])
303
-
304
- approved = True
305
- reason = ""
306
- comments = ""
307
-
308
- urn = factory.LazyAttribute(lambda obj: f"urn:observation:{obj.identifier}")
309
-
310
- data = factory.Dict({})
311
-
312
-
313
- # Convenience functions for common scenarios
314
-
315
- def create_coastal_checklist(**kwargs):
316
- """Create a checklist at a coastal location with appropriate species."""
317
- location = LocationFactory(data={"habitat": "coastal"})
318
- checklist = ChecklistFactory(
319
- location=location,
320
- with_observations=True,
321
- **kwargs
322
- )
323
- return checklist
324
-
325
-
326
- def create_wetland_checklist(**kwargs):
327
- """Create a checklist at a wetland location with appropriate species."""
328
- location = LocationFactory(data={"habitat": "coastal_wetland"})
329
- checklist = ChecklistFactory(
330
- location=location,
331
- with_observations=True,
332
- **kwargs
333
- )
334
- return checklist
335
-
336
-
337
- def create_urban_checklist(**kwargs):
338
- """Create a checklist at an urban location with appropriate species."""
339
- location = LocationFactory(data={"habitat": "urban"})
340
- checklist = ChecklistFactory(
341
- location=location,
342
- with_observations=True,
343
- **kwargs
344
- )
345
- return checklist
346
-
347
-
348
- def create_grassland_checklist(**kwargs):
349
- """Create a checklist at a grassland location with steppe specialists."""
350
- location = LocationFactory(data={"habitat": "grassland"})
351
- checklist = ChecklistFactory(
352
- location=location,
353
- with_observations=True,
354
- **kwargs
355
- )
356
- return checklist
357
-
358
-
359
- def create_expert_observer_checklist(**kwargs):
360
- """Create a checklist by an expert observer with many species."""
361
- observer = ObserverFactory(data={"experience": "expert"})
362
- checklist = ChecklistFactory(
363
- observer=observer,
364
- duration=fuzzy.FuzzyInteger(120, 300).fuzz(),
365
- species_count=fuzzy.FuzzyInteger(15, 30).fuzz(),
366
- with_observations=fuzzy.FuzzyInteger(15, 30).fuzz(),
367
- **kwargs
368
- )
369
- return checklist
370
-
371
-
372
- def create_beginner_observer_checklist(**kwargs):
373
- """Create a checklist by a beginner observer with fewer species."""
374
- observer = ObserverFactory(data={"experience": "beginner"})
375
- checklist = ChecklistFactory(
376
- observer=observer,
377
- duration=fuzzy.FuzzyInteger(30, 90).fuzz(),
378
- species_count=fuzzy.FuzzyInteger(3, 8).fuzz(),
379
- with_observations=fuzzy.FuzzyInteger(3, 8).fuzz(),
380
- **kwargs
381
- )
382
- return checklist