# path-handling > Use when resolving Steam library paths, constructing compatdata paths, or working with secondary Steam libraries. Covers path construction, validation order, and common pitfalls. - Author: Frank Wang - Repository: ifrankwang/steam-trainer-launcher - Version: 20260125200951 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-06 - Source: https://github.com/ifrankwang/steam-trainer-launcher - Web: https://mule.run/skillshub/@@ifrankwang/steam-trainer-launcher~path-handling:20260125200951 --- --- name: path-handling description: Use when resolving Steam library paths, constructing compatdata paths, or working with secondary Steam libraries. Covers path construction, validation order, and common pitfalls. license: GPL 3.0 compatibility: opencode metadata: audience: developers workflow: path-handling --- ## Steam Library Path Resolution **IMPORTANT**: When resolving paths for games in secondary Steam libraries: | Path Component | Correct | Incorrect | |---------------|---------|-----------| | Base directory | `lib` (library root) | `apps_path` (if different) | | compatdata path | `lib / "steamapps" / "compatdata"` | `lib / "compatdata"` | **Example**: ```python # For a game in secondary library: # Library: /run/media/user/External/SteamLibrary/ # Apps path: /run/media/user/External/SteamLibrary/steamapps/ # CORRECT: Use apps_path for steamapps-relative paths compat_data_path = apps_path / "compatdata" / str(app_id) # Result: /run/media/user/External/SteamLibrary/steamapps/compatdata/123456 # WRONG: Use lib directly compat_data_path = lib / "compatdata" / str(app_id) # Result: /run/media/user/External/SteamLibrary/compatdata/123456 (MISSING steamapps!) ``` ## Validation Order 1. Check if path is absolute first 2. If relative, resolve relative to correct base directory 3. Validate resolved path is safe (not outside allowed directories) 4. Verify path exists for file operations ## Common Pitfalls ### 1. Testing Single-Library Only **Problem**: Tests pass but real multi-library environment fails. **Solution**: Always test with primary + secondary library scenarios. ### 2. Path Construction Errors **Problem**: Using `lib` instead of `apps_path` for steamapps-relative paths. **Solution**: Explicitly use `apps_path = lib / "steamapps"` for relative path resolution. ### 3. Assuming Relative Order **Problem**: Code assumes `apps_path == lib / "steamapps"` when they might differ. **Solution**: Always compute `apps_path = lib / "steamapps"` explicitly, don't assume. ### 4. Test Assertion Gaps **Problem**: Tests check `is_absolute()` and `exists()` but not path structure. **Solution**: Verify exact path structure: ```python # Check BOTH assert path.is_absolute() assert "steamapps" in str(path) # Verify structure ``` ### 5. Blocking Operations in GUI **Problem**: Using `time.sleep()` in main thread blocks UI. **Solution**: Use async patterns: ```python # BAD: Blocks GUI for 0.5 seconds import time time.sleep(0.5) # GOOD: Non-blocking with background thread threading.Thread(target=check_with_timeout, daemon=True).start() # GOOD: Non-blocking with select select.select([stdout], [], [], timeout_seconds) ``` ### 6. Symlink TOCTOU Race Conditions **Problem**: Time-of-check to time-of-use vulnerability. **Solution**: Validate target before creating, use atomic operations. ### 7. Hardcoded Proton Version Parsing **Problem**: Fragile version string parsing breaks on format changes. **Solution**: Use configuration file or flexible matching. ## Best Practices Summary - ✅ Write tests for edge cases (empty, error, multi-library) - ✅ Validate paths from external sources - ✅ Use context managers for resource cleanup - ✅ Add docstrings for public APIs - ✅ Use specific exception types - ✅ Log errors with meaningful messages - ✅ Verify path structure, not just existence - ✅ Test with real-world scenarios (multiple libraries, removable media)