-
Notifications
You must be signed in to change notification settings - Fork 8
Create resource_extra_fields_export.py #47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 1 commit
ee01749
4b7cf84
ce58347
5c25878
a53d96e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,225 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| eLabFTW Resource Export Script | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -------------------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| This script connects to an eLabFTW instance via the API and exports all items | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from a specific category. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| For each item, the script: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Extracts the internal eLabFTW resource ID | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Extracts the item title | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Reads all configured extra fields (custom metadata fields) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Exports the data in a predefined column order | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The export is written to: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - A CSV file (for universal compatibility) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - An XLSX Excel file (with formatting, filters, and auto column width) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| The FIELD_ORDER list defines the exact column structure of the export. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| This ensures a stable and reproducible layout, which is important for: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Regulatory documentation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Data imports into other systems | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Standardized reporting | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import elabapi_python | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import json | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import csv | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from openpyxl import Workbook | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from openpyxl.styles import Font | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from openpyxl.utils import get_column_letter | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ######################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # CONFIG # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ######################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Base URL of your eLabFTW API (must include /api/v2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| API_HOST_URL = 'https://YOUR-URL/api/v2' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Personal API key generated in eLabFTW | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| API_KEY = 'YOUR API Key' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Category ID from which items should be exported | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| CATEGORY_ID = 123456 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Output filenames | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| OUTPUT_FILE = "export.csv" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| OUTPUT_XLSX = "export.xlsx" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ######################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # API CONFIGURATION # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ######################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Create configuration object for the eLabFTW API | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| configuration = elabapi_python.Configuration() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| configuration.api_key['api_key'] = API_KEY | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| configuration.api_key_prefix['api_key'] = 'Authorization' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| configuration.host = API_HOST_URL | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| configuration.debug = False | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Set to True if valid SSL certificates are used | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| configuration.verify_ssl = True | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Create API client | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| api_client = elabapi_python.ApiClient(configuration) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Set authorization header manually (required for authentication) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| api_client.set_default_header( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| header_name='Authorization', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| header_value=API_KEY | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+53
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
cfg="$(fd '^configuration\.py$' | head -n1)"
example_cfg="examples/client.py"
test -n "$cfg"
echo "Inspecting generated auth semantics in: $cfg"
sed -n '/def get_api_key_with_prefix/,/def /p' "$cfg"
echo
echo "Inspecting example auth setup in: $example_cfg"
rg -n -C2 'set_default_header|api_key_prefix|api_key\[' "$example_cfg"Repository: elabftw/elabapi-python Length of output: 48 🏁 Script executed: # Find key files and understand repository structure
fd -t f -e py '(client\.py|configuration\.py|resource_extra)' | head -20Repository: elabftw/elabapi-python Length of output: 125 🏁 Script executed: # List top-level structure
ls -laRepository: elabftw/elabapi-python Length of output: 763 🏁 Script executed: # Search for elabapi_python module location and Configuration class
rg -l "class Configuration" --max-count=5Repository: elabftw/elabapi-python Length of output: 48 🏁 Script executed: # Examine both example files to understand auth setup
echo "=== examples/client.py ==="
cat -n examples/client.py
echo -e "\n=== examples/resource_extra_fields_export.py (first 80 lines) ==="
head -80 examples/resource_extra_fields_export.py | cat -nRepository: elabftw/elabapi-python Length of output: 5742 🏁 Script executed: # Check imports and find elabapi_python
rg "^import|^from" examples/ | head -20Repository: elabftw/elabapi-python Length of output: 1135 🏁 Script executed: # Search for other uses of api_key_prefix in the codebase to understand the pattern
rg "api_key_prefix" --max-count=10Repository: elabftw/elabapi-python Length of output: 164 🏁 Script executed: # Look at how other examples handle authentication
rg -l "Configuration\|ApiClient" examples/*.py | head -10Repository: elabftw/elabapi-python Length of output: 48 🏁 Script executed: # Check if there are any other authentication patterns in examples
fd -t f -e py examples/ | xargs rg -l "set_default_header|api_key" | head -10Repository: elabftw/elabapi-python Length of output: 494 🏁 Script executed: # Look for OpenAPI generated client documentation or patterns
fd -t f -e py -e md | xargs rg -l "get_api_key_with_prefix|prepend_prefix" 2>/dev/null | head -10Repository: elabftw/elabapi-python Length of output: 48 🏁 Script executed: # Check all examples for their authentication patterns
echo "=== Checking all example files for auth setup ==="
for file in examples/*.py; do
echo -e "\n--- $file ---"
rg -n "Configuration\|set_default_header|api_key\[|api_key_prefix" "$file" | head -15
doneRepository: elabftw/elabapi-python Length of output: 1334 🏁 Script executed: # Let's look at the full context of both authentication setups in resource_extra_fields_export.py
echo "=== Full resource_extra_fields_export.py auth section ==="
sed -n '50,75p' examples/resource_extra_fields_export.py | cat -nRepository: elabftw/elabapi-python Length of output: 1008 🏁 Script executed: # Check README or any documentation about authentication
cat README.md | head -100Repository: elabftw/elabapi-python Length of output: 3790 🏁 Script executed: # Search for requirements or setup.py to understand elabapi_python version/source
fd -t f '(requirements|setup|pyproject)' | xargs cat 2>/dev/null | head -50Repository: elabftw/elabapi-python Length of output: 48 🏁 Script executed: # Let's check if there's any documentation in comments about how api_key works
rg -i "api.?key|authorization" --type md | head -20Repository: elabftw/elabapi-python Length of output: 212 🏁 Script executed: # Let's check all examples to see if any others use api_key/api_key_prefix pattern
rg -c "api_key\[|api_key_prefix" examples/*.pyRepository: elabftw/elabapi-python Length of output: 108 🏁 Script executed: # Check if examples/00-getting-started.py (first example) shows auth setup
sed -n '1,80p' examples/00-getting-started.py | cat -nRepository: elabftw/elabapi-python Length of output: 4970 Consolidate authentication configuration to the standard pattern. Lines 55–56 employ Suggested change # Create configuration object for the eLabFTW API
configuration = elabapi_python.Configuration()
-configuration.api_key['api_key'] = API_KEY
-configuration.api_key_prefix['api_key'] = 'Authorization'
configuration.host = API_HOST_URL📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Load Items API endpoint | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| itemsApi = elabapi_python.ItemsApi(api_client) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ############################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # DEFINE EXPORT ORDER HERE # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ############################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FIELD_ORDER defines the exact column order of metadata fields | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| in the exported files. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Why is this necessary? | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| eLabFTW stores extra fields dynamically in JSON format. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Without explicitly defining the order: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Column positions could change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Fields might appear in random order | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Downstream processing (e.g., Excel templates, validation scripts) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| could break | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| By defining FIELD_ORDER: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - The export structure remains stable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Reports remain consistent | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Future modifications can be controlled centrally | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| You can modify this list to match your own category setup. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Simply replace the example field names below with the exact | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| field titles used in your system. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FIELD_ORDER = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Record Number", # e.g. internal running number | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Project ID", # e.g. reference or file number | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Organism Name", # e.g. E. coli strain | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Gene / Target", # e.g. transgene or modification | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Storage Location", # e.g. freezer or storage unit | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Experiment Purpose", # short description of use | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Donor Organism", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Recipient Organism", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Vector", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Resistance Marker", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Sequence Information", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Risk Assessment Reference", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Created By", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Created At", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Comments" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # -------------------------------------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # ----------- SCRIPT STARTS HERE ------------------ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # -------------------------------------------------- | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print("Starting export...") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Retrieve all items from the specified category | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| items = itemsApi.read_items(cat=CATEGORY_ID) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print(f"Items found: {len(items)}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+125
to
+132
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Engage defensive protocols: the API call lacks error handling. The 🛡️ Proposed fix: Add main guard and API error handling+def main():
+ print("Starting export...")
-print("Starting export...")
+ # Retrieve all items from the specified category
+ try:
+ items = itemsApi.read_items(cat=CATEGORY_ID)
+ except elabapi_python.ApiException as e:
+ print(f"API request failed: {e}")
+ return
-# Retrieve all items from the specified category
-items = itemsApi.read_items(cat=CATEGORY_ID)
+ print(f"Items found: {len(items)}")
+ # ... rest of logic ...
-print(f"Items found: {len(items)}")
+if __name__ == "__main__":
+ main()🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rows = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Iterate through all retrieved items | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for item in items: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| row = {} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Internal eLabFTW resource ID (primary identifier) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| row["Ressourcen ID"] = item.id or "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Item title | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| row["Titel"] = item.title or "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Metadata is stored as JSON string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| metadata_raw = item.metadata | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if metadata_raw: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| metadata = json.loads(metadata_raw) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extra_fields = metadata.get("extra_fields", {}) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| extra_fields = {} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Extract all fields defined in FIELD_ORDER | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for field in FIELD_ORDER: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if field in extra_fields: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value = extra_fields[field].get("value", "") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value = "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
ELN-uzun marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Convert list-type fields into comma-separated string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if isinstance(value, list): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value = ", ".join(value) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| row[field] = value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+185
to
+189
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure type safety before joining list values. If 🛡️ Proposed fix: Convert elements to strings # Convert list-type fields into comma-separated string
if isinstance(value, list):
- value = ", ".join(value)
+ value = ", ".join(str(v) for v in value)🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rows.append(row) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ######################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # WRITE CSV # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ######################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Define final column structure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| csv_columns = ["Ressourcen ID", "Titel"] + FIELD_ORDER | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Write CSV file (UTF-8 encoding for special characters) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with open(OUTPUT_FILE, "w", newline="", encoding="utf-8") as f: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writer = csv.DictWriter(f, fieldnames=csv_columns) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writer.writeheader() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| writer.writerows(rows) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print("CSV export finished.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ######################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # WRITE XLSX # | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ######################### | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wb = Workbook() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ws = wb.active | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ws.title = "Export" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Write header row | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ws.append(csv_columns) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Make header row bold | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for cell in ws[1]: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cell.font = Font(bold=True) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Write data rows | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for row in rows: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ws.append([row[col] for col in csv_columns]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Enable auto-filter for the entire sheet | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ws.auto_filter.ref = ws.dimensions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Automatically adjust column width based on content length | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for col in ws.columns: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| max_length = 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| column = col[0].column | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| column_letter = get_column_letter(column) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for cell in col: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if cell.value: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| max_length = max(max_length, len(str(cell.value))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| except: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pass | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| adjusted_width = max_length + 2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ws.column_dimensions[column_letter].width = adjusted_width | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+236
to
+244
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A bare This silently swallows all exceptions, making debugging nearly impossible when anomalies occur. We must be specific about what we catch, or at minimum, log the encounter. 🛡️ Proposed fix: Handle exceptions properly for cell in col:
try:
if cell.value:
max_length = max(max_length, len(str(cell.value)))
- except:
- pass
+ except (TypeError, AttributeError):
+ continue📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff (0.15.2)[error] 216-216: Do not use bare (E722) [error] 216-217: (S110) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Save Excel file | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| wb.save(OUTPUT_XLSX) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print("XLSX export finished successfully.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.