A Flet-based single-page UI application designed to perform various Alma-Digital bibliographic record editing functions using the Alma API.
🚕 CABB (Crunch Alma Bibs in Bulk) provides a user-friendly interface for cleaning and maintaining Alma bibliographic records, supporting both single-record operations and batch processing via Alma Sets.
The application supports both single record and batch processing (via Alma Sets):
- Single Record Mode - Enter an MMS ID to process one bibliographic record at a time
- Batch Processing Mode - Enter a Set ID to load all members and process them in bulk
- Fetch and Display XML - Preview the full XML structure of a bibliographic record
- Clear dc:relation Collections Fields - Removes all dc:relation fields having a value that begins with "alma:01GCL_INST/bibs/collections/"
- Supports batch processing across entire sets
- Provides progress tracking (X of Y processed)
- Placeholder Function 3 - Reserved for future Alma-Digital record editing functionality
- Placeholder Function 4 - Reserved for future Alma-Digital record editing functionality
- Placeholder Function 5 - Reserved for future Alma-Digital record editing functionality
- Load any Alma set by Set ID
- Preview set members (first 20 displayed)
- Apply editing functions to all members in the set
- Real-time progress tracking during batch operations
- Success/failure summary after batch completion
- Flet - Modern Python framework for building user interfaces
- requests - HTTP library for direct Alma API calls
- python-dotenv - Environment variable management
- Python 3.x - Programming language
CABB/
├── app.py # Main Flet application
├── requirements.txt # Python dependencies
├── run.sh # Quick launch script
├── .env.example # Environment variables template
├── .gitignore # Git ignore rules
└── README.md # This file
- Python 3.8 or higher
- pip (Python package installer)
- An Alma API key with appropriate permissions
-
Clone the repository
git clone https://github.com/Digital-Grinnell/CABB.git cd CABB -
Configure environment variables
Copy the example environment file and edit it with your Alma API credentials:
cp .env.example .env
Edit
.envand add your Alma API credentials:ALMA_API_KEY=your_actual_api_key_here ALMA_API_REGION=AmericaValid ALMA_API_REGION values:
America(default - North America)EuropeAsia PacificCanadaChina
Required API Key Permissions:
Your Alma API key must have the following permissions enabled:
- Bibs - Read/Write (for reading and updating bibliographic records)
- Configuration - Read-only (for accessing Sets and retrieving set members)
To configure your API key in Alma:
- Go to Alma > Admin > General > API Key Management
- Create or edit your API key
- Ensure "Bibs" has Read/Write permissions
- Ensure "Configuration" has Read permissions
- Save the API key
-
Run the application
Use the provided quick launch script:
./run.sh
The script will:
- Create a virtual environment (
.venv) if it doesn't exist - Install all required dependencies
- Launch the Flet application
- Create a virtual environment (
If you prefer to set up manually:
# Create virtual environment
python3 -m venv .venv
# Activate virtual environment
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Run the application
python app.py-
Launch the application using
./run.sh -
Connect to Alma API by clicking the "Connect to Alma API" button
-
Enter an MMS ID in the "Single Record" input field
-
Select an editing function from the available buttons:
- "Fetch and Display XML" to preview the record
- "Clear dc:relation Collections Fields" to remove collection references
- Additional functions as implemented
-
Enter a Set ID in the "Batch Processing (Set)" input field
- Example:
7071087320004641
- Example:
-
Click "Load Set Members" to fetch all bibliographic records in the set
- The app will display the set name and member count
- First 20 members are shown for preview
-
Select an editing function to apply to all records in the set
- Progress will be shown as "Processing X/Y: [MMS_ID]"
- A summary of successes/failures is displayed upon completion
-
Click "Clear Set" when done to reset for single record or a different set
- The Log Output window shows real-time operation details
- Full logs are saved to timestamped files:
cabb_YYYYMMDD_HHMMSS.log - Click the copy icon next to "Status" to copy status messages to clipboard
-
Connect to Alma API
- Click the "Connect to Alma API" button
- The status will show if the connection is successful
-
Enter a record MMS ID
- Input the bibliographic record's MMS ID in the text field
-
Execute editing functions
- Click any of the five function buttons to perform operations on the specified record
- The status area will display the result of each operation
- Created project structure with virtual environment support
- Implemented Flet-based single-page UI
- Integrated almapipy library for Alma API connectivity
- Created five function placeholders with corresponding UI buttons
- Implemented placeholder for clearing dc:relation fields
- Pattern matching:
alma:01GCL_INST/bibs/collections/* - Uses XML parsing for record manipulation
- Note: Full implementation requires actual XML manipulation logic
- Single-page design: All functionality on one page for simplicity
- Class-based architecture:
AlmaBibEditorclass encapsulates all business logic - Environment variables: API keys stored securely in
.envfile - Virtual environment: Isolated Python environment for dependency management
The main application file containing:
AlmaBibEditorclass: Handles Alma API interactionsmain(page)function: Builds the Flet UI- Event handlers for each button
- Status update mechanisms
initialize_alma_connection()
- Establishes connection to Alma API using almapipy
- Validates API key from environment variables
- Returns success status and message
clear_dc_relation_collections(mms_id)
- Main implementation for Function 1
- Fetches bibliographic record by MMS ID
- Parses XML to find and remove matching dc:relation fields
- Updates the record via Alma API
Placeholder Functions 2-5
- Reserved for future functionality
- Follow same pattern: accept MMS ID, return status tuple
- Ready for implementation of additional editing features
To implement additional editing functions:
- Add a method to the
AlmaBibEditorclass - Create an event handler in the
main()function - Add a button to the UI
- Update the README with the new functionality
Example:
def new_editing_function(self, mms_id: str) -> tuple[bool, str]:
"""Description of new function"""
# Implementation here
return True, "Success message"See requirements.txt for complete list:
flet>=0.21.0- UI frameworkalmapipy>=0.4.0- Alma API wrapperpython-dotenv>=1.0.0- Environment variable management
- Never commit your
.envfile or API keys to version control - The
.envfile is included in.gitignoreto prevent accidental commits - Use API keys with minimal required permissions
- Regularly rotate your API keys
This application uses a direct XML approach for updating Alma bibliographic records. Understanding how to properly handle XML namespaces is critical for successful API interactions.
Alma's API has very strict requirements for XML structure, particularly around namespaces:
-
The
<bib>root element must NOT have a default namespace declaration- ❌ Rejected:
<bib xmlns="http://alma.exlibrisgroup.com/dc/01GCL_INST"> - ✅ Accepted:
<bib xmlns:dc="..." xmlns:dcterms="...">
- ❌ Rejected:
-
Alma-specific elements (
<record>,<dginfo>, etc.) must be unprefixed- ❌ Rejected:
<ns0:record>or<alma:record> - ✅ Accepted:
<record>
- ❌ Rejected:
-
Dublin Core elements must use proper namespace prefixes
- ✅ Required:
<dc:identifier>,<dc:title>,<dcterms:created>
- ✅ Required:
The application uses a three-step approach to handle namespaces correctly:
namespaces_to_register = {
'dc': 'http://purl.org/dc/elements/1.1/',
'dcterms': 'http://purl.org/dc/terms/',
'xsi': 'http://www.w3.org/2001/XMLSchema-instance'
}
for prefix, uri in namespaces_to_register.items():
ET.register_namespace(prefix, uri)Note: We do NOT register the Alma default namespace (http://alma.exlibrisgroup.com/dc/01GCL_INST) because doing so would add an unwanted xmlns attribute to the <bib> element.
root = ET.fromstring(response.text)
# Find and modify elements using namespace-aware XPath
relations = root.findall('.//dc:relation', {'dc': 'http://purl.org/dc/elements/1.1/'})xml_bytes = ET.tostring(root, encoding='utf-8')
xml_str = xml_bytes.decode('utf-8')
# Remove auto-generated ns0: prefixes from Alma elements
xml_str = xml_str.replace('ns0:', '').replace(':ns0', '')
# Remove the xmlns declaration that Alma rejects
xml_str = xml_str.replace(' xmlns="http://alma.exlibrisgroup.com/dc/01GCL_INST"', '')
xml_bytes = xml_str.encode('utf-8')When Python's ElementTree encounters elements in a namespace that isn't registered, it automatically generates a namespace prefix (like ns0:). Our post-processing step:
- Removes the
ns0:prefix - Converting<ns0:record>to<record> - Removes the generated namespace declaration - Eliminating
xmlns="http://alma.exlibrisgroup.com/dc/01GCL_INST"from the<bib>element - Preserves registered namespace prefixes - Keeping
dc:,dcterms:, andxsi:intact
What Alma Expects:
<bib xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/">
<mms_id>991011687640104641</mms_id>
<title>Example Title</title>
<record>
<dginfo>Example dginfo</dginfo>
<dc:identifier>dg_123456</dc:identifier>
<dc:title>Example Title</dc:title>
</record>
</bib>What Would Be Rejected:
<!-- ❌ Default namespace on <bib> -->
<bib xmlns="http://alma.exlibrisgroup.com/dc/01GCL_INST">
...
</bib>
<!-- ❌ Namespace prefix on Alma elements -->
<bib>
<ns0:record xmlns:ns0="http://alma.exlibrisgroup.com/dc/01GCL_INST">
<ns0:dginfo>Example</ns0:dginfo>
</ns0:record>
</bib>- Always use
validate=truein PUT requests - Alma will tell you immediately if the XML structure is wrong - Log the XML being sent - Essential for debugging namespace issues
- Don't try to register the default Alma namespace - It causes more problems than it solves
- Post-process the XML string - Simple string replacement is more reliable than complex namespace handling
- Test with Function 1 first - Fetch and view the XML to understand the expected structure
app.py- Contains the implementation (seeclear_dc_relation_collections()method)ALMA_API_UPDATE_NOTES.md- Historical documentation of what approaches didn't work
- Ensure you've created a
.envfile with validALMA_API_KEY - Check that the
.envfile is in the project root directory
Error message: UNAUTHORIZED: API-key not defined or not configured to allow this API
This error occurs when trying to load a set without proper API key permissions.
Solution:
- Log into Alma as an administrator
- Navigate to: Admin > General > API Key Management
- Find and edit your API key
- Under API Permissions, ensure these are enabled:
- Bibs: Read/Write ✓
- Configuration: Read ✓ (this is required for Sets API)
- Click Save
- Wait a few minutes for the changes to propagate
- Restart the application and try again
Note: If you don't have admin access, contact your Alma administrator to add Configuration permissions to your API key.
- Verify your API key is valid
- Check that
ALMA_API_REGIONis set to one of:America,Europe,Asia Pacific,Canada, orChina - Ensure your API key has appropriate permissions
- Confirm the region matches your institution's Alma location
Error: unexpected element (uri:"...", local:"bib"). Expected elements are <{}bib>
- This means the
<bib>element has a namespace declaration it shouldn't have - Solution is already implemented in the code's string replacement step
Error: Field ns0:dginfo is invalid
- This means Alma elements have an unwanted namespace prefix
- Solution is already implemented in the code's
ns0:removal step
Error: Field dc:identifier is invalid
- Check that Dublin Core namespaces are properly registered
- Verify the namespace URIs are exactly correct
- Delete the
.venvfolder and run./run.shagain - Ensure Python 3.8+ is installed:
python3 --version
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
[Specify license here]
For questions or support, please open an issue on GitHub.
- Built with Flet
- Developed for Digital Grinnell
- Alma API integration using direct REST calls