localcosmos-app-kit 0.9.17__py3-none-any.whl → 0.10.0__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.
Files changed (27) hide show
  1. app_kit/appbuilder/AppReleaseBuilder.py +111 -53
  2. app_kit/appbuilder/JSONBuilders/TaxonProfilesJSONBuilder.py +38 -15
  3. app_kit/appbuilder/JSONBuilders/__pycache__/TaxonProfilesJSONBuilder.cpython-313.pyc +0 -0
  4. app_kit/appbuilder/TaxonBuilder.py +35 -28
  5. app_kit/appbuilder/__pycache__/AppReleaseBuilder.cpython-313.pyc +0 -0
  6. app_kit/appbuilder/__pycache__/TaxonBuilder.cpython-313.pyc +0 -0
  7. app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/manage_taxon.html +1 -1
  8. app_kit/features/taxon_profiles/forms.py +12 -37
  9. app_kit/features/taxon_profiles/models.py +29 -36
  10. app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/create_taxon_profile.html +1 -1
  11. app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_form.html +35 -54
  12. app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_morphotype.html +2 -1
  13. app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/nature_guide_taxonlist.html +2 -2
  14. app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/non_nature_guide_taxonlist.html +1 -1
  15. app_kit/features/taxon_profiles/templates/taxon_profiles/manage_taxon_profile.html +4 -4
  16. app_kit/features/taxon_profiles/urls.py +3 -0
  17. app_kit/features/taxon_profiles/views.py +44 -32
  18. app_kit/taxonomy/sources/custom/management/commands/__pycache__/import_custom_species_csv.cpython-313.pyc +0 -0
  19. app_kit/taxonomy/sources/custom/management/commands/__pycache__/import_custom_taxonomy_csv.cpython-313.pyc +0 -0
  20. app_kit/taxonomy/sources/custom/management/commands/import_custom_species_csv.py +177 -0
  21. app_kit/taxonomy/sources/custom/management/commands/import_custom_taxonomy_csv.py +177 -0
  22. {localcosmos_app_kit-0.9.17.dist-info → localcosmos_app_kit-0.10.0.dist-info}/METADATA +1 -1
  23. {localcosmos_app_kit-0.9.17.dist-info → localcosmos_app_kit-0.10.0.dist-info}/RECORD +26 -23
  24. app_kit/tests/TESTS_ROOT/media_for_tests/test/imagestore/31/a6a11b61d65ee19c4c22caa0682288ff.jpg +0 -0
  25. {localcosmos_app_kit-0.9.17.dist-info → localcosmos_app_kit-0.10.0.dist-info}/WHEEL +0 -0
  26. {localcosmos_app_kit-0.9.17.dist-info → localcosmos_app_kit-0.10.0.dist-info}/licenses/LICENCE +0 -0
  27. {localcosmos_app_kit-0.9.17.dist-info → localcosmos_app_kit-0.10.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,177 @@
1
+ # temporary script for a one-time import of BeachExplorer's higher taxonom
2
+ import csv
3
+ import os
4
+ import re
5
+ from typing import List, Optional
6
+
7
+ from django.core.management.base import BaseCommand, CommandError
8
+ from django.db import transaction
9
+
10
+ from taxonomy.models import TaxonomyModelRouter
11
+
12
+ RANK_SET = set([
13
+ 'domain','kingdom','phylum','division','class','order','family','genus','species',
14
+ 'subkingdom','infrakingdom','superphylum','subphylum','infraphylum',
15
+ 'superclass','subclass','infraclass','superorder','suborder',
16
+ 'infraorder','parvorder','superfamily','subfamily','tribe','subtribe',
17
+ 'clade'
18
+ ])
19
+
20
+
21
+ def is_code_like(val: str) -> bool:
22
+ return bool(re.fullmatch(r'[a-z]{2,6}', val))
23
+
24
+ def _non_empty_indices(parts: List[str]) -> List[int]:
25
+ return [i for i, p in enumerate(parts) if p]
26
+
27
+
28
+ class Command(BaseCommand):
29
+ help = 'Import a custom taxonomy tree from a GROK-Rang CSV (headerlos, |-getrennt).'
30
+
31
+ def add_arguments(self, parser):
32
+ parser.add_argument('csv_path', type=str, help='Pfad zur GROK-Rang CSV-Datei (ohne Header).')
33
+ parser.add_argument('--language', type=str, default=None,
34
+ help='Sprachcode für Bezeichnungen aus dem Pfad (z. B. de, en).')
35
+ parser.add_argument('--delimiter', type=str, default='|',
36
+ help='Trennzeichen (Standard: |).')
37
+ parser.add_argument('--encoding', type=str, default='utf-8',
38
+ help='Datei-Kodierung (Standard: utf-8).')
39
+ parser.add_argument('--dry-run', action='store_true', help='Nur prüfen, am Ende zurückrollen.')
40
+ parser.add_argument('--report-limit', type=int, default=10,
41
+ help='Maximale Anzahl Beispiel-Einträge in der Dry-Run-Übersicht (Standard: 10).')
42
+
43
+ def handle(self, *args, **options):
44
+ csv_path = options['csv_path']
45
+ language = options['language']
46
+ delimiter = options['delimiter'] or '|'
47
+ encoding = options['encoding']
48
+ dry_run = options['dry_run']
49
+
50
+ if not os.path.exists(csv_path):
51
+ raise CommandError(f'Datei nicht gefunden: {csv_path}')
52
+
53
+ models = TaxonomyModelRouter('taxonomy.sources.custom')
54
+ self.stdout.write(self.style.NOTICE('Quelle: taxonomy.sources.custom'))
55
+ self.stdout.write(self.style.NOTICE(f'Trennzeichen: {repr(delimiter)}'))
56
+
57
+ # track last Latin parent per depth to build a Latin-only hierarchy
58
+ self.depth_taxon = {}
59
+
60
+ with open(csv_path, 'r', encoding=encoding, newline='') as f:
61
+ reader = csv.reader(f, delimiter=delimiter)
62
+ created_count = 0
63
+ existing_count = 0
64
+ skipped_count = 0
65
+ skip_reasons = {}
66
+ skipped_examples = []
67
+ row_index = 0
68
+
69
+ try:
70
+ with transaction.atomic():
71
+ for parts in reader:
72
+ row_index += 1
73
+ if not parts:
74
+ # Treat truly empty lines as skipped for reporting
75
+ skipped_count += 1
76
+ skip_reasons['empty line'] = skip_reasons.get('empty line', 0) + 1
77
+ if len(skipped_examples) < (options.get('report_limit') or 10):
78
+ skipped_examples.append({'row': row_index, 'reason': 'empty line', 'raw': []})
79
+ continue
80
+ c, e, s, reason = self._import_grok_row(models, parts, language)
81
+ created_count += c
82
+ existing_count += e
83
+ if s:
84
+ skipped_count += s
85
+ if reason:
86
+ skip_reasons[reason] = skip_reasons.get(reason, 0) + 1
87
+ if len(skipped_examples) < (options.get('report_limit') or 10):
88
+ skipped_examples.append({'row': row_index, 'reason': reason, 'raw': parts})
89
+
90
+ if dry_run:
91
+ # Print a detailed dry-run report before rolling back
92
+ self.stdout.write(self.style.WARNING('Dry-Run Bericht:'))
93
+ self.stdout.write(f' Zeilen gelesen: {row_index}')
94
+ self.stdout.write(f' Würde erstellen: {created_count}')
95
+ self.stdout.write(f' Bereits vorhanden: {existing_count}')
96
+ self.stdout.write(f' Übersprungen: {skipped_count}')
97
+ if skip_reasons:
98
+ self.stdout.write(' Gründe für Überspringen:')
99
+ for r, cnt in sorted(skip_reasons.items(), key=lambda x: (-x[1], x[0])):
100
+ self.stdout.write(f' - {r}: {cnt}')
101
+ if skipped_examples:
102
+ self.stdout.write(' Beispiele übersprungener Einträge:')
103
+ for ex in skipped_examples:
104
+ preview = '|'.join([str(p) for p in ex.get('raw', [])])
105
+ self.stdout.write(f" - Zeile {ex['row']}: {ex['reason']} -> {preview}")
106
+ # Trigger rollback
107
+ raise CommandError('Dry-Run abgeschlossen: Änderungen werden zurückgerollt.')
108
+
109
+ except CommandError as e:
110
+ if 'Dry-Run abgeschlossen' in str(e):
111
+ self.stdout.write(self.style.WARNING(str(e)))
112
+ return
113
+ raise
114
+
115
+ self.stdout.write(self.style.SUCCESS(
116
+ f'Fertig. Erstellt: {created_count}, vorhanden: {existing_count}, Zeilen: {row_index}'))
117
+
118
+ def _get_or_create(self, models, parent, latname, author, rank):
119
+ existing_qs = models.TaxonTreeModel.objects.filter(taxon_latname=latname, rank=rank)
120
+ if parent is None:
121
+ existing_qs = existing_qs.filter(is_root_taxon=True)
122
+ else:
123
+ existing_qs = existing_qs.filter(parent=parent)
124
+
125
+ instance = existing_qs.first()
126
+ created = False
127
+ if not instance:
128
+ extra = {'rank': rank}
129
+ if parent is None:
130
+ extra['is_root_taxon'] = True
131
+ else:
132
+ extra['parent'] = parent
133
+ instance = models.TaxonTreeModel.objects.create(latname, None, **extra)
134
+ created = True
135
+ return instance, created
136
+
137
+ def _clear_deeper_depth(self, depth: int):
138
+ # drop any cached parents deeper than current depth
139
+ for d in list(self.depth_taxon.keys()):
140
+ if d > depth:
141
+ del self.depth_taxon[d]
142
+
143
+ def _import_grok_row(self, models, parts: List[str], language: Optional[str]):
144
+ # Normalize tokens but keep positional layout
145
+ parts = [(p or '').strip() for p in parts]
146
+ if not parts or len(parts) < 3:
147
+ return 0, 0, 1, 'empty or too few columns'
148
+
149
+ # Fixed GROK layout: [...path..., latin, code, rank]
150
+ rank = parts[-1]
151
+ if not rank:
152
+ return 0, 0, 1, 'missing rank'
153
+ latin = parts[-3] if len(parts) >= 3 else ''
154
+ if not latin:
155
+ return 0, 0, 1, 'missing latin name'
156
+
157
+ # Path segments are all tokens before latin
158
+ path_segments = [p for p in parts[:-3] if p]
159
+ depth = len(path_segments)
160
+ parent = self.depth_taxon.get(depth - 1) if depth > 0 else None
161
+
162
+ taxon, created = self._get_or_create(models, parent, latin, author=None, rank=rank)
163
+
164
+ # Store this taxon as the current parent at its depth and clear deeper cache
165
+ self.depth_taxon[depth] = taxon
166
+ self._clear_deeper_depth(depth)
167
+
168
+ # Locale: letzter Pfadteil als Bezeichnung (attach vernacular to Latin taxon)
169
+ if path_segments and language:
170
+ vernacular = path_segments[-1]
171
+ exists = models.TaxonLocaleModel.objects.filter(
172
+ taxon=taxon, name=vernacular, language=language
173
+ ).exists()
174
+ if not exists:
175
+ models.TaxonLocaleModel.objects.create(taxon, vernacular, language, preferred=True)
176
+
177
+ return (1, 0, 0, None) if created else (0, 1, 0, None)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: localcosmos_app_kit
3
- Version: 0.9.17
3
+ Version: 0.10.0
4
4
  Summary: LocalCosmos App Kit. Web Portal to build Android and iOS apps
5
5
  Home-page: https://github.com/localcosmos/app-kit
6
6
  Author: Thomas Uher
@@ -37,10 +37,10 @@ app_kit/app_kit_api/tests/__pycache__/test_serializers.cpython-311.pyc,sha256=Xv
37
37
  app_kit/app_kit_api/tests/__pycache__/test_views.cpython-311.pyc,sha256=jzyuIXHjnoubiVjdoa5h2YxGSTAomhTxhyxfZBqVf1o,10161
38
38
  app_kit/appbuilder/AppBuilderBase.py,sha256=mDwmMd0Fdl-wedTYWEK8AcHfiAhvjxFBGOkLrGavwTs,29160
39
39
  app_kit/appbuilder/AppPreviewBuilder.py,sha256=C0oSh_i1Cx4vLW01T0qJeo-MrtqqjD72Hh43k4kG5EI,6845
40
- app_kit/appbuilder/AppReleaseBuilder.py,sha256=Xh1G8DI5azLLA1_uE-S_4HQDACs2xqxbA87bBGhdBeo,131151
40
+ app_kit/appbuilder/AppReleaseBuilder.py,sha256=up6NEc5l46FdPBWH2iW6XZKMET_s1PEJ4Jq2J0Wiges,134050
41
41
  app_kit/appbuilder/ContentImageBuilder.py,sha256=k9YdH2d5oIyfbeoA9H_DaUigc1SQ69WnXFy9e00DdfA,7332
42
42
  app_kit/appbuilder/GBIFlib.py,sha256=iGj01hrk0iG-qjEkPM8ez_lNKL_zJedPTS3oUZDd8vg,989
43
- app_kit/appbuilder/TaxonBuilder.py,sha256=4c9tDVxWoHIXiy3z-hHku2OXceQDJDjrehvm8spXtuE,15983
43
+ app_kit/appbuilder/TaxonBuilder.py,sha256=BQcu1EWn-eGrTZhrbVCDdRsjBQ9nsjpUKaJMIXgbA8A,16390
44
44
  app_kit/appbuilder/__init__.py,sha256=PIqSBvR4NFND1zb_KOryk3PFZ5yhiGwaZIZSRSTp1JY,152
45
45
  app_kit/appbuilder/precompile_fulltree.py,sha256=Lrf5j0xGY2FgpuuWdUrfef1ZlLs-GntFYpngtZ5pTF0,2005
46
46
  app_kit/appbuilder/JSONBuilders/BackboneTaxonomyJSONBuilder.py,sha256=worozLAgqxKJSdBzQ45zlCL3l4BnpZAYX-Dl4SfmwUs,6488
@@ -52,7 +52,7 @@ app_kit/appbuilder/JSONBuilders/GlossaryJSONBuilder.py,sha256=7pITMctTmEVRbyb7Dl
52
52
  app_kit/appbuilder/JSONBuilders/JSONBuilder.py,sha256=BssXm7ueXghCmHHmWsnQekQdbE4g0UIIQ59a6k0Bzts,6010
53
53
  app_kit/appbuilder/JSONBuilders/MapJSONBuilder.py,sha256=NgP5g_H0sfq5VRkoHdMzkQUGLgUofcwG1R2xe6vUS9U,2792
54
54
  app_kit/appbuilder/JSONBuilders/NatureGuideJSONBuilder.py,sha256=LZgyfc0e2xhTB9XES6fgm_vmL-O7VBBXsRdNDapgu5E,25498
55
- app_kit/appbuilder/JSONBuilders/TaxonProfilesJSONBuilder.py,sha256=XNtRAQ31UPSghcFPUR1-RQLdzDpDxmkITb_paYP4uxQ,34716
55
+ app_kit/appbuilder/JSONBuilders/TaxonProfilesJSONBuilder.py,sha256=tvHz0--awo5Rvsc_nPNGvwbPKLAuNXUh4RX0erZOTZM,36345
56
56
  app_kit/appbuilder/JSONBuilders/TemplateContentJSONBuilder.py,sha256=zWF7SNeRosbOi876boXp0tpIYXVs04fKtauK9Fr_DRs,7382
57
57
  app_kit/appbuilder/JSONBuilders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
58
  app_kit/appbuilder/JSONBuilders/generic_forms_JSON_specification,sha256=dFabBHtkfzJqB2zNSRR2OaIyroYr1nEw_qY6VFZF7dQ,6720
@@ -74,7 +74,7 @@ app_kit/appbuilder/JSONBuilders/__pycache__/NatureGuideJSONBuilder.cpython-311.p
74
74
  app_kit/appbuilder/JSONBuilders/__pycache__/NatureGuideJSONBuilder.cpython-313.pyc,sha256=jF5kdrd9eYsIuLJtophN4ptZB67MM1poI4Oao2aY8RU,25376
75
75
  app_kit/appbuilder/JSONBuilders/__pycache__/TaxonJSONBuilder.cpython-311.pyc,sha256=nEt3jd6Pf4lb0QnFpU7QPg9bsKa68z0Vh8C85t4CMO0,9663
76
76
  app_kit/appbuilder/JSONBuilders/__pycache__/TaxonProfilesJSONBuilder.cpython-311.pyc,sha256=bffiRE-WzCN3s0sz00rFuuu8c0qFL7kRq97XwtuRnoo,22862
77
- app_kit/appbuilder/JSONBuilders/__pycache__/TaxonProfilesJSONBuilder.cpython-313.pyc,sha256=--E2Ix4-WlvKe_BPIWLnqoNmEnkfWop0ZDn2FWJu1Ew,29536
77
+ app_kit/appbuilder/JSONBuilders/__pycache__/TaxonProfilesJSONBuilder.cpython-313.pyc,sha256=y3XVQ4f5zXWVClaO6vQLNXKklpt7K4ymnix51Xnu5Ok,29288
78
78
  app_kit/appbuilder/JSONBuilders/__pycache__/TemplateContentJSONBuilder.cpython-311.pyc,sha256=7fGagTetGK129h057h6dPXMSwggBX03uHOm3_dr3ueE,5932
79
79
  app_kit/appbuilder/JSONBuilders/__pycache__/TemplateContentJSONBuilder.cpython-313.pyc,sha256=lXf1kZuOMRWsHmnP1aN7UJIPEfWF-PhiMyyZ9FfY1Tg,6501
80
80
  app_kit/appbuilder/JSONBuilders/__pycache__/__init__.cpython-311.pyc,sha256=MxwSyVkGIkNVrjjMZzXCHh9k7_ytM6tzgpNTaCtDNn4,211
@@ -84,13 +84,13 @@ app_kit/appbuilder/__pycache__/AppBuilderBase.cpython-313.pyc,sha256=GTLt_n208ej
84
84
  app_kit/appbuilder/__pycache__/AppPreviewBuilder.cpython-311.pyc,sha256=5kKHNjUuOfp31cqB_ZO175x-wGgVVhqX8YkHWSlX--k,8245
85
85
  app_kit/appbuilder/__pycache__/AppPreviewBuilder.cpython-313.pyc,sha256=C7-mLN6yGvDrknbBamjKkI9fxjfT3djrdr3-8Fhc7HQ,7526
86
86
  app_kit/appbuilder/__pycache__/AppReleaseBuilder.cpython-311.pyc,sha256=ZAHDJfyKvQzTsyFHIjvRjCiCn1dzObCPp6XYWCGHZmI,126739
87
- app_kit/appbuilder/__pycache__/AppReleaseBuilder.cpython-313.pyc,sha256=8bJrshzvJDUlDowgZ96tnBvNx6h9zh96m12mAekOwCQ,129137
87
+ app_kit/appbuilder/__pycache__/AppReleaseBuilder.cpython-313.pyc,sha256=_88iSOHywr1q1eKR6zJLdemnjwvIrL2kldxx0mZcrT0,131779
88
88
  app_kit/appbuilder/__pycache__/ContentImageBuilder.cpython-311.pyc,sha256=EyL2LamJkdU_7O_F0j3vwtTYjInblFSPKmlPLyXvSuE,8920
89
89
  app_kit/appbuilder/__pycache__/ContentImageBuilder.cpython-313.pyc,sha256=K6b-GlHYhM0SWlniDyyFfKdK_QF7kHN8yFahn2ETCa8,8737
90
90
  app_kit/appbuilder/__pycache__/GBIFlib.cpython-311.pyc,sha256=NNB_AHGQnN0ld82WuJHxGn5RthLO_fGkpVAfAHaDyMU,1945
91
91
  app_kit/appbuilder/__pycache__/GBIFlib.cpython-313.pyc,sha256=13SE5Ayqrg8n90KGWbLE7rQ-UPaU2Q0XbY5dQENpXTA,1962
92
92
  app_kit/appbuilder/__pycache__/TaxonBuilder.cpython-311.pyc,sha256=7JVnCo4-CVmaX_EIzU05is5ySaqWPA86QBlFM-B4Trw,16273
93
- app_kit/appbuilder/__pycache__/TaxonBuilder.cpython-313.pyc,sha256=mxUE3vbiXd4R9F3iFOdPIAuZySRhBJ6KIeGllVJp4Uw,16957
93
+ app_kit/appbuilder/__pycache__/TaxonBuilder.cpython-313.pyc,sha256=fNSv6AE_6jLLNiXE4SFVpSHv6_hVkeSUIGmaFJxLkao,17166
94
94
  app_kit/appbuilder/__pycache__/__init__.cpython-311.pyc,sha256=KkcyxSIx1hiGZkOwMG8qWGJQ-RPacWMKpfpnP-naNv4,388
95
95
  app_kit/appbuilder/__pycache__/__init__.cpython-313.pyc,sha256=iHwg7gUn2XzOOz0SNmIeY6GVMxTcc5NKM3gzSz4pLnA,329
96
96
  app_kit/appbuilder/app/frontends/Multiverse/settings.json,sha256=dCcy0ZGor57YhlrPUJVj-IADrF413gBBWFUfletZW6g,2026
@@ -154,7 +154,7 @@ app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/add_taxon_form.html
154
154
  app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/manage_backbone_taxa_form.html,sha256=wVUAExurrDbck2SD9pwL4IWdOx0Z-QHWU9idNbnc5VY,1529
155
155
  app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/manage_backbonetaxonomy.html,sha256=0EehuPUlE6-g7miYOycv_j2aZPqmU-Ykwd_bpC3LdMM,4101
156
156
  app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/manage_fulltree_form.html,sha256=uqw8OL3dGy7_iZzGxgGc3KHNSsGHVBniBx2FQSrM8h0,622
157
- app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/manage_taxon.html,sha256=vkQjHX7K9OGPB3lrBFnJguWpCXKzbvLmKrnwAPgOG34,1882
157
+ app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/manage_taxon.html,sha256=Rsn0XHwq4n_Zk4iPVi_MKb3sB6z6L2KeaZPP82tZi4Y,1846
158
158
  app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/remove_backbone_taxon.html,sha256=-9t83d771KmyoeENWqvxrxyoI7zOK5-sHL_rLdHxsP0,1206
159
159
  app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/swap_taxon.html,sha256=6soId42pD0s-vxCSNE8RNNotSfSWOINmMk3Eyo9hlMM,7469
160
160
  app_kit/features/backbonetaxonomy/templates/backbonetaxonomy/taxon_relationships.html,sha256=jBFcbS1CJnd0b9IqSMGcfDFR-tmHygOs4wSBfFekPEo,5503
@@ -398,10 +398,10 @@ app_kit/features/nature_guides/tests/__pycache__/test_views.cpython-311.pyc,sha2
398
398
  app_kit/features/taxon_profiles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
399
399
  app_kit/features/taxon_profiles/admin.py,sha256=suMo4x8I3JBxAFBVIdE-5qnqZ6JAZV0FESABHOSc-vg,63
400
400
  app_kit/features/taxon_profiles/apps.py,sha256=c0nynglV50B8qvXTnu7v6LZHT6N5nOTayOasKICAAJE,119
401
- app_kit/features/taxon_profiles/forms.py,sha256=T5mU0QGhG_fSNppzuzTxjxb078VA4IckOPOaP7nM5fE,16998
402
- app_kit/features/taxon_profiles/models.py,sha256=xYDHT_KI_xatFUwYYnkogXeqd70kr9Dp8YVum8hzvRw,24214
403
- app_kit/features/taxon_profiles/urls.py,sha256=wamGUfN5cpCvYEfNnTTbdqBt1GeFQbybmzsG7_KtpvA,10814
404
- app_kit/features/taxon_profiles/views.py,sha256=WCA2C8D6eyghFg42CRBQZlyvcy_UWf2iDcZPwOcRzSc,61245
401
+ app_kit/features/taxon_profiles/forms.py,sha256=jBvYFgKAG9_gpCG3dfE97KQTnTiKjTIOQenmeXVE62g,16131
402
+ app_kit/features/taxon_profiles/models.py,sha256=kllsA7VTgD5a8KVyHAUV0udMcv7Keg5hd5x1LcrmR3I,23855
403
+ app_kit/features/taxon_profiles/urls.py,sha256=IhJOF7HIPOw-VanBzJtSanKOdAgWL1vKy9evcHD3Bzw,11098
404
+ app_kit/features/taxon_profiles/views.py,sha256=gIZTKT7bdnHOBhNgLqpLsTtkAjARbMPDnHC4Y1lXoBQ,61750
405
405
  app_kit/features/taxon_profiles/zip_import.py,sha256=aYFEtaMjn5Qebj0eaOeM-WVdvMUDymH4wUOnhAItN9I,29883
406
406
  app_kit/features/taxon_profiles/migrations/0001_initial.py,sha256=aknHwoaZMBwDWMnp7dftXToVGuyN4f9xy3epQSqGkxQ,3659
407
407
  app_kit/features/taxon_profiles/migrations/0002_taxontext_long_text.py,sha256=FN2GAdO4paIgX8FpREoLk7cihlHRRaehVY7_Ve0K97w,383
@@ -418,7 +418,7 @@ app_kit/features/taxon_profiles/migrations/0012_taxonprofile_updated_at.py,sha25
418
418
  app_kit/features/taxon_profiles/migrations/0013_alter_taxonprofile_options_and_more.py,sha256=03fp39qqKjBJOiUspog7BzgxVg80lZJ8vq8dZhq8K98,596
419
419
  app_kit/features/taxon_profiles/migrations/0014_alter_taxonprofile_unique_together_and_more.py,sha256=wPO0TfoU_I9_BBLOSe3gvzMzEeGpxP5exnwuGT_ngUU,2501
420
420
  app_kit/features/taxon_profiles/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
421
- app_kit/features/taxon_profiles/templates/taxon_profiles/manage_taxon_profile.html,sha256=9uqOz0oQuA8Yxyg1yTSZs0RCWpjASOS6mIZgJm6uJFQ,11184
421
+ app_kit/features/taxon_profiles/templates/taxon_profiles/manage_taxon_profile.html,sha256=i04Bvrb5fKgxnD4oCUaqTcTf2D3RsQElmg7LHUe8HEE,11059
422
422
  app_kit/features/taxon_profiles/templates/taxon_profiles/manage_taxon_profiles.html,sha256=NJGnmoa5da40e-hUpZAG2V-UZGqf_oxAd8bIABfuaKw,9304
423
423
  app_kit/features/taxon_profiles/templates/taxon_profiles/manage_taxon_texts.html,sha256=q1Do_NKTwkQ8sHWY4Zx4CXaWbpfFBGxn6_8Uc3N4EVA,1353
424
424
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/backbone_taxa_taxonlist.html,sha256=6zEHqwPnU0bJJmyQqkXxWw90D0IQ1WPtm4sCCKXFJMQ,656
@@ -427,7 +427,7 @@ app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/change_navigation_
427
427
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/change_taxon_profile_publication_status.html,sha256=zuDHrJc77sAVLCmFmhvUMyJSYVQu8zQT_RC0PwavTiI,596
428
428
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/collected_taxon_images.html,sha256=a6HQJ6p4QMSpDqYraentxFyGmIxs-5uypFbWIyoR4q8,3654
429
429
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/collected_taxon_traits.html,sha256=PkA7sGNPBFQ_t1Pb4X1avCd_n9SVFKedN0BIsYyB0Eg,2470
430
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/create_taxon_profile.html,sha256=TylM_rq_aARbxzBgLZ8iGO6BNMFiGCue9-4saUZdS4c,1092
430
+ app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/create_taxon_profile.html,sha256=jbyin1419LNIbBltUmvN4S02K9jq2vgdJwGz3Dh8dSs,1056
431
431
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/delete_all_manually_added_images.html,sha256=_zOaLGeVD3AKPmIzwRTr-eHi0Lo38dOTsSzYI-Oz_rE,1022
432
432
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/delete_navigation_entry.html,sha256=kCNgH9qiAvF5Y3XP6UPA-XZeFb0Uw2CZakkYY-JjZD0,226
433
433
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/delete_navigation_entry_taxon.html,sha256=xn3CFCzn1qZS5tM76GeQn4-2_WL4zLo5OxUTAD47XiQ,410
@@ -438,19 +438,19 @@ app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/delete_taxon_text_
438
438
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/delete_taxon_text_type_category.html,sha256=mIgqNz2dcZyl-6U2bClztlERrSCzct5RhOnY_KB51tA,381
439
439
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_navigation_entry.html,sha256=a_Cydkty0fWKIOzcnXOa0US-eLrjKI_y8LaI4unxeC0,2497
440
440
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_navigation_image.html,sha256=9uAZLbs5Rs4Xew3ua-0BOT4MzLXjW25XjgO73vPJxP8,872
441
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_form.html,sha256=RZ-7jxCk-gxW7Ozzm_5sX7SlhG9N-LL80yYAq1iB0QY,4432
441
+ app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_form.html,sha256=VbfbX5xrfhzjBealfy49tbzZf4Z0wFXc7UvujzuMvnw,3089
442
442
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_image.html,sha256=TORQADZVRluI4VN3D_0cKJsKhEJu7y8JgOR-sDv6INU,1141
443
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_morphotype.html,sha256=uB_yzjW_cKFO32dqwaKtSUw-jLRfrzl2Aerf7cP66Fo,1071
443
+ app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_profile_morphotype.html,sha256=eVyORlAKHmHjB3crC1uTusXhmYOz72Fo2Hd3fwT00nA,1049
444
444
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_taxon_text_set.html,sha256=E98YJtky7fBZxPiP_gkT6LxaRHtN5BDPgc0ow3mU93I,1148
445
445
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_text_type.html,sha256=XFkHIQsxGFndUCMK5U-b0E48Fibbod2mlYw51DUcbWk,1404
446
446
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/manage_text_type_category.html,sha256=5aS1gI4kXOms7TWBiGIOp37Z56TzC4QyhHBuoJlkBCs,1391
447
447
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/move_image_to_section.html,sha256=IVpYDx7oLL16auz9D5rSXA6PMChPLhT6IsmQsuYkELg,585
448
448
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/move_navigation_entry.html,sha256=mZ-e8N8j-XhFaueIOpJSGv8knL2iX20i_FvQSeqS5uE,2158
449
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/nature_guide_taxonlist.html,sha256=tFbBXh60iJPOB7hWDxSr83yvfjL1DF8MfHuVGle3iZQ,2015
449
+ app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/nature_guide_taxonlist.html,sha256=dXtTcymXITUEoBsGe2XoTSbifyacPLjD0NX539cVyRU,1911
450
450
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/navigation_entry_taxa.html,sha256=6UeTMqrtUCU7WEzZBK_yT9HquxxFWONRekiwoj7jh5U,2063
451
451
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/navigation_entry_taxon_profiles.html,sha256=m3IaC1yd4lvpRTV8CnSOM60pFxZukIndmCw_Yv-Yorw,910
452
452
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/navigation_entry_taxon_profiles_list.html,sha256=DrSBBxOOMSUYBZj7-XCPvmDkWB_Y8587AVlrCLPVrxE,431
453
- app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/non_nature_guide_taxonlist.html,sha256=dGz2NdCx38ACm3lixNHsOJsedImGs7D2oLfds6iMq1U,629
453
+ app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/non_nature_guide_taxonlist.html,sha256=4sLthyIACNopPz7ev1A4866M3nxRpkrhZEgR3eT3Smo,582
454
454
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/set_taxon_text_set_for_taxon_profile.html,sha256=M92q0Qh2RB-Lxi717_EctdZbrp7v7kd1BMdrclkaQ8Q,611
455
455
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/taxon_profiles_navigation.html,sha256=a098AWlYiJae0V23YMwXx1JsPW0D_4DI1ASMn4E9Sx4,980
456
456
  app_kit/features/taxon_profiles/templates/taxon_profiles/ajax/taxon_profiles_navigation_level.html,sha256=GY0KFR7BPiLsiMIVy8xRukZpbsQ6q7RBE3QiaR7506s,6204
@@ -1797,6 +1797,10 @@ app_kit/taxonomy/sources/custom/models.py,sha256=4ExGyy2l_mYnGlsBhLndS7lQL5QSFGb
1797
1797
  app_kit/taxonomy/sources/custom/tests.py,sha256=mrbGGRNg5jwbTJtWWa7zSKdDyeB4vmgZCRc2nk6VY-g,60
1798
1798
  app_kit/taxonomy/sources/custom/urls.py,sha256=0P71XKmzS7mLeYIMcn0EE6Vi0pRV1fu-l_d317Kpnug,1032
1799
1799
  app_kit/taxonomy/sources/custom/views.py,sha256=ZFkqba9mGgKdbaZx4GNGI0hKoviyaEOnjf4CGvTTr8E,9780
1800
+ app_kit/taxonomy/sources/custom/management/commands/import_custom_species_csv.py,sha256=Ng3-FKfJpxXijxb8EzTEKXgjM8ivJiM92FAIG4ngrug,7434
1801
+ app_kit/taxonomy/sources/custom/management/commands/import_custom_taxonomy_csv.py,sha256=Y3QHClrZdvz5Fz-UgyTYhxtcCc6UxBa4BXpyL47PN54,8202
1802
+ app_kit/taxonomy/sources/custom/management/commands/__pycache__/import_custom_species_csv.cpython-313.pyc,sha256=AxUh7xot7wo__NBggEI9PEqH9lDX0GHBQ9ZkmTwLjNs,9725
1803
+ app_kit/taxonomy/sources/custom/management/commands/__pycache__/import_custom_taxonomy_csv.cpython-313.pyc,sha256=nU0sag8bvHUMSb6KBbs7EF8sZbdp5zwDdSiERW_PAQg,10567
1800
1804
  app_kit/taxonomy/sources/custom/migrations/0001_initial.py,sha256=FLCqXqGQcG0-cMeyxgSt-BuE-5uNq7HfCvYXBDni4wc,4246
1801
1805
  app_kit/taxonomy/sources/custom/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1802
1806
  app_kit/taxonomy/sources/custom/templates/custom_taxonomy/manage_custom_taxon.html,sha256=SSXwvvZflxkKAK1GrkZM15ZD6JUfjEWDmiI78TGhmKg,1348
@@ -1899,7 +1903,6 @@ app_kit/tests/TESTS_ROOT/images/app-background.jpg,sha256=bmW6cudSfmcRqGSK9P2Sc5
1899
1903
  app_kit/tests/TESTS_ROOT/images/localcosmos-logo.svg,sha256=4-MHj0FjED9eTgmUHnAP-DHCQRqc557HH9akHaoQxs0,409549
1900
1904
  app_kit/tests/TESTS_ROOT/images/test-image-2560-1440.jpg,sha256=BOP-1ZlA9wq-E1sUkOpyqUowpFCdSoF965oKgajjSq0,156278
1901
1905
  app_kit/tests/TESTS_ROOT/ipa_for_tests/TestApp.ipa,sha256=YdGWqMepeBwvpkch3DSVMlnNkf8RuGwENWuwHtoY1Do,78900
1902
- app_kit/tests/TESTS_ROOT/media_for_tests/test/imagestore/31/a6a11b61d65ee19c4c22caa0682288ff.jpg,sha256=dXT6yUqaMJ_91rwQMHT22VjDGb69KRCmm4eboxjtnxM,49349
1903
1906
  app_kit/tests/TESTS_ROOT/templates/neobiota.html,sha256=3ag2VGCuaZ-FoAu25GMUb3s4qMsY7AyhNoDf7CSZJ_w,147
1904
1907
  app_kit/tests/TESTS_ROOT/xlsx_for_testing/BackboneTaxonomy/invalid/Backbone taxonomy.xlsx,sha256=cMkmCtGBR1wwhpDSbjrscNSvLMGnb6YbaliQqws-l7M,8121
1905
1908
  app_kit/tests/TESTS_ROOT/xlsx_for_testing/BackboneTaxonomy/invalid_content_type/Backbone taxonomy.xlsx,sha256=aYRrPI-UABxQUZF-bWvbrD_31ZQgEijdKCzBGOXzGRk,7996
@@ -1935,8 +1938,8 @@ app_kit/tests/__pycache__/test_models.cpython-313.pyc,sha256=Lmv3BfjLs5Fg-olJeMl
1935
1938
  app_kit/tests/__pycache__/test_utils.cpython-313.pyc,sha256=GX3REqZygi2eO_A2F2_KtYi7hg54X5QPtCTCGWuxGpM,14054
1936
1939
  app_kit/tests/__pycache__/test_views.cpython-311.pyc,sha256=NDJR40TcMm-bXXC-wV7OgH1sGR3N7psSWYiUirkkrjU,133242
1937
1940
  app_kit/tests/__pycache__/test_views.cpython-313.pyc,sha256=q851UqIZFCCTfQb1lF4SVxV1j_Vu1hJdOlpckmrGX28,125363
1938
- localcosmos_app_kit-0.9.17.dist-info/licenses/LICENCE,sha256=VnxALPSxXoU59rlNeRdJtwS_nU79IFpVWsZZCQUM4Mw,1086
1939
- localcosmos_app_kit-0.9.17.dist-info/METADATA,sha256=e8ksAKCmQ153iA3vmv2B_1ILF-cHvCiN4JbKU19a1XA,1388
1940
- localcosmos_app_kit-0.9.17.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
1941
- localcosmos_app_kit-0.9.17.dist-info/top_level.txt,sha256=F6H4pEBkCvUR_iwQHIy4K1iby-jzfWg3CTym5XJKeys,8
1942
- localcosmos_app_kit-0.9.17.dist-info/RECORD,,
1941
+ localcosmos_app_kit-0.10.0.dist-info/licenses/LICENCE,sha256=VnxALPSxXoU59rlNeRdJtwS_nU79IFpVWsZZCQUM4Mw,1086
1942
+ localcosmos_app_kit-0.10.0.dist-info/METADATA,sha256=pVHi86lhY2n4lU4kKq5TLikiIHOxHWFiEerAaFnNzqw,1388
1943
+ localcosmos_app_kit-0.10.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
1944
+ localcosmos_app_kit-0.10.0.dist-info/top_level.txt,sha256=F6H4pEBkCvUR_iwQHIy4K1iby-jzfWg3CTym5XJKeys,8
1945
+ localcosmos_app_kit-0.10.0.dist-info/RECORD,,