Repository: microsoft/playwright-python

Issue:
Inspect fails to retrieve module inside frozen app
# Description of the issue

when freezing playwright with [pyinstaller](https://github.com/pyinstaller/pyinstaller) the assertion in [`get_file_dirname`](https://github.com/microsoft/playwright-python/blob/master/playwright/path_utils.py#L19-L24) fails

```
  File "main.py", line 6, in <module>
    with sync_playwright() as p:
  File "playwright/__init__.py", line 34, in sync_playwright
  File "playwright/main.py", line 81, in __init__
  File "playwright/main.py", line 76, in run_driver
  File "asyncio/base_events.py", line 587, in run_until_complete
  File "playwright/main.py", line 44, in run_driver_async
  File "playwright/main.py", line 36, in compute_driver_executable
  File "playwright/path_utils.py", line 23, in get_file_dirname
AssertionError
```

The reason is that the inspect module fails to find the module on the following lines inside [`get_file_dirname`](https://github.com/microsoft/playwright-python/blob/master/playwright/path_utils.py#L19-L24)

```python
frame = inspect.stack()[1]
module = inspect.getmodule(frame[0])
```

# Context information

* version of python: 3.7.9
* version of pyinstaller: 4.1
* version of playwright-python: Version 0.162.1
* platform: GNU/Linux (Ubuntu 18.04 LTS)

# Reproducing the bug

install packages

    $ pip install playwright pyinstaller

install the browsers inside playwright

    $ PLAYWRIGHT_BROWSERS_PATH=0 python -m playwright install

create `main.py`

```python
# main.py
import sys
from pathlib import Path
from playwright import sync_playwright

with sync_playwright() as p:
    for browser_type in [p.chromium]:
        browser = browser_type.launch(
            headless=False,
            executablePath=Path(sys.modules['playwright'].__file__).parent / 'driver' / '.local-browsers' / 'chromium-827102' / 'chrome-linux' / 'chrome')
        page = browser.newPage()
        page.goto('http://whatsmyuseragent.org/')
        page.screenshot(path=f'example-{browser_type.name}.png')
        browser.close()
```

freeze into single binary file with pyinstaller

    $ pyinstaller -F main.py --add-data /path/to/lib/python3.7/site-packages/playwright/driver:playwright/driver

execute the binary file

```
$ ./dist/main 
Traceback (most recent call last):
  File "main.py", line 6, in <module>
    with sync_playwright() as p:
  File "playwright/__init__.py", line 34, in sync_playwright
  File "playwright/main.py", line 81, in __init__
  File "playwright/main.py", line 76, in run_driver
  File "asyncio/base_events.py", line 587, in run_until_complete
  File "playwright/main.py", line 44, in run_driver_async
  File "playwright/main.py", line 36, in compute_driver_executable
  File "playwright/path_utils.py", line 23, in get_file_dirname
AssertionError
```

# Proposed solution

The problem can be fixed by changing  [`get_file_dirname`](https://github.com/microsoft/playwright-python/blob/master/playwright/path_utils.py#L19-L24) with

```python
import inspect
import sys
from pathlib import Path

def get_file_dirname() -> Path:
    """Returns the callee (`__file__`) directory name"""
    module_name = inspect.currentframe().f_back.f_globals["__name__"]
    module = sys.modules[module_name]
    assert module
    return Path(module.__file__).parent.absolute()
```


Discussion:

Resolving patch:
diff --git a/playwright/main.py b/playwright/main.py
--- a/playwright/main.py
+++ b/playwright/main.py
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 import asyncio
+import inspect
 import os
 import subprocess
 import sys
@@ -21,18 +22,18 @@
 
 from greenlet import greenlet
 
+import playwright
 from playwright.async_api import Playwright as AsyncPlaywright
 from playwright.connection import Connection
 from playwright.helper import Error
 from playwright.object_factory import create_remote_object
-from playwright.path_utils import get_file_dirname
 from playwright.playwright import Playwright
 from playwright.sync_api import Playwright as SyncPlaywright
 from playwright.sync_base import dispatcher_fiber, set_dispatcher_fiber
 
 
 def compute_driver_executable() -> Path:
-    package_path = get_file_dirname()
+    package_path = Path(inspect.getfile(playwright)).parent
     platform = sys.platform
     if platform == "win32":
         return package_path / "driver" / "playwright-cli.exe"


Test patch: