testdata imgs
49
testdata/generate_testdata.py
vendored
|
|
@ -8,6 +8,7 @@ who are friends with each other.
|
||||||
import csv
|
import csv
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
@ -15,6 +16,9 @@ from hashlib import sha256
|
||||||
from nacl.signing import SigningKey
|
from nacl.signing import SigningKey
|
||||||
from nacl.encoding import HexEncoder
|
from nacl.encoding import HexEncoder
|
||||||
|
|
||||||
|
IMGS_DIR = os.path.join(os.path.dirname(__file__), 'imgs')
|
||||||
|
IMAGE_ATTACHMENT_PROBABILITY = 0.9
|
||||||
|
|
||||||
|
|
||||||
# Realistic item database with shared_data category/tag references using fully qualified handles
|
# Realistic item database with shared_data category/tag references using fully qualified handles
|
||||||
# Format: (name, category_handle, tags_handles, policy, description, qty, properties_list)
|
# Format: (name, category_handle, tags_handles, policy, description, qty, properties_list)
|
||||||
|
|
@ -250,6 +254,21 @@ def load_shared_data():
|
||||||
return all_tags, all_categories, all_properties
|
return all_tags, all_categories, all_properties
|
||||||
|
|
||||||
|
|
||||||
|
def load_available_images():
|
||||||
|
"""Read every file in imgs/ and return a list of (data, mime_type) tuples."""
|
||||||
|
images = []
|
||||||
|
for filename in sorted(os.listdir(IMGS_DIR)):
|
||||||
|
filepath = os.path.join(IMGS_DIR, filename)
|
||||||
|
if not os.path.isfile(filepath):
|
||||||
|
continue
|
||||||
|
mime_type, _ = mimetypes.guess_type(filename)
|
||||||
|
if not mime_type:
|
||||||
|
continue
|
||||||
|
with open(filepath, 'rb') as f:
|
||||||
|
images.append((f.read(), mime_type))
|
||||||
|
return images
|
||||||
|
|
||||||
|
|
||||||
def generate_keypair():
|
def generate_keypair():
|
||||||
"""Generate a signing key pair and return (hex_private_key, hex_public_key)."""
|
"""Generate a signing key pair and return (hex_private_key, hex_public_key)."""
|
||||||
signing_key = SigningKey.generate()
|
signing_key = SigningKey.generate()
|
||||||
|
|
@ -341,7 +360,7 @@ def _quote_value_if_needed(value):
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
def generate_inventory_csv(count, num_locations, location_id_map, item_range=None):
|
def generate_inventory_csv(count, num_locations, location_id_map, item_range=None, available_images=None):
|
||||||
"""Generate a realistic inventory.csv with varied items using shared_data references and properties.
|
"""Generate a realistic inventory.csv with varied items using shared_data references and properties.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -349,6 +368,12 @@ def generate_inventory_csv(count, num_locations, location_id_map, item_range=Non
|
||||||
num_locations: Number of locations
|
num_locations: Number of locations
|
||||||
location_id_map: Map of location names to IDs
|
location_id_map: Map of location names to IDs
|
||||||
item_range: Tuple of (start_idx, end_idx) to partition the ITEMS_DATABASE, or None for all items
|
item_range: Tuple of (start_idx, end_idx) to partition the ITEMS_DATABASE, or None for all items
|
||||||
|
available_images: List of (data, mime_type) tuples to randomly attach to items, or None to skip
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Tuple of (inventory_csv_bytes, files) where files maps a zip arcname (matching
|
||||||
|
`toolshed.offlinedata.inventory_files()`'s 'files/<hash><ext>' convention) to file bytes,
|
||||||
|
for every image actually referenced by an item.
|
||||||
"""
|
"""
|
||||||
# Get location names from the map
|
# Get location names from the map
|
||||||
location_names = list(location_id_map.keys())
|
location_names = list(location_id_map.keys())
|
||||||
|
|
@ -365,6 +390,7 @@ def generate_inventory_csv(count, num_locations, location_id_map, item_range=Non
|
||||||
selected_items = random.sample(available_items, min(count, len(available_items)))
|
selected_items = random.sample(available_items, min(count, len(available_items)))
|
||||||
|
|
||||||
rows = []
|
rows = []
|
||||||
|
files = {}
|
||||||
for i, item_tuple in enumerate(selected_items, 1):
|
for i, item_tuple in enumerate(selected_items, 1):
|
||||||
# Handle both old format (6 elements) and new format (7 elements with properties)
|
# Handle both old format (6 elements) and new format (7 elements with properties)
|
||||||
if len(item_tuple) == 7:
|
if len(item_tuple) == 7:
|
||||||
|
|
@ -382,6 +408,16 @@ def generate_inventory_csv(count, num_locations, location_id_map, item_range=Non
|
||||||
properties_str = ', '.join(
|
properties_str = ', '.join(
|
||||||
f"{prop_handle}={_quote_value_if_needed(value)}" for prop_handle, value in properties_list)
|
f"{prop_handle}={_quote_value_if_needed(value)}" for prop_handle, value in properties_list)
|
||||||
|
|
||||||
|
# Attach a random image to most items, matching `toolshed.offlinedata.inventory_files()`'s
|
||||||
|
# 'files/<hash><ext>' arcname convention so the import side resolves it as the same file.
|
||||||
|
files_str = ''
|
||||||
|
if available_images and random.random() < IMAGE_ATTACHMENT_PROBABILITY:
|
||||||
|
data, mime_type = random.choice(available_images)
|
||||||
|
extension = mimetypes.guess_extension(mime_type) or ''
|
||||||
|
arcname = f'files/{sha256(data).hexdigest()}{extension}'
|
||||||
|
files[arcname] = data
|
||||||
|
files_str = arcname
|
||||||
|
|
||||||
rows.append({
|
rows.append({
|
||||||
'id': str(i),
|
'id': str(i),
|
||||||
'name': name,
|
'name': name,
|
||||||
|
|
@ -393,7 +429,7 @@ def generate_inventory_csv(count, num_locations, location_id_map, item_range=Non
|
||||||
'storage_location': location,
|
'storage_location': location,
|
||||||
'tags': ', '.join(tags_for_item),
|
'tags': ', '.join(tags_for_item),
|
||||||
'properties': properties_str,
|
'properties': properties_str,
|
||||||
'files': '',
|
'files': files_str,
|
||||||
'created_at': '2026-08-01T00:00:00+00:00',
|
'created_at': '2026-08-01T00:00:00+00:00',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -403,7 +439,7 @@ def generate_inventory_csv(count, num_locations, location_id_map, item_range=Non
|
||||||
writer = csv.DictWriter(output, fieldnames=fieldnames)
|
writer = csv.DictWriter(output, fieldnames=fieldnames)
|
||||||
writer.writeheader()
|
writer.writeheader()
|
||||||
writer.writerows(rows)
|
writer.writerows(rows)
|
||||||
return output.getvalue().encode('utf-8')
|
return output.getvalue().encode('utf-8'), files
|
||||||
|
|
||||||
|
|
||||||
def generate_sample_files():
|
def generate_sample_files():
|
||||||
|
|
@ -447,9 +483,14 @@ def generate_export_zip(username, domain, friend_username, friend_domain, friend
|
||||||
friends_csv = generate_friends_csv(friend_username, friend_domain, friend_public_key)
|
friends_csv = generate_friends_csv(friend_username, friend_domain, friend_public_key)
|
||||||
zip_file.writestr('friends.csv', friends_csv)
|
zip_file.writestr('friends.csv', friends_csv)
|
||||||
|
|
||||||
inventory_csv = generate_inventory_csv(num_items, num_locations, location_id_map, item_range)
|
available_images = load_available_images()
|
||||||
|
inventory_csv, item_files = generate_inventory_csv(
|
||||||
|
num_items, num_locations, location_id_map, item_range, available_images)
|
||||||
zip_file.writestr('inventory.csv', inventory_csv)
|
zip_file.writestr('inventory.csv', inventory_csv)
|
||||||
|
|
||||||
|
for arcname, content in item_files.items():
|
||||||
|
zip_file.writestr(arcname, content)
|
||||||
|
|
||||||
sample_files = generate_sample_files()
|
sample_files = generate_sample_files()
|
||||||
for arcname, content in sample_files.items():
|
for arcname, content in sample_files.items():
|
||||||
zip_file.writestr(arcname, content)
|
zip_file.writestr(arcname, content)
|
||||||
|
|
|
||||||
BIN
testdata/imgs/1-600x800.png
vendored
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
testdata/imgs/1-800x600.png
vendored
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
testdata/imgs/1.png
vendored
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
testdata/imgs/10-600x800.png
vendored
Normal file
|
After Width: | Height: | Size: 279 KiB |
BIN
testdata/imgs/10-800x600.png
vendored
Normal file
|
After Width: | Height: | Size: 361 KiB |
BIN
testdata/imgs/10.png
vendored
Normal file
|
After Width: | Height: | Size: 244 KiB |
BIN
testdata/imgs/2-600x800.png
vendored
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
testdata/imgs/2-800x600.png
vendored
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
testdata/imgs/2.png
vendored
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
testdata/imgs/3-600x800.png
vendored
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
testdata/imgs/3-800x600.png
vendored
Normal file
|
After Width: | Height: | Size: 145 KiB |
BIN
testdata/imgs/3.png
vendored
Normal file
|
After Width: | Height: | Size: 105 KiB |
BIN
testdata/imgs/4-600x800.png
vendored
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
testdata/imgs/4-800x600.png
vendored
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
testdata/imgs/4.png
vendored
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
testdata/imgs/5-600x800.png
vendored
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
testdata/imgs/5-800x600.png
vendored
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
testdata/imgs/5.png
vendored
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
testdata/imgs/6-600x800.png
vendored
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
testdata/imgs/6-800x600.png
vendored
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
testdata/imgs/6.png
vendored
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
testdata/imgs/7-600x800.png
vendored
Normal file
|
After Width: | Height: | Size: 265 KiB |
BIN
testdata/imgs/7-800x600.png
vendored
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
testdata/imgs/7.png
vendored
Normal file
|
After Width: | Height: | Size: 192 KiB |
BIN
testdata/imgs/8-600x800.png
vendored
Normal file
|
After Width: | Height: | Size: 201 KiB |
BIN
testdata/imgs/8-800x600.png
vendored
Normal file
|
After Width: | Height: | Size: 164 KiB |
BIN
testdata/imgs/8.png
vendored
Normal file
|
After Width: | Height: | Size: 153 KiB |
BIN
testdata/imgs/9-600x800.png
vendored
Normal file
|
After Width: | Height: | Size: 428 KiB |
BIN
testdata/imgs/9-800x600.png
vendored
Normal file
|
After Width: | Height: | Size: 522 KiB |
BIN
testdata/imgs/9.png
vendored
Normal file
|
After Width: | Height: | Size: 340 KiB |
2
testdata/user-a.key
vendored
|
|
@ -1 +1 @@
|
||||||
795e884532881938a1b03e37731443f4d1974327dafd5d508e0cb00cb0b161b6
|
982abc6680c1358c9d4d2436c96c00aebe36e9dd50fe184c12f1ac58fc7f8565
|
||||||
BIN
testdata/user-a.zip
vendored
2
testdata/user-b.key
vendored
|
|
@ -1 +1 @@
|
||||||
d011fedc3ba733baef6aa7550bbee47db66c2ad3dbfb0f6dcc14c984866df5eb
|
2e81e04093250c647cb2c364e39017be5aeac0303e138d6ded2e2cc7c3cdcdde
|
||||||