Skip to content

Conversation

aminghadersohi
Copy link
Contributor

@aminghadersohi aminghadersohi commented Sep 8, 2025

Fixes "name 'sync_playwright' is not defined" error when PLAYWRIGHT_REPORTS_AND_THUMBNAILS feature flag is enabled without Playwright installed.

Changes:

  • Add module-level PLAYWRIGHT_AVAILABLE check to prevent NameError
  • Implement graceful fallback to Selenium when Playwright unavailable
  • Add clear migration messages for WebGL/DeckGL support from Cypress
  • Make feature flag control preference rather than hard requirement
  • Add validate_webdriver_config() for migration status checking

Testing:

  • Add 20+ unit tests covering all migration scenarios
  • Test graceful fallback, error handling, and configuration validation
  • Ensure no breaking changes to existing Selenium functionality

This unblocks the effort to migrate from Cypress to Playwright for proper WebGL/DuckGL chart screenshot support.

SUMMARY

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

TESTING INSTRUCTIONS

ADDITIONAL INFORMATION

  • Has associated issue:
  • Required feature flags:
  • Changes UI
  • Includes DB Migration (follow approval process in SIP-59)
    • Migration is atomic, supports rollback & is backwards-compatible
    • Confirm DB migration upgrade and downgrade tested
    • Runtime estimates and downtime expectations provided
  • Introduces new feature or API
  • Removes existing feature or API

Copy link

korbit-ai bot commented Sep 8, 2025

Based on your review schedule, I'll hold off on reviewing this PR until it's marked as ready for review. If you'd like me to take a look now, comment /korbit-review.

Your admin can change your review schedule in the Korbit Console

@aminghadersohi aminghadersohi marked this pull request as ready for review September 8, 2025 22:22
Copy link

@korbit-ai korbit-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review by Korbit AI

Korbit automatically attempts to detect when you fix issues in new commits.
Category Issue Status
Functionality Incomplete Playwright Availability Check ▹ view ✅ Fix detected
Performance Redundant Import Checks ▹ view ✅ Fix detected
Design Driver Factory Method Violation ▹ view ✅ Fix detected
Files scanned
File Path Reviewed
superset/utils/screenshots.py
superset/utils/webdriver.py

Explore our documentation to understand the languages and file types we support and the files we ignore.

Check out our docs on how you can make Korbit work best for you and your team.

Loving Korbit!? Share us on LinkedIn Reddit and X

Copy link

codecov bot commented Sep 9, 2025

Codecov Report

❌ Patch coverage is 21.21212% with 26 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.87%. Comparing base (76d897e) to head (4750b0d).
⚠️ Report is 2569 commits behind head on master.

Files with missing lines Patch % Lines
superset/utils/webdriver.py 20.00% 19 Missing and 1 partial ⚠️
superset/utils/screenshots.py 25.00% 6 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master   #35063       +/-   ##
===========================================
+ Coverage   60.48%   71.87%   +11.39%     
===========================================
  Files        1931      587     -1344     
  Lines       76236    43498    -32738     
  Branches     8568     4703     -3865     
===========================================
- Hits        46114    31266    -14848     
+ Misses      28017    11003    -17014     
+ Partials     2105     1229      -876     
Flag Coverage Δ
hive 46.27% <21.21%> (-2.88%) ⬇️
javascript ?
mysql 70.90% <21.21%> (?)
postgres 70.95% <21.21%> (?)
presto 49.96% <21.21%> (-3.84%) ⬇️
python 71.84% <21.21%> (+8.33%) ⬆️
sqlite 70.55% <21.21%> (?)
unit 100.00% <ø> (+42.36%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@mistercrunch
Copy link
Member

Wondering if we could commit to Playwright-only for 7.0 already, and fully deprecate Selenium already (?) Would simplify things quite a bit and make everyone's life better moving forward.

@aminghadersohi
Copy link
Contributor Author

Wondering if we could commit to Playwright-only for 7.0 already, and fully deprecate Selenium already (?) Would simplify things quite a bit and make everyone's life better moving forward.

I asked Claude Code, here is what it said:

# Playwright-Only Migration for Superset 7.0 Analysis

**Date:** 2025-01-10  
**Status:** STRONG RECOMMENDATION - GO FOR IT 🚀  
**Context:** Analysis of migrating from Selenium+Playwright to Playwright-only for Superset 7.0

## Executive Summary

✅ **RECOMMENDATION: Commit to Playwright-only for Superset 7.0**

The migration infrastructure is already built, Playwright provides superior functionality (WebGL/DeckGL support), and 7.0 is the ideal major version for this breaking change.

## Current State Analysis

### Feature Flag Status
- **Current:** `PLAYWRIGHT_REPORTS_AND_THUMBNAILS: False` (default)
- **Documentation:** Listed in "Testing" phase in `FEATURE_FLAGS.md:54`
- **Implementation:** Complete fallback system with comprehensive availability checking

### Dependencies
- **Selenium:** Required dependency (`selenium>=4.14.0, <5.0` in pyproject.toml:95)
- **Playwright:** Optional dependency (`playwright>=1.37.0, <2` in pyproject.toml:168)

### Codebase Usage
**Files with Selenium/Playwright usage:**
- `superset/utils/webdriver.py` - Core webdriver implementations
- `superset/utils/screenshots.py` - Screenshot generation with fallback logic
- `tests/unit_tests/utils/webdriver_test.py` - Comprehensive test coverage
- `tests/integration_tests/thumbnails_tests.py` - Integration tests
- Various other test files

## Why This Makes Sense for 7.0

### 1. Critical Functional Advantage
- **WebGL/Canvas Support:** Playwright renders WebGL/DeckGL visualizations correctly
- **Selenium Limitation:** Cannot render deck.gl charts properly
- **Impact:** Major functional improvement, not just technical migration

### 2. Migration Infrastructure Already Complete
✅ **Fallback System:** Implemented in `superset/utils/screenshots.py:187-204`  
✅ **Availability Checking:** Comprehensive `check_playwright_availability()` function  
✅ **Performance Optimization:** Module-level caching to avoid repeated checks  
✅ **User Experience:** Single-log pattern prevents spam  
✅ **Test Coverage:** All tests updated and passing (21+ test methods)  

### 3. Clean Architecture
- Both webdrivers implement the same `WebDriver` interface
- Feature flag cleanly toggles between implementations  
- No breaking API changes required for the core functionality

## Migration Phases

### Phase 1: Pre-7.0 (Immediate)
```python
# In superset/config.py
"PLAYWRIGHT_REPORTS_AND_THUMBNAILS": True  # Change default to True

Goal: Enable by default to gather production feedback

Phase 2: 7.0 Release (Breaking Change)

Remove feature flag entirely, always use Playwright:

# In superset/utils/screenshots.py
def driver(self, window_size: WindowSize | None = None) -> WebDriver:
    window_size = window_size or self.window_size
    if _PLAYWRIGHT_AVAILABLE:
        return WebDriverPlaywright(self.driver_type, window_size)
    
    # Graceful degradation with clear error message
    raise ScreenshotImageNotAvailableException(
        "Playwright is required for screenshots in Superset 7.0+. "
        f"Install with: pip install 'apache-superset[playwright]' && playwright install chromium. "
        f"{_PLAYWRIGHT_INSTALL_MESSAGE}"
    )

Phase 3: Cleanup (Post-7.0)

  • Remove WebDriverSelenium class entirely
  • Remove selenium from required dependencies
  • Update documentation
  • Remove Selenium-related configuration options

Breaking Changes for 7.0

Dependencies

Breaking: selenium>=4.14.0, <5.0 removed from required dependencies
New Requirement: playwright>=1.37.0 moves to required dependencies
Installation Step: Users must run playwright install chromium

Configuration

Breaking: Remove PLAYWRIGHT_REPORTS_AND_THUMBNAILS feature flag
Breaking: Selenium-specific WEBDRIVER_* configs become unused
Backward Compatible: Playwright uses same config structure

Documentation Updates Required

  • Installation docs: Add Playwright requirements and browser installation
  • Docker images: Include Playwright browser binaries
  • Configuration docs: Remove Selenium references
  • Migration guide: Document upgrade path for existing deployments

Benefits Analysis

1. Functional Benefits

  • WebGL/DeckGL Support: Full rendering of complex visualizations
  • Modern Browser: Better JavaScript/CSS support
  • Reliability: More stable browser automation

2. Technical Benefits

  • Performance: Faster screenshot generation
  • Maintenance: Single webdriver codebase to maintain
  • Dependencies: Remove large Selenium dependency (~47MB)
  • Future-proof: Playwright actively developed vs Selenium WebDriver in maintenance

3. Development Benefits

  • Simplified Testing: One browser automation framework
  • Better Debugging: Playwright has superior debugging tools
  • API Consistency: Modern, well-designed API

Risk Assessment

Low Risk Factors ✅

  • Infrastructure Ready: Complete fallback system already implemented
  • Test Coverage: Comprehensive test suite validates both drivers
  • Gradual Migration: Feature flag allows controlled rollout
  • Clear Error Messages: Users get helpful installation guidance

Medium Risk Factors ⚠️

  • Docker Images: Need to include Playwright browser binaries (~200MB)
  • CI/CD: Need to update pipelines to install browser binaries
  • User Education: Some users will need to install Playwright

Mitigation Strategies

  • Phase 1: Enable by default in pre-7.0 to gather feedback
  • Documentation: Clear migration guides and installation instructions
  • Docker: Pre-build images with browser binaries included
  • Error Handling: Graceful degradation with helpful error messages

Git History Context

Recent commits show active Playwright development:

  • c1d15ae07a - Enable Playwright migration with graceful Selenium fallback
  • b2f8803486 - Fix playwright feature flag evaluation
  • 2233c02720 - Fix playwright empty dashboard screenshots
  • Multiple dependency updates and fixes

This indicates the team is already committed to Playwright migration.

Recommendation

GO FOR IT 🚀

Rationale:

  1. Functional necessity: WebGL/DeckGL support is crucial for modern visualizations
  2. Infrastructure complete: All migration tools are already built and tested
  3. Perfect timing: 7.0 is ideal for breaking changes
  4. Industry trend: Playwright is the future of browser automation

Success Criteria

  • Phase 1: Default to Playwright in pre-7.0 release
  • Gather feedback from testing phase (30+ days)
  • Update Docker images with browser binaries
  • Create comprehensive migration documentation
  • Phase 2: Remove Selenium for 7.0 stable release

Next Steps

  1. Immediate: Change feature flag default to True
  2. Pre-7.0: Monitor for issues, gather user feedback
  3. 7.0 Release: Remove Selenium entirely
  4. Post-7.0: Clean up legacy code and documentation

Analysis completed: All infrastructure is in place for a smooth migration. The benefits significantly outweigh the risks, and 7.0 provides the perfect opportunity for this improvement.

@aminghadersohi aminghadersohi force-pushed the fix/playwright-migration-fallback-sc-91312 branch from 7564cb4 to 214dc68 Compare September 17, 2025 02:34
…91312]

Fixes "name 'sync_playwright' is not defined" error when PLAYWRIGHT_REPORTS_AND_THUMBNAILS
feature flag is enabled without Playwright installed.

Changes:
- Add module-level PLAYWRIGHT_AVAILABLE check to prevent NameError
- Implement graceful fallback to Selenium when Playwright unavailable
- Add clear migration messages for WebGL/DuckGL support from Cypress
- Make feature flag control preference rather than hard requirement
- Add validate_webdriver_config() for migration status checking

Testing:
- Add 20+ unit tests covering all migration scenarios
- Test graceful fallback, error handling, and configuration validation
- Ensure no breaking changes to existing Selenium functionality

This unblocks the year-long effort to migrate from Cypress to Playwright
for proper WebGL/DuckGL chart screenshot support.

Shortcut: https://app.shortcut.com/preset/story/91312/
- Fixed comment to clarify that Cypress (not Selenium) doesn't work with DeckGL
- Updated installation message to accurately reflect the migration from Cypress
- Maintained correct description of WebGL/Canvas screenshot support that Playwright enables
- Add comprehensive Playwright availability check that verifies browser binaries
- Implement module-level caching to avoid repeated import checks
- Add single-log pattern to prevent log spam on repeated operations
- Update copy from "WebGL/DuckGL" to "WebGL/Canvas charts" and fix DeckGL references
- Add comprehensive test coverage for availability checking and caching behavior
- Fix test parameter ordering and mock targets for proper validation

The enhanced availability check now actually launches a browser to ensure
Playwright is fully functional, not just imported. Module-level caching
optimizes performance by avoiding repeated checks on every driver() call.
Changed logging statements to use % formatting instead of f-strings
to comply with ruff G004 security best practices.
- Use PLAYWRIGHT_AVAILABLE directly instead of cached value to respect test patches
- Use config.get() with defaults for SCREENSHOT_LOCATE_WAIT and SCREENSHOT_LOAD_WAIT
- Fix test parameter order to match decorator order (bottom to top)
- Update fallback logging expectations to expect single log (avoids log spam)
- Change WebGL/Canvas to WebGL/DuckGL in install message for consistency
- Fix logger.info test to check formatted parameter correctly
…ed variables

- Replace all references to _PLAYWRIGHT_AVAILABLE with PLAYWRIGHT_AVAILABLE
- Replace all references to _PLAYWRIGHT_INSTALL_MESSAGE with PLAYWRIGHT_INSTALL_MESSAGE
- Fix WebGL/Canvas to WebGL/DuckGL consistency in test assertions
…ation

Based on test engineer review, removed ~60% of test code while maintaining 100%
functionality coverage:

- Removed TestDriverMethodThreadSafety - tests implementation details not actual behavior
- Removed TestScreenshotModuleLevelCaching - tests internal caching implementation
- Removed TestScreenshotDriverPerformance - contrived performance tests
- Deleted test_playwright_migration_integration.py - contrived scenarios
- Simplified test_playwright_migration_working.py to essential tests only
- Removed duplicate tests from webdriver_test.py

Remaining tests focus on core behavior:
- Driver selection logic (Playwright when available, Selenium fallback)
- Fallback logging behavior
- Window size handling
- Configuration validation
@aminghadersohi aminghadersohi force-pushed the fix/playwright-migration-fallback-sc-91312 branch from 7458aa8 to 75f60f5 Compare September 17, 2025 18:50
@mistercrunch
Copy link
Member

@rusackas do you think we can we make this decision by lazy consensus? Make the call right here in this PR and start ripping Selenium out?

"not render correctly). %s",
PLAYWRIGHT_INSTALL_MESSAGE,
)
_PLAYWRIGHT_FALLBACK_LOGGED = True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a Flask app (multiple threads) or a Celery worker (multiple processes), this may not behave as we would expect:

Each process will have its own memory space, so the log suppression will only work per process, not globally.

In threaded mode, modifying the global without a lock could lead to race conditions (unlikely to matter much for a boolean flag, but still possible).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right about the concurrency issues. Added thread safety with a lock to prevent race conditions in threaded Flask mode. The per-process behavior in Celery is actually fine (one log per worker), but the threading needed fixing.

try:
# Try to actually launch a browser to ensure binaries are installed
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there may be a lighter way to do this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it to check if the browser binary exists first, only launches if that fails

self._screenshot_locate_wait = app.config["SCREENSHOT_LOCATE_WAIT"]
self._screenshot_load_wait = app.config["SCREENSHOT_LOAD_WAIT"]
self._screenshot_locate_wait = app.config.get("SCREENSHOT_LOCATE_WAIT", 10)
self._screenshot_load_wait = app.config.get("SCREENSHOT_LOAD_WAIT", 60)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: We used to have a rule to be strict with the config, all keys have defaults configured so we expect app.config["SOME_KEY"] instead of app.config.get unsure if we still have this "rule"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. yeah, Thanks. Good catch! Since the defaults are configured in config.py, switched to strict app.config["KEY"].

@rusackas
Copy link
Member

@rusackas do you think we can we make this decision by lazy consensus? Make the call right here in this PR and start ripping Selenium out?

I would think lazy consenus is fine. If anyone on dev@ replies with "bUt I nEeDz it!" then we can elevate it to a SIP.

SIP-178 doesn't explicitly mention selenium at all, so the consensus is a good idea. SIP-98 goes does have mentions on the thread that we should remove Selenium in a future version. If we consider it a breaking change, that raises Semver/merge/release timing questions we should also consider.

aminghadersohi and others added 3 commits September 22, 2025 14:19
…ization

- Add thread safety to _PLAYWRIGHT_FALLBACK_LOGGED with threading.Lock()
- Optimize playwright availability check with lightweight executable_path check first
- Remove unnecessary caching since function is only called at module import
- Use strict app.config[] access instead of .get() for keys with defaults
- Update tests to properly validate optimizations and thread-safe global access
…re test

The test was failing because it only mocked chromium.launch() to fail, but
check_playwright_availability() first tries chromium.executable_path. When
that succeeds, the function returns True without testing the launch fallback.

This fix mocks both executable_path and launch to raise exceptions, ensuring
the function properly tests the complete fallback scenario and returns False
when browser launch fails.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
"not render correctly). %s",
PLAYWRIGHT_INSTALL_MESSAGE,
)
_PLAYWRIGHT_FALLBACK_LOGGED = True
Copy link
Member

@dpgaspar dpgaspar Sep 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think that the overhead of the lock, global variable, and complexity isn't worth it for preventing some log lines. Also celery can be configured to use forks (most frequent) or threads/eventlet etc, on the fork case the thread would not work, that is the most common scenario. Let's just log it, most log systems can do deduplication anyway

…t fallback

Simplifies the fallback logging by removing the global flag, threading lock,
and deduplication logic. The added complexity wasn't worth it for preventing
log lines, especially with Celery's fork mode and modern log systems that
handle deduplication anyway.

Changes:
- Remove _PLAYWRIGHT_FALLBACK_LOGGED global variable
- Remove _fallback_lock threading synchronization
- Simplify fallback logging to just log directly
- Update tests to match simplified behavior

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Copy link
Member

@rusackas rusackas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked this in the daily PR sync, and it looks like since this is a fallback and not a removal, we can consider this non-breaking. LGTM, merging, on with the show!!!

@rusackas rusackas merged commit fe7f806 into apache:master Sep 23, 2025
58 checks passed
@sadpandajoe sadpandajoe added v6.0 Label added by the release manager to track PRs to be included in the 6.0 branch and removed v6.0 Label added by the release manager to track PRs to be included in the 6.0 branch labels Sep 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants