Create Location and Add Items¶
This example demonstrates how to create a new storage location in Homebox, add items to it (both individually and in bulk via CSV import), attach images, and generate a printable location label.
What it demonstrates¶
- Creating a location with
client.locations.create_location() - Creating a single item with
client.items.create_item() - Uploading photo attachments with
client.items.create_item_attachment() - Bulk-importing items from CSV using
client.items.export_items()andclient.items.import_items() - Generating a printable PNG label for a location with
client.labelmaker.get_location_label()
Setup¶
Copy examples/.env.sample to examples/.env and set:
HOMEBOX_URL=https://your-homebox-instance/api
HOMEBOX_USERNAME=your@email.com
HOMEBOX_PASSWORD=yourpassword
Then run:
A PNG label file will be saved to the current working directory.
Source code¶
examples/create_location_add_items.py
"""Example script that shows how to create a new location in homebox and add several items to that location.
Exemplifies how to add images to items, and how to use the bulk item creation endpoint.
Script generates a label png for the created location.
In order to run this script, you need to have the following environment variables set:
- HOMEBOX_URL: the URL of your Homebox instance (e.g. http://localhost
- HOMEBOX_USERNAME: the username of a user with permissions to create locations and items
- HOMEBOX_PASSWORD: the password of that user
You can use the .env.sample file in the examples directory as a template for your .env file.
"""
from __future__ import annotations
import base64
import csv
import io
import os
from datetime import UTC, datetime
from pathlib import Path
from homebox import HomeboxClient
from homebox.models import DuplicateOptions, ItemCreate, LocationCreate
def _load_dotenv() -> None:
dotenv_path = Path(__file__).parent / ".env"
if not dotenv_path.is_file():
return
with dotenv_path.open() as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
if "=" not in line:
continue
key, value = line.split("=", 1)
os.environ.setdefault(key.strip(), value.strip())
def _require_env(name: str) -> str:
value = os.getenv(name)
if not value:
raise RuntimeError(f"Missing required environment variable: {name}")
return value
def _build_client() -> HomeboxClient:
base_url = _require_env("HOMEBOX_URL")
username = _require_env("HOMEBOX_USERNAME")
password = _require_env("HOMEBOX_PASSWORD")
client = HomeboxClient(base_url=base_url)
client.login(username, password)
return client
def _tiny_png() -> bytes:
return base64.b64decode(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO7+X0kAAAAASUVORK5CYII="
)
def _safe_name(value: str) -> str:
cleaned = "".join(ch.lower() if ch.isalnum() else "_" for ch in value).strip("_")
return cleaned or "location"
def _set_first_key(record: dict[str, str], keys: list[str], value: str) -> None:
lowered = {k.lower().replace(" ", ""): k for k in record}
for key in keys:
match = lowered.get(key.lower().replace(" ", ""))
if match:
record[match] = value
return
def main() -> None:
_load_dotenv()
client = _build_client()
created_location_id: str | None = None
created_item_ids: list[str] = []
location_name = f"Example Storage {datetime.now(UTC).strftime('%Y%m%d_%H%M%S')}"
try:
location = client.locations.create_location(
LocationCreate(
name=location_name,
description="Location created by create_location_add_items.py",
)
)
created_location_id = location.id
print(f"Created location: {location.name} ({location.id})")
featured_item = client.items.create_item(
ItemCreate(
name="Mirrorless Camera",
description="Featured item created individually",
quantity=1,
locationId=location.id,
)
)
if featured_item.id:
created_item_ids.append(featured_item.id)
print(f"Created featured item: {featured_item.name} ({featured_item.id})")
image = _tiny_png()
client.items.create_item_attachment(
featured_item.id,
file=image,
type="photo",
primary=True,
name="front.png",
)
client.items.create_item_attachment(
featured_item.id,
file=image,
type="photo",
primary=False,
name="rear.png",
)
print("Attached two images to the featured item")
# Show the ancestry path of the featured item (location → item).
path = client.items.get_item_path(featured_item.id)
print("Item path:")
for node in path:
print(f" [{node.type}] {node.name} ({node.id})")
# Duplicate the featured item and keep track of the copy for cleanup.
duplicate = client.items.duplicate_item(
featured_item.id,
DuplicateOptions(
copyAttachments=True,
copyCustomFields=True,
copyMaintenance=False,
copyPrefix="Copy of ",
),
)
if duplicate.id:
created_item_ids.append(duplicate.id)
print(f"Duplicated item: {duplicate.name} ({duplicate.id})")
bulk_items = [
{"name": "Tripod", "description": "Carbon tripod", "quantity": "1"},
{"name": "Camera Bag", "description": "Weather resistant bag", "quantity": "2"},
{"name": "SD Card", "description": "128GB UHS-II", "quantity": "4"},
]
exported_csv = client.items.export_items()
headers = next(csv.reader([exported_csv.splitlines()[0]]))
out = io.StringIO()
writer = csv.DictWriter(out, fieldnames=headers)
writer.writeheader()
for item in bulk_items:
row = {header: "" for header in headers}
_set_first_key(row, ["HB.name"], item["name"])
_set_first_key(row, ["HB.description"], item["description"])
_set_first_key(row, ["HB.quantity", "HB.qty"], item["quantity"])
_set_first_key(row, ["HB.location", "HB.locationname"], location.name)
writer.writerow(row)
client.items.import_items(out.getvalue().encode("utf-8"))
print(f"Bulk-created {len(bulk_items)} items using import_items()")
label_data = client.labelmaker.get_location_label(location.id, print=False)
output_file = Path.cwd() / f"{_safe_name(location_name)}_label.png"
output_file.write_bytes(label_data)
print(f"Saved location label to: {output_file}")
finally:
for item_id in created_item_ids:
client.items.delete_item(item_id)
print(f"Deleted item: {item_id}")
if created_location_id:
client.locations.delete_location(created_location_id)
print(f"Deleted location: {created_location_id}")
if __name__ == "__main__":
main()