Add seed_insects.py (15 curated beneficial + pest insects)

This commit is contained in:
2026-06-05 21:49:12 +02:00
parent 2cfa57a188
commit 62c2aecc4e
+134
View File
@@ -0,0 +1,134 @@
#!/usr/bin/env python3
"""
Seed a curated starter set of beneficial & pest insects relevant to a temperate
permaculture farm. Conservative, widely-documented entomological facts.
Idempotent: skips insects whose slug already exists.
Run: HERBAPI_TOKEN=... python3 seed_insects.py
"""
import json
import os
import re
import urllib.error
import urllib.request
BASE = os.environ.get("HERBAPI_BASE", "http://herbapi01.corp.sub-net.at:8080/api/v1")
TOKEN = os.environ.get("HERBAPI_TOKEN", "")
def api(path, method="GET", data=None):
r = urllib.request.Request(
BASE + path,
data=json.dumps(data).encode() if data is not None else None,
method=method,
)
r.add_header("Authorization", "Bearer " + TOKEN)
r.add_header("Content-Type", "application/json")
try:
with urllib.request.urlopen(r) as resp:
return resp.status, json.loads(resp.read().decode())
except urllib.error.HTTPError as e:
return e.code, e.read().decode()[:200]
INSECTS = [
# ── Beneficials ──
{"name_scientific": "Apis mellifera", "name_de": "Westliche Honigbiene", "name_en": "Western honey bee",
"order_scientific": "Hymenoptera", "family_scientific": "Apidae", "role": "beneficial",
"beneficial_roles": ["pollinator"], "life_cycle": "holometabolous", "overwinters_as": "adult",
"active_months": [3, 4, 5, 6, 7, 8, 9, 10],
"description": "Eusocial honey bee; the principal managed pollinator of orchards and field crops.",
"native_range": "Europe, Africa, Western Asia"},
{"name_scientific": "Bombus terrestris", "name_de": "Dunkle Erdhummel", "name_en": "Buff-tailed bumblebee",
"order_scientific": "Hymenoptera", "family_scientific": "Apidae", "role": "beneficial",
"beneficial_roles": ["pollinator"], "life_cycle": "holometabolous", "overwinters_as": "adult",
"active_months": [3, 4, 5, 6, 7, 8, 9],
"description": "Buzz-pollinator, effective on tomatoes and early-season fruit in cool weather.",
"native_range": "Europe"},
{"name_scientific": "Osmia bicornis", "name_de": "Rote Mauerbiene", "name_en": "Red mason bee",
"order_scientific": "Hymenoptera", "family_scientific": "Megachilidae", "role": "beneficial",
"beneficial_roles": ["pollinator"], "life_cycle": "holometabolous", "overwinters_as": "adult",
"active_months": [4, 5, 6],
"description": "Solitary spring bee; excellent orchard pollinator, readily uses bee hotels.",
"native_range": "Europe"},
{"name_scientific": "Coccinella septempunctata", "name_de": "Siebenpunkt-Marienkäfer", "name_en": "Seven-spot ladybird",
"order_scientific": "Coleoptera", "family_scientific": "Coccinellidae", "role": "beneficial",
"beneficial_roles": ["predator"], "preys_on": ["myzus-persicae"], "life_cycle": "holometabolous",
"overwinters_as": "adult", "active_months": [4, 5, 6, 7, 8, 9],
"description": "Adults and larvae are voracious aphid predators.", "native_range": "Palearctic"},
{"name_scientific": "Chrysoperla carnea", "name_de": "Gemeine Florfliege", "name_en": "Green lacewing",
"order_scientific": "Neuroptera", "family_scientific": "Chrysopidae", "role": "beneficial",
"beneficial_roles": ["predator"], "preys_on": ["myzus-persicae"], "life_cycle": "holometabolous",
"overwinters_as": "adult", "active_months": [4, 5, 6, 7, 8, 9],
"description": "Larvae ('aphid lions') prey on aphids, mites and small caterpillars.", "native_range": "Europe"},
{"name_scientific": "Episyrphus balteatus", "name_de": "Hainschwebfliege", "name_en": "Marmalade hoverfly",
"order_scientific": "Diptera", "family_scientific": "Syrphidae", "role": "beneficial",
"beneficial_roles": ["pollinator", "predator"], "preys_on": ["myzus-persicae"], "life_cycle": "holometabolous",
"overwinters_as": "adult", "active_months": [3, 4, 5, 6, 7, 8, 9, 10],
"description": "Adults pollinate; larvae are major aphid predators.", "native_range": "Palearctic"},
{"name_scientific": "Aphidius colemani", "name_de": "Blattlaus-Schlupfwespe", "name_en": "Aphid parasitoid wasp",
"order_scientific": "Hymenoptera", "family_scientific": "Braconidae", "role": "beneficial",
"beneficial_roles": ["parasitoid"], "preys_on": ["myzus-persicae"], "life_cycle": "holometabolous",
"description": "Tiny wasp that parasitises aphids; widely used in biocontrol.", "native_range": "Cosmopolitan (biocontrol)"},
{"name_scientific": "Carabus auratus", "name_de": "Goldlaufkäfer", "name_en": "Golden ground beetle",
"order_scientific": "Coleoptera", "family_scientific": "Carabidae", "role": "beneficial",
"beneficial_roles": ["predator"], "life_cycle": "holometabolous", "overwinters_as": "adult",
"active_months": [4, 5, 6, 7, 8],
"description": "Ground-dwelling predator of slugs, caterpillars and other soil pests.", "native_range": "Western Europe"},
# ── Pests ──
{"name_scientific": "Myzus persicae", "name_de": "Grüne Pfirsichblattlaus", "name_en": "Green peach aphid",
"order_scientific": "Hemiptera", "family_scientific": "Aphididae", "role": "pest", "pest_severity": "major",
"life_cycle": "hemimetabolous", "active_months": [4, 5, 6, 7, 8, 9, 10],
"description": "Highly polyphagous aphid; sap-sucker and major virus vector.", "native_range": "Cosmopolitan"},
{"name_scientific": "Leptinotarsa decemlineata", "name_de": "Kartoffelkäfer", "name_en": "Colorado potato beetle",
"order_scientific": "Coleoptera", "family_scientific": "Chrysomelidae", "role": "pest", "pest_severity": "major",
"life_cycle": "holometabolous", "overwinters_as": "adult", "active_months": [5, 6, 7, 8],
"description": "Defoliates potato and other solanaceous crops; rapid resistance to insecticides.", "native_range": "North America (invasive in Europe)"},
{"name_scientific": "Pieris brassicae", "name_de": "Großer Kohlweißling", "name_en": "Large white",
"order_scientific": "Lepidoptera", "family_scientific": "Pieridae", "role": "pest", "pest_severity": "moderate",
"life_cycle": "holometabolous", "overwinters_as": "pupa", "active_months": [4, 5, 6, 7, 8, 9],
"description": "Caterpillars defoliate brassicas (cabbage, kale, broccoli).", "native_range": "Europe, North Africa, Asia"},
{"name_scientific": "Plutella xylostella", "name_de": "Kohlmotte", "name_en": "Diamondback moth",
"order_scientific": "Lepidoptera", "family_scientific": "Plutellidae", "role": "pest", "pest_severity": "moderate",
"life_cycle": "holometabolous", "active_months": [5, 6, 7, 8, 9],
"description": "Small moth whose larvae mine and skeletonise brassica leaves; resistance-prone.", "native_range": "Cosmopolitan"},
{"name_scientific": "Delia radicum", "name_de": "Kleine Kohlfliege", "name_en": "Cabbage root fly",
"order_scientific": "Diptera", "family_scientific": "Anthomyiidae", "role": "pest", "pest_severity": "moderate",
"life_cycle": "holometabolous", "overwinters_as": "pupa", "active_months": [4, 5, 6, 7, 8],
"description": "Larvae feed on brassica roots, wilting and killing transplants.", "native_range": "Holarctic"},
{"name_scientific": "Phyllotreta nemorum", "name_de": "Gelbstreifiger Kohlerdfloh", "name_en": "Turnip flea beetle",
"order_scientific": "Coleoptera", "family_scientific": "Chrysomelidae", "role": "pest", "pest_severity": "minor",
"life_cycle": "holometabolous", "overwinters_as": "adult", "active_months": [4, 5, 6, 7],
"description": "Adults shot-hole brassica seedlings; worst in warm dry spells.", "native_range": "Europe, Asia"},
{"name_scientific": "Forficula auricularia", "name_de": "Gemeiner Ohrwurm", "name_en": "European earwig",
"order_scientific": "Dermaptera", "family_scientific": "Forficulidae", "role": "both",
"beneficial_roles": ["predator"], "pest_severity": "minor", "preys_on": ["myzus-persicae"],
"life_cycle": "hemimetabolous", "overwinters_as": "adult", "active_months": [5, 6, 7, 8, 9, 10],
"description": "Eats aphids and codling-moth eggs (beneficial) but can damage soft fruit and seedlings.",
"native_range": "Europe"},
]
def main():
if not TOKEN:
raise SystemExit("HERBAPI_TOKEN not set")
existing = {i["slug"] for i in api("/insects?per_page=100")[1]["data"]}
created = skipped = errors = 0
for ins in INSECTS:
slug = re.sub(r"[^a-z0-9]+", "-", ins["name_scientific"].lower()).strip("-")
if slug in existing:
print(f"skip {slug} (exists)")
skipped += 1
continue
code, resp = api("/insects", "POST", ins)
if code == 200:
print(f"created {slug}")
created += 1
else:
print(f"ERROR {slug}: {code} {resp}")
errors += 1
print(f"\ncreated={created} skipped={skipped} errors={errors}")
if __name__ == "__main__":
main()