Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Tomcat42
python-browsers
browsers-0.5.2.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File browsers-0.5.2.obscpio of Package python-browsers
07070100000000000081A4000000000000000000000001639CA5620000034E000000000000000000000000000000000000002300000000browsers-0.5.2/.all-contributorsrc{ "projectName": "browsers", "projectOwner": "roniemartinez", "repoType": "github", "repoHost": "https://github.com", "files": [ "README.md" ], "imageSize": 100, "commit": false, "contributors": [ { "login": "roniemartinez", "name": "Ronie Martinez", "avatar_url": "https://avatars.githubusercontent.com/u/2573537?v=4", "profile": "https://ron.sh/", "contributions": [ "code", "ideas", "doc", "maintenance" ] }, { "login": "SergeyPirogov", "name": "Sergey Pirogov", "avatar_url": "https://avatars.githubusercontent.com/u/4622856?v=4", "profile": "https://t.me/automation_remarks_ua", "contributions": [ "bug" ] } ], "contributorsPerLine": 7, "skipCi": false, "commitConvention": "none" } 07070100000001000041ED000000000000000000000001639CA56200000000000000000000000000000000000000000000001700000000browsers-0.5.2/.github07070100000002000081A4000000000000000000000001639CA562000001F5000000000000000000000000000000000000002600000000browsers-0.5.2/.github/dependabot.yml# To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: "pip" # See documentation for possible values directory: "/" # Location of package manifests schedule: interval: "daily" 07070100000003000041ED000000000000000000000001639CA56200000000000000000000000000000000000000000000002100000000browsers-0.5.2/.github/workflows07070100000004000081A4000000000000000000000001639CA56200000921000000000000000000000000000000000000003500000000browsers-0.5.2/.github/workflows/codeql-analysis.yml# For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL" on: push: branches: [ master ] pull_request: # The branches below must be a subset of the branches above branches: [ master ] schedule: - cron: '45 8 * * 4' jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'python' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Learn more about CodeQL language support at https://git.io/codeql-language-support steps: - name: Checkout repository uses: actions/checkout@v2 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v1 # âšī¸ Command-line programs to run using the OS shell. # đ https://git.io/JvXDl # âī¸ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 07070100000005000081A4000000000000000000000001639CA562000002EF000000000000000000000000000000000000002A00000000browsers-0.5.2/.github/workflows/pypi.yml# This workflow will publish to PyPI # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Publish to PyPI on: release: types: - published jobs: pypi: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 with: python-version: '3.x' - name: Install dependencies run: | pip3 install -U pip setuptools poetry - name: Build package run: | poetry config http-basic.pypi ${{ secrets.PYPI_USER }} ${{ secrets.PYPI_PASS }} poetry build - name: Publish package run: | poetry publish 07070100000006000081A4000000000000000000000001639CA56200000912000000000000000000000000000000000000002C00000000browsers-0.5.2/.github/workflows/python.yml# This workflow will install Python dependencies, run tests and lint with a variety of Python versions # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Python on: push: branches: - master pull_request: branches: - master workflow_dispatch: concurrency: group: ${{ github.ref }} cancel-in-progress: true jobs: test: runs-on: ${{ matrix.os }} strategy: matrix: os: [ ubuntu-latest, macos-latest, windows-latest ] python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11' ] include: - os: ubuntu-latest pip-cache: ~/.cache/pip poetry-cache: ~/.cache/pypoetry - os: macos-latest pip-cache: ~/Library/Caches/pip poetry-cache: ~/Library/Caches/pypoetry - os: windows-latest pip-cache: ~\AppData\Local\pip\Cache poetry-cache: ~\AppData\Local\pypoetry\Cache steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - uses: actions/cache@v2 with: path: ${{ matrix.pip-cache }} key: ${{ runner.os }}-${{ matrix.python-version }}-pip-${{ hashFiles('**/poetry.lock') }} restore-keys: | ${{ runner.os }}-${{ matrix.python-version }}-pip- - uses: actions/cache@v2 with: path: ${{ matrix.poetry-cache }} key: ${{ runner.os }}-${{ matrix.python-version }}-poetry-${{ hashFiles('**/poetry.lock') }} restore-keys: | ${{ runner.os }}-${{ matrix.python-version }}-poetry- - uses: actions/cache@v2 with: path: .mypy_cache key: ${{ runner.os }}-${{ matrix.python-version }}-mypy-${{ hashFiles('**/poetry.lock') }} restore-keys: | ${{ runner.os }}-${{ matrix.python-version }}-mypy- - name: Install dependencies run: | make install-actions - name: Lint run: | make lint - name: Test run: | make test - name: Code Coverage uses: codecov/codecov-action@v2.1.0 if: ${{ success() }} 07070100000007000081A4000000000000000000000001639CA56200000357000000000000000000000000000000000000002E00000000browsers-0.5.2/.github/workflows/testpypi.yml# This workflow will publish to TestPyPI # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions name: Publish to TestPyPI on: push: tags: - '*' jobs: testpypi: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v2 with: python-version: '3.x' - name: Install dependencies run: | pip3 install -U pip setuptools poetry - name: Build package run: | poetry config repositories.testpypi https://test.pypi.org/legacy/ poetry config http-basic.testpypi ${{ secrets.TEST_PYPI_USER }} ${{ secrets.TEST_PYPI_PASS }} poetry build - name: Publish package run: | poetry publish -r testpypi 07070100000008000081A4000000000000000000000001639CA56200000808000000000000000000000000000000000000001A00000000browsers-0.5.2/.gitignore### Python template # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ cover/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder .pybuilder/ target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv # For a library or package, you might want to ignore these files since the code is # intended to run in multiple environments; otherwise, check them in: # .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # PEP 582; used by e.g. github.com/David-OConnor/pyflow __pypackages__/ # Celery stuff celerybeat-schedule celerybeat.pid # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # pytype static type analyzer .pytype/ # Cython debug symbols cython_debug/ 07070100000009000081A4000000000000000000000001639CA5620000042F000000000000000000000000000000000000001700000000browsers-0.5.2/LICENSEMIT License Copyright (c) 2022 Ronie Martinez Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0707010000000A000081A4000000000000000000000001639CA56200000351000000000000000000000000000000000000001800000000browsers-0.5.2/Makefile.PHONY: install install: pip3 install -U pip setuptools poetry poetry install .PHONY: install-actions install-actions: pip3 install pip setuptools poetry poetry config virtualenvs.create false poetry config experimental.new-installer false poetry install .PHONY: format format: poetry run autoflake --remove-all-unused-imports --in-place -r --exclude __init__.py . poetry run isort . poetry run black . .PHONY: lint lint: poetry run autoflake --remove-all-unused-imports --in-place -r --exclude __init__.py --check . poetry run isort --check-only . poetry run black --check . poetry run pflake8 . poetry run mypy tests browsers .PHONY: test test: poetry run pytest .PHONY: tag tag: VERSION=`poetry version | grep -o -E "\d+\.\d+\.\d+(-\w+\.\d+)?"`; \ git tag -s -a $$VERSION -m "Release $$VERSION"; \ echo "Tagged $$VERSION"; 0707010000000B000081A4000000000000000000000001639CA56200001921000000000000000000000000000000000000001900000000browsers-0.5.2/README.md<table> <tr> <td>License</td> <td><img src='https://img.shields.io/pypi/l/pybrowsers.svg?style=for-the-badge' alt="License"></td> <td>Version</td> <td><img src='https://img.shields.io/pypi/v/pybrowsers.svg?logo=pypi&style=for-the-badge' alt="Version"></td> </tr> <tr> <td>Github Actions</td> <td><img src='https://img.shields.io/github/actions/workflow/status/roniemartinez/browsers/python.yml?branch=master&label=actions&logo=github%20actions&style=for-the-badge' alt="Github Actions"></td> <td>Coverage</td> <td><img src='https://img.shields.io/codecov/c/github/roniemartinez/browsers/branch?label=codecov&logo=codecov&style=for-the-badge' alt="CodeCov"></td> </tr> <tr> <td>Supported versions</td> <td><img src='https://img.shields.io/pypi/pyversions/pybrowsers.svg?logo=python&style=for-the-badge' alt="Python Versions"></td> <td>Wheel</td> <td><img src='https://img.shields.io/pypi/wheel/pybrowsers.svg?style=for-the-badge' alt="Wheel"></td> </tr> <tr> <td>Status</td> <td><img src='https://img.shields.io/pypi/status/pybrowsers.svg?style=for-the-badge' alt="Status"></td> <td>Downloads</td> <td><img src='https://img.shields.io/pypi/dm/pybrowsers.svg?style=for-the-badge' alt="Downloads"></td> </tr> <tr> <td>All Contributors</td> <td><a href="#contributors-"><img src='https://img.shields.io/github/all-contributors/roniemartinez/browsers?style=for-the-badge' alt="All Contributors"></a></td> </tr> </table> # browsers Python library for detecting and launching browsers ## Why? I recently wrote a snippet for detecting installed browsers in an OSX machine in https://github.com/mitmproxy/mitmproxy/issues/5247#issuecomment-1095337723 based on https://github.com/httptoolkit/browser-launcher and I thought this could be useful to other devs since I cannot find an equivalent library of `httptoolkit/browser-launcher` in Python and the known `webbrowser` standard library does not support arguments. ## Installation ```bash pip install pybrowsers ``` ## Features - Detect browser on OSX - Detect browser on Linux - Detect browser on Windows - Launch browser with arguments - Launch and get browser by version with wildcard support ## Usage ### Import ```python import browsers ``` ### List all installer browsers ```python import browsers print(list(browsers.browsers())) # [{'browser_type': 'chrome', 'path': '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', 'display_name': 'Google Chrome', 'version': '100.0.4896.127'}, {'browser_type': 'firefox', 'path': '/Applications/Firefox.app/Contents/MacOS/firefox', 'display_name': 'Firefox', 'version': '99.0.1'}, {'browser_type': 'safari', 'path': '/Applications/Safari.app/Contents/MacOS/Safari', 'display_name': 'Safari', 'version': '15.4'}, {'browser_type': 'opera', 'path': '/Applications/Opera.app/Contents/MacOS/Opera', 'display_name': 'Opera', 'version': '85.0.4341.60'}, {'browser_type': 'msedge', 'path': '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge', 'display_name': 'Microsoft Edge', 'version': '100.1185.22042050'}] ``` ### Get browser information ```python import browsers print(browsers.get("chrome")) # {'browser_type': 'chrome', 'path': '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', 'display_name': 'Google Chrome', 'version': '100.0.4896.127'} ``` ### Launch browser ```python import browsers browsers.launch("chrome") ``` ### Launch browser with URL ```python import browsers browsers.launch("chrome", url="https://github.com/roniemartinez/browsers") ``` ### Launch browser with arguments ```python import browsers browsers.launch("chrome", args=["--incognito"]) ``` ### Specifying version The `get()` and `launch()` functions support specifying version in case multiple versions are installed. Wildcard pattern is also supported. ```python import browsers print(browsers.get("chrome", version="100.0.4896.127")) # complete version # {'browser_type': 'chrome', 'path': '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', 'display_name': 'Google Chrome', 'version': '100.0.4896.127'} print(browsers.get("chrome", version="100.*")) # wildcard # {'browser_type': 'chrome', 'path': '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', 'display_name': 'Google Chrome', 'version': '100.0.4896.127'} browsers.launch("chrome", version="100.0.4896.127") # complete version browsers.launch("chrome", version="100.*") # wildcard ``` ## References - [httptoolkit/browser-launcher](https://github.com/httptoolkit/browser-launcher) - [Desktop Entry Specification](https://specifications.freedesktop.org/desktop-entry-spec/latest/) - [Github: webbrowser.open incomplete on Windows](https://github.com/python/cpython/issues/52479#issuecomment-1093496412) - [Stackoverflow: Grabbing full file version of an exe in Python](https://stackoverflow.com/a/68774871/1279157) ## Contributors ⨠Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --> <!-- prettier-ignore-start --> <!-- markdownlint-disable --> <table> <tr> <td align="center"><a href="https://ron.sh/"><img src="https://avatars.githubusercontent.com/u/2573537?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ronie Martinez</b></sub></a><br /><a href="https://github.com/roniemartinez/browsers/commits?author=roniemartinez" title="Code">đģ</a> <a href="#ideas-roniemartinez" title="Ideas, Planning, & Feedback">đ¤</a> <a href="https://github.com/roniemartinez/browsers/commits?author=roniemartinez" title="Documentation">đ</a> <a href="#maintenance-roniemartinez" title="Maintenance">đ§</a></td> <td align="center"><a href="https://t.me/automation_remarks_ua"><img src="https://avatars.githubusercontent.com/u/4622856?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sergey Pirogov</b></sub></a><br /><a href="https://github.com/roniemartinez/browsers/issues?q=author%3ASergeyPirogov" title="Bug reports">đ</a></td> </tr> </table> <!-- markdownlint-restore --> <!-- prettier-ignore-end --> <!-- ALL-CONTRIBUTORS-LIST:END --> This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!0707010000000C000041ED000000000000000000000001639CA56200000000000000000000000000000000000000000000001800000000browsers-0.5.2/browsers0707010000000D000081A4000000000000000000000001639CA56200000BCE000000000000000000000000000000000000002400000000browsers-0.5.2/browsers/__init__.pyimport fnmatch import logging import shlex import subprocess import sys from typing import Iterator, Optional, Sequence from . import linux, osx, windows from .common import Browser __all__ = ["Browser", "browsers", "get", "launch"] logging.basicConfig(stream=sys.stdout, level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s") logger = logging.getLogger(__name__) def browsers() -> Iterator[Browser]: """ Iterates over installed browsers. :return: Iterator of Tuple of browser key and browser information. """ if sys.platform == "linux": yield from linux.browsers() elif sys.platform == "win32": yield from windows.browsers() elif sys.platform == "darwin": yield from osx.browsers() else: # pragma: no cover logger.info( "'%s' is currently not supported. Please open an issue or a PR at '%s'", sys.platform, "https://github.com/roniemartinez/browsers", ) def get(browser: str, version: str = "*") -> Optional[Browser]: """ Returns the information for the provided browser key. :param browser: Any of "chrome", "chrome-canary", "firefox", "firefox-developer", "firefox-nightly", "opera", "opera-beta", "opera-developer", "msedge", "msedge-beta", "msedge-dev", "msedge-canary", "msie", "brave", "brave-beta", "brave-dev", "brave-nightly", and "safari". :param version: Version string (supports wildcard, e.g. 100.*) :return: Dictionary containing "path", "display_name" and "version". """ for b in browsers(): if b["browser_type"] == browser and fnmatch.fnmatch(b["version"], version): return b return None def launch( browser: str, version: str = "*", url: Optional[str] = None, args: Optional[Sequence[str]] = None ) -> Optional[subprocess.Popen]: """ Launches a web browser. :param browser: Browser key. :param version: Version string (supports wildcard, e.g. 100.*) :param url: URL. :param args: Arguments to be passed to the browser. """ if args is None: args = [] b = get(browser, version) if not b: logger.info("Cannot find browser '%s'", browser) return None return _launch(browser, b["path"], args, url) def _launch( browser: str, path: str, args: Sequence[str], url: Optional[str] = None ) -> subprocess.Popen: # pragma: no cover url_arg = [] if browser == "firefox" and url is not None: args = ("-new-tab", url, *args) elif url is not None: url_arg.append(url) if browser == "safari": if args: logger.warning("Safari does not accept command line arguments. %s will be ignored.", str(args)) command = ["open", "--wait-apps", "--new", "--fresh", "-a", path, *url_arg] elif sys.platform != "linux": command = [path, *url_arg, *args] else: command = [*shlex.split(path), *url_arg, *args] return subprocess.Popen(command) 0707010000000E000081A4000000000000000000000001639CA562000000E5000000000000000000000000000000000000002200000000browsers-0.5.2/browsers/common.pyimport sys if sys.version_info >= (3, 8): from typing import TypedDict else: from typing_extensions import TypedDict class Browser(TypedDict): browser_type: str path: str display_name: str version: str 0707010000000F000081A4000000000000000000000001639CA5620000083E000000000000000000000000000000000000002100000000browsers-0.5.2/browsers/linux.pyimport os import re import subprocess import sys from typing import Iterator from .common import Browser LINUX_DESKTOP_ENTRY_LIST = ( # desktop entry name can be "firefox.desktop" or "firefox_firefox.desktop" ("chrome", ("google-chrome",)), ("chromium", ("chromium", "chromium_chromium")), ("firefox", ("firefox", "firefox_firefox")), ("msedge", ("microsoft-edge",)), ("opera", ("opera_opera",)), ("opera-beta", ("opera-beta_opera-beta",)), ("opera-developer", ("opera-developer_opera-developer",)), ("brave", ("brave-browser", "brave_brave")), ("brave-beta", ("brave-browser-beta",)), ("brave-nightly", ("brave-browser-nightly",)), ) # $XDG_DATA_HOME and $XDG_DATA_DIRS are not always set XDG_DATA_LOCATIONS = ( "~/.local/share/applications", "/usr/share/applications", "/var/lib/snapd/desktop/applications", ) VERSION_PATTERN = re.compile(r"\b(\S+\.\S+)\b") # simple pattern assuming all version strings have a dot on them def browsers() -> Iterator[Browser]: # type: ignore[return] if sys.platform == "linux": from xdg.DesktopEntry import DesktopEntry for browser, desktop_entries in LINUX_DESKTOP_ENTRY_LIST: for application_dir in XDG_DATA_LOCATIONS: for desktop_entry in desktop_entries: path = os.path.join(application_dir, f"{desktop_entry}.desktop") if not os.path.isfile(path): continue entry = DesktopEntry(path) executable_path = entry.getExec() if executable_path.lower().endswith(" %u"): executable_path = executable_path[:-3].strip() version = subprocess.getoutput(f"{executable_path} --version 2>&1").strip() match = VERSION_PATTERN.search(version) if match: version = match[0] yield Browser( browser_type=browser, path=executable_path, display_name=entry.getName(), version=version ) 07070100000010000081A4000000000000000000000001639CA5620000098B000000000000000000000000000000000000001F00000000browsers-0.5.2/browsers/osx.pyimport os import plistlib import subprocess import sys from typing import Iterator from .common import Browser OSX_BROWSER_BUNDLE_LIST = ( # browser name, bundle ID, version string ("chrome", "com.google.Chrome", "KSVersion"), ("chrome-canary", "com.google.Chrome.canary", "KSVersion"), ("chromium", "org.chromium.Chromium", "CFBundleShortVersionString"), ("firefox", "org.mozilla.firefox", "CFBundleShortVersionString"), ("firefox-developer", "org.mozilla.firefoxdeveloperedition", "CFBundleShortVersionString"), ("firefox-nightly", "org.mozilla.nightly", "CFBundleShortVersionString"), ("safari", "com.apple.Safari", "CFBundleShortVersionString"), ("opera", "com.operasoftware.Opera", "CFBundleVersion"), ("opera-beta", "com.operasoftware.OperaNext", "CFBundleVersion"), ("opera-developer", "com.operasoftware.OperaDeveloper", "CFBundleVersion"), ("msedge", "com.microsoft.edgemac", "CFBundleVersion"), ("msedge-beta", "com.microsoft.edgemac.Beta", "CFBundleVersion"), ("msedge-dev", "com.microsoft.edgemac.Dev", "CFBundleVersion"), ("msedge-canary", "com.microsoft.edgemac.Canary", "CFBundleVersion"), ("brave", "com.brave.Browser", "CFBundleVersion"), ("brave-beta", "com.brave.Browser.beta", "CFBundleVersion"), ("brave-dev", "com.brave.Browser.dev", "CFBundleVersion"), ("brave-nightly", "com.brave.Browser.nightly", "CFBundleVersion"), ) def browsers() -> Iterator[Browser]: # type: ignore[return] if sys.platform == "darwin": for browser, bundle_id, version_string in OSX_BROWSER_BUNDLE_LIST: paths = subprocess.getoutput(f'mdfind "kMDItemCFBundleIdentifier == {bundle_id}"').splitlines() for path in paths: with open(os.path.join(path, "Contents/Info.plist"), "rb") as f: plist = plistlib.load(f) executable_name = plist.get("CFBundleExecutable") executable = os.path.join(path, "Contents/MacOS", executable_name) display_name = plist.get("CFBundleDisplayName") or plist.get("CFBundleName", browser) version = plist[version_string] yield Browser( browser_type=browser, path=executable if browser != "safari" else path, display_name=display_name, version=version, ) 07070100000011000081A4000000000000000000000001639CA56200000BBA000000000000000000000000000000000000002300000000browsers-0.5.2/browsers/windows.pyimport os import sys from typing import Iterator from .common import Browser WINDOWS_REGISTRY_BROWSER_NAMES = { "Google Chrome": "chrome", "Google Chrome Canary": "chrome-canary", "Chromium": "chromium", "Mozilla Firefox": "firefox", "Firefox Developer Edition": "firefox-developer", "Firefox Nightly": "firefox-nightly", "Opera Stable": "opera", "Opera beta": "opera-beta", "Opera developer": "opera-developer", "Microsoft Edge": "msedge", "Microsoft Edge Beta": "msedge-beta", "Microsoft Edge Dev": "msedge-dev", "Microsoft Edge Canary": "msedge-canary", "Internet Explorer": "msie", "Brave": "brave", "Brave Beta": "brave-beta", "Brave Nightly": "brave-nightly", } def browsers() -> Iterator[Browser]: # type: ignore[return] if sys.platform == "win32": import winreg yield from _win32_browsers_from_registry(winreg.HKEY_CURRENT_USER, winreg.KEY_READ) yield from _win32_browsers_from_registry(winreg.HKEY_LOCAL_MACHINE, winreg.KEY_READ | winreg.KEY_WOW64_64KEY) yield from _win32_browsers_from_registry(winreg.HKEY_LOCAL_MACHINE, winreg.KEY_READ | winreg.KEY_WOW64_32KEY) def _win32_browsers_from_registry(tree: int, access: int) -> Iterator[Browser]: # type: ignore[return] if sys.platform == "win32": import winreg try: with winreg.OpenKey(tree, r"Software\Clients\StartMenuInternet", access=access) as hkey: i = 0 while True: try: subkey = winreg.EnumKey(hkey, i) i += 1 except OSError: break try: display_name = winreg.QueryValue(hkey, subkey) if not display_name or not isinstance(display_name, str): # pragma: no cover display_name = subkey except OSError: # pragma: no cover display_name = subkey try: cmd = winreg.QueryValue(hkey, rf"{subkey}\shell\open\command") cmd = cmd.strip('"') os.stat(cmd) except (OSError, AttributeError, TypeError, ValueError): # pragma: no cover continue yield Browser( browser_type=WINDOWS_REGISTRY_BROWSER_NAMES.get(display_name, "unknown"), path=cmd, display_name=display_name, version=_get_file_version(cmd), ) except FileNotFoundError: pass def _get_file_version(path: str) -> str: import win32api info = win32api.GetFileVersionInfo(path, "\\") ms = info["FileVersionMS"] ls = info["FileVersionLS"] return ".".join(map(str, (win32api.HIWORD(ms), win32api.LOWORD(ms), win32api.HIWORD(ls), win32api.LOWORD(ls)))) 07070100000012000081A4000000000000000000000001639CA56200009982000000000000000000000000000000000000001B00000000browsers-0.5.2/poetry.lock[[package]] name = "attrs" version = "21.4.0" description = "Classes Without Boilerplate" category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.extras] dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six", "sphinx", "sphinx-notfound-page", "zope.interface"] docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six", "zope.interface"] tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "six"] [[package]] name = "autoflake" version = "1.7.8" description = "Removes unused imports and unused variables" category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] pyflakes = ">=1.1.0,<3" tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} [[package]] name = "black" version = "22.12.0" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] click = ">=8.0.0" mypy-extensions = ">=0.4.3" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} [package.extras] colorama = ["colorama (>=0.4.3)"] d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "click" version = "8.1.2" description = "Composable command line interface toolkit" category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "colorama" version = "0.4.4" description = "Cross-platform colored terminal text." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "commonmark" version = "0.9.1" description = "Python parser for the CommonMark Markdown spec" category = "dev" optional = false python-versions = "*" [package.extras] test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"] [[package]] name = "coverage" version = "6.4.4" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} [package.extras] toml = ["tomli"] [[package]] name = "exceptiongroup" version = "1.0.0rc9" description = "Backport of PEP 654 (exception groups)" category = "dev" optional = false python-versions = ">=3.7" [package.extras] test = ["pytest (>=6)"] [[package]] name = "flake8" version = "5.0.4" description = "the modular source code checker: pep8 pyflakes and co" category = "dev" optional = false python-versions = ">=3.6.1" [package.dependencies] importlib-metadata = {version = ">=1.1.0,<4.3", markers = "python_version < \"3.8\""} mccabe = ">=0.7.0,<0.8.0" pycodestyle = ">=2.9.0,<2.10.0" pyflakes = ">=2.5.0,<2.6.0" [[package]] name = "importlib-metadata" version = "4.2.0" description = "Read metadata from Python packages" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] docs = ["jaraco.packaging (>=8.2)", "rst.linker (>=1.9)", "sphinx"] testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pep517", "pyfakefs", "pytest (>=4.6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy"] [[package]] name = "iniconfig" version = "1.1.1" description = "iniconfig: brain-dead simple config-ini parsing" category = "dev" optional = false python-versions = "*" [[package]] name = "isort" version = "5.11.2" description = "A Python utility / library to sort Python imports." category = "dev" optional = false python-versions = ">=3.7.0" [package.extras] colors = ["colorama (>=0.4.3,<0.5.0)"] pipfile-deprecated-finder = ["pipreqs", "requirementslib"] plugins = ["setuptools"] requirements-deprecated-finder = ["pip-api", "pipreqs"] [[package]] name = "mccabe" version = "0.7.0" description = "McCabe checker, plugin for flake8" category = "dev" optional = false python-versions = ">=3.6" [[package]] name = "mypy" version = "0.991" description = "Optional static typing for Python" category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] mypy-extensions = ">=0.4.3" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""} typing-extensions = ">=3.10" [package.extras] dmypy = ["psutil (>=4.0)"] install-types = ["pip"] python2 = ["typed-ast (>=1.4.0,<2)"] reports = ["lxml"] [[package]] name = "mypy-extensions" version = "0.4.3" description = "Experimental type system extensions for programs checked with the mypy typechecker." category = "dev" optional = false python-versions = "*" [[package]] name = "packaging" version = "21.3" description = "Core utilities for Python packages" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" [[package]] name = "pathspec" version = "0.9.0" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [[package]] name = "platformdirs" version = "2.5.1" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" [package.extras] docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] [[package]] name = "pluggy" version = "1.0.0" description = "plugin and hook calling mechanisms for python" category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} [package.extras] dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] [[package]] name = "pprintpp" version = "0.4.0" description = "A drop-in replacement for pprint that's actually pretty" category = "dev" optional = false python-versions = "*" [[package]] name = "pycodestyle" version = "2.9.1" description = "Python style guide checker" category = "dev" optional = false python-versions = ">=3.6" [[package]] name = "pyflakes" version = "2.5.0" description = "passive checker of Python programs" category = "dev" optional = false python-versions = ">=3.6" [[package]] name = "pygments" version = "2.11.2" description = "Pygments is a syntax highlighting package written in Python." category = "dev" optional = false python-versions = ">=3.5" [[package]] name = "pyparsing" version = "3.0.8" description = "pyparsing module - Classes and methods to define and execute parsing grammars" category = "dev" optional = false python-versions = ">=3.6.8" [package.extras] diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pyproject-flake8" version = "5.0.4.post1" description = "pyproject-flake8 (`pflake8`), a monkey patching wrapper to connect flake8 with pyproject.toml configuration" category = "dev" optional = false python-versions = "*" [package.dependencies] flake8 = "5.0.4" tomli = {version = "*", markers = "python_version < \"3.11\""} [[package]] name = "pytest" version = "7.2.0" description = "pytest: simple powerful testing with Python" category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] [[package]] name = "pytest-clarity" version = "1.0.1" description = "A plugin providing an alternative, colourful diff output for failing assertions." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] pprintpp = ">=0.4.0" pytest = ">=3.5.0" rich = ">=8.0.0" [[package]] name = "pytest-cov" version = "4.0.0" description = "Pytest plugin for measuring coverage." category = "dev" optional = false python-versions = ">=3.6" [package.dependencies] coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] [[package]] name = "pywin32" version = "305" description = "Python for Window Extensions" category = "main" optional = false python-versions = "*" [[package]] name = "pyxdg" version = "0.28" description = "PyXDG contains implementations of freedesktop.org standards in python." category = "main" optional = false python-versions = "*" [[package]] name = "rich" version = "12.2.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" category = "dev" optional = false python-versions = ">=3.6.3,<4.0.0" [package.dependencies] commonmark = ">=0.9.0,<0.10.0" pygments = ">=2.6.0,<3.0.0" typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} [package.extras] jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"] [[package]] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" category = "dev" optional = false python-versions = ">=3.7" [[package]] name = "typed-ast" version = "1.5.2" description = "a fork of Python 2 and 3 ast modules with type comment support" category = "dev" optional = false python-versions = ">=3.6" [[package]] name = "typing-extensions" version = "4.1.1" description = "Backported and Experimental Type Hints for Python 3.6+" category = "dev" optional = false python-versions = ">=3.6" [[package]] name = "zipp" version = "3.8.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "dev" optional = false python-versions = ">=3.7" [package.extras] docs = ["jaraco.packaging (>=9)", "rst.linker (>=1.9)", "sphinx"] testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "1.1" python-versions = "^3.7" content-hash = "3fe90c3e7796c7b1106e9b250c8a3e922ca5ebfac77c27ce7586999cff13e547" [metadata.files] attrs = [ {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, ] autoflake = [ {file = "autoflake-1.7.8-py3-none-any.whl", hash = "sha256:46373ef69b6714f5064c923bb28bd797c4f8a9497f557d87fc36665c6d956b39"}, {file = "autoflake-1.7.8.tar.gz", hash = "sha256:e7e46372dee46fa1c97acf310d99d922b63d369718a270809d7c278d34a194cf"}, ] black = [ {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, ] click = [ {file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e"}, {file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"}, ] colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] commonmark = [ {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"}, {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"}, ] coverage = [ {file = "coverage-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7b4da9bafad21ea45a714d3ea6f3e1679099e420c8741c74905b92ee9bfa7cc"}, {file = "coverage-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fde17bc42e0716c94bf19d92e4c9f5a00c5feb401f5bc01101fdf2a8b7cacf60"}, {file = "coverage-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdbb0d89923c80dbd435b9cf8bba0ff55585a3cdb28cbec65f376c041472c60d"}, {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67f9346aeebea54e845d29b487eb38ec95f2ecf3558a3cffb26ee3f0dcc3e760"}, {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42c499c14efd858b98c4e03595bf914089b98400d30789511577aa44607a1b74"}, {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c35cca192ba700979d20ac43024a82b9b32a60da2f983bec6c0f5b84aead635c"}, {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9cc4f107009bca5a81caef2fca843dbec4215c05e917a59dec0c8db5cff1d2aa"}, {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f444627b3664b80d078c05fe6a850dd711beeb90d26731f11d492dcbadb6973"}, {file = "coverage-6.4.4-cp310-cp310-win32.whl", hash = "sha256:66e6df3ac4659a435677d8cd40e8eb1ac7219345d27c41145991ee9bf4b806a0"}, {file = "coverage-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:35ef1f8d8a7a275aa7410d2f2c60fa6443f4a64fae9be671ec0696a68525b875"}, {file = "coverage-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c1328d0c2f194ffda30a45f11058c02410e679456276bfa0bbe0b0ee87225fac"}, {file = "coverage-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61b993f3998ee384935ee423c3d40894e93277f12482f6e777642a0141f55782"}, {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5dd4b8e9cd0deb60e6fcc7b0647cbc1da6c33b9e786f9c79721fd303994832f"}, {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7026f5afe0d1a933685d8f2169d7c2d2e624f6255fb584ca99ccca8c0e966fd7"}, {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9c7b9b498eb0c0d48b4c2abc0e10c2d78912203f972e0e63e3c9dc21f15abdaa"}, {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ee2b2fb6eb4ace35805f434e0f6409444e1466a47f620d1d5763a22600f0f892"}, {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ab066f5ab67059d1f1000b5e1aa8bbd75b6ed1fc0014559aea41a9eb66fc2ce0"}, {file = "coverage-6.4.4-cp311-cp311-win32.whl", hash = "sha256:9d6e1f3185cbfd3d91ac77ea065d85d5215d3dfa45b191d14ddfcd952fa53796"}, {file = "coverage-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e3d3c4cc38b2882f9a15bafd30aec079582b819bec1b8afdbde8f7797008108a"}, {file = "coverage-6.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a095aa0a996ea08b10580908e88fbaf81ecf798e923bbe64fb98d1807db3d68a"}, {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6f44409ab02e202b31a05dd6666797f9de2aa2b4b3534e9d450e42dea5e817"}, {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b7101938584d67e6f45f0015b60e24a95bf8dea19836b1709a80342e01b472f"}, {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14a32ec68d721c3d714d9b105c7acf8e0f8a4f4734c811eda75ff3718570b5e3"}, {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6a864733b22d3081749450466ac80698fe39c91cb6849b2ef8752fd7482011f3"}, {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:08002f9251f51afdcc5e3adf5d5d66bb490ae893d9e21359b085f0e03390a820"}, {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a3b2752de32c455f2521a51bd3ffb53c5b3ae92736afde67ce83477f5c1dd928"}, {file = "coverage-6.4.4-cp37-cp37m-win32.whl", hash = "sha256:f855b39e4f75abd0dfbcf74a82e84ae3fc260d523fcb3532786bcbbcb158322c"}, {file = "coverage-6.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ee6ae6bbcac0786807295e9687169fba80cb0617852b2fa118a99667e8e6815d"}, {file = "coverage-6.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:564cd0f5b5470094df06fab676c6d77547abfdcb09b6c29c8a97c41ad03b103c"}, {file = "coverage-6.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cbbb0e4cd8ddcd5ef47641cfac97d8473ab6b132dd9a46bacb18872828031685"}, {file = "coverage-6.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6113e4df2fa73b80f77663445be6d567913fb3b82a86ceb64e44ae0e4b695de1"}, {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d032bfc562a52318ae05047a6eb801ff31ccee172dc0d2504614e911d8fa83e"}, {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e431e305a1f3126477abe9a184624a85308da8edf8486a863601d58419d26ffa"}, {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cf2afe83a53f77aec067033199797832617890e15bed42f4a1a93ea24794ae3e"}, {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:783bc7c4ee524039ca13b6d9b4186a67f8e63d91342c713e88c1865a38d0892a"}, {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ff934ced84054b9018665ca3967fc48e1ac99e811f6cc99ea65978e1d384454b"}, {file = "coverage-6.4.4-cp38-cp38-win32.whl", hash = "sha256:e1fabd473566fce2cf18ea41171d92814e4ef1495e04471786cbc943b89a3781"}, {file = "coverage-6.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:4179502f210ebed3ccfe2f78bf8e2d59e50b297b598b100d6c6e3341053066a2"}, {file = "coverage-6.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:98c0b9e9b572893cdb0a00e66cf961a238f8d870d4e1dc8e679eb8bdc2eb1b86"}, {file = "coverage-6.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc600f6ec19b273da1d85817eda339fb46ce9eef3e89f220055d8696e0a06908"}, {file = "coverage-6.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a98d6bf6d4ca5c07a600c7b4e0c5350cd483c85c736c522b786be90ea5bac4f"}, {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01778769097dbd705a24e221f42be885c544bb91251747a8a3efdec6eb4788f2"}, {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfa0b97eb904255e2ab24166071b27408f1f69c8fbda58e9c0972804851e0558"}, {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fcbe3d9a53e013f8ab88734d7e517eb2cd06b7e689bedf22c0eb68db5e4a0a19"}, {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:15e38d853ee224e92ccc9a851457fb1e1f12d7a5df5ae44544ce7863691c7a0d"}, {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6913dddee2deff8ab2512639c5168c3e80b3ebb0f818fed22048ee46f735351a"}, {file = "coverage-6.4.4-cp39-cp39-win32.whl", hash = "sha256:354df19fefd03b9a13132fa6643527ef7905712109d9c1c1903f2133d3a4e145"}, {file = "coverage-6.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:1238b08f3576201ebf41f7c20bf59baa0d05da941b123c6656e42cdb668e9827"}, {file = "coverage-6.4.4-pp36.pp37.pp38-none-any.whl", hash = "sha256:f67cf9f406cf0d2f08a3515ce2db5b82625a7257f88aad87904674def6ddaec1"}, {file = "coverage-6.4.4.tar.gz", hash = "sha256:e16c45b726acb780e1e6f88b286d3c10b3914ab03438f32117c4aa52d7f30d58"}, ] exceptiongroup = [ {file = "exceptiongroup-1.0.0rc9-py3-none-any.whl", hash = "sha256:2e3c3fc1538a094aab74fad52d6c33fc94de3dfee3ee01f187c0e0c72aec5337"}, {file = "exceptiongroup-1.0.0rc9.tar.gz", hash = "sha256:9086a4a21ef9b31c72181c77c040a074ba0889ee56a7b289ff0afb0d97655f96"}, ] flake8 = [ {file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"}, {file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"}, ] importlib-metadata = [ {file = "importlib_metadata-4.2.0-py3-none-any.whl", hash = "sha256:057e92c15bc8d9e8109738a48db0ccb31b4d9d5cfbee5a8670879a30be66304b"}, {file = "importlib_metadata-4.2.0.tar.gz", hash = "sha256:b7e52a1f8dec14a75ea73e0891f3060099ca1d8e6a462a4dff11c3e119ea1b31"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] isort = [ {file = "isort-5.11.2-py3-none-any.whl", hash = "sha256:e486966fba83f25b8045f8dd7455b0a0d1e4de481e1d7ce4669902d9fb85e622"}, {file = "isort-5.11.2.tar.gz", hash = "sha256:dd8bbc5c0990f2a095d754e50360915f73b4c26fc82733eb5bfc6b48396af4d2"}, ] mccabe = [ {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, ] mypy = [ {file = "mypy-0.991-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7d17e0a9707d0772f4a7b878f04b4fd11f6f5bcb9b3813975a9b13c9332153ab"}, {file = "mypy-0.991-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0714258640194d75677e86c786e80ccf294972cc76885d3ebbb560f11db0003d"}, {file = "mypy-0.991-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c8f3be99e8a8bd403caa8c03be619544bc2c77a7093685dcf308c6b109426c6"}, {file = "mypy-0.991-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc9ec663ed6c8f15f4ae9d3c04c989b744436c16d26580eaa760ae9dd5d662eb"}, {file = "mypy-0.991-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4307270436fd7694b41f913eb09210faff27ea4979ecbcd849e57d2da2f65305"}, {file = "mypy-0.991-cp310-cp310-win_amd64.whl", hash = "sha256:901c2c269c616e6cb0998b33d4adbb4a6af0ac4ce5cd078afd7bc95830e62c1c"}, {file = "mypy-0.991-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d13674f3fb73805ba0c45eb6c0c3053d218aa1f7abead6e446d474529aafc372"}, {file = "mypy-0.991-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c8cd4fb70e8584ca1ed5805cbc7c017a3d1a29fb450621089ffed3e99d1857f"}, {file = "mypy-0.991-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:209ee89fbb0deed518605edddd234af80506aec932ad28d73c08f1400ef80a33"}, {file = "mypy-0.991-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37bd02ebf9d10e05b00d71302d2c2e6ca333e6c2a8584a98c00e038db8121f05"}, {file = "mypy-0.991-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:26efb2fcc6b67e4d5a55561f39176821d2adf88f2745ddc72751b7890f3194ad"}, {file = "mypy-0.991-cp311-cp311-win_amd64.whl", hash = "sha256:3a700330b567114b673cf8ee7388e949f843b356a73b5ab22dd7cff4742a5297"}, {file = "mypy-0.991-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:1f7d1a520373e2272b10796c3ff721ea1a0712288cafaa95931e66aa15798813"}, {file = "mypy-0.991-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:641411733b127c3e0dab94c45af15fea99e4468f99ac88b39efb1ad677da5711"}, {file = "mypy-0.991-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3d80e36b7d7a9259b740be6d8d906221789b0d836201af4234093cae89ced0cd"}, {file = "mypy-0.991-cp37-cp37m-win_amd64.whl", hash = "sha256:e62ebaad93be3ad1a828a11e90f0e76f15449371ffeecca4a0a0b9adc99abcef"}, {file = "mypy-0.991-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b86ce2c1866a748c0f6faca5232059f881cda6dda2a893b9a8373353cfe3715a"}, {file = "mypy-0.991-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac6e503823143464538efda0e8e356d871557ef60ccd38f8824a4257acc18d93"}, {file = "mypy-0.991-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0cca5adf694af539aeaa6ac633a7afe9bbd760df9d31be55ab780b77ab5ae8bf"}, {file = "mypy-0.991-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a12c56bf73cdab116df96e4ff39610b92a348cc99a1307e1da3c3768bbb5b135"}, {file = "mypy-0.991-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:652b651d42f155033a1967739788c436491b577b6a44e4c39fb340d0ee7f0d70"}, {file = "mypy-0.991-cp38-cp38-win_amd64.whl", hash = "sha256:4175593dc25d9da12f7de8de873a33f9b2b8bdb4e827a7cae952e5b1a342e243"}, {file = "mypy-0.991-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:98e781cd35c0acf33eb0295e8b9c55cdbef64fcb35f6d3aa2186f289bed6e80d"}, {file = "mypy-0.991-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6d7464bac72a85cb3491c7e92b5b62f3dcccb8af26826257760a552a5e244aa5"}, {file = "mypy-0.991-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c9166b3f81a10cdf9b49f2d594b21b31adadb3d5e9db9b834866c3258b695be3"}, {file = "mypy-0.991-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8472f736a5bfb159a5e36740847808f6f5b659960115ff29c7cecec1741c648"}, {file = "mypy-0.991-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e80e758243b97b618cdf22004beb09e8a2de1af481382e4d84bc52152d1c476"}, {file = "mypy-0.991-cp39-cp39-win_amd64.whl", hash = "sha256:74e259b5c19f70d35fcc1ad3d56499065c601dfe94ff67ae48b85596b9ec1461"}, {file = "mypy-0.991-py3-none-any.whl", hash = "sha256:de32edc9b0a7e67c2775e574cb061a537660e51210fbf6006b0b36ea695ae9bb"}, {file = "mypy-0.991.tar.gz", hash = "sha256:3c0165ba8f354a6d9881809ef29f1a9318a236a6d81c690094c5df32107bde06"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] pathspec = [ {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, ] platformdirs = [ {file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"}, {file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"}, ] pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] pprintpp = [ {file = "pprintpp-0.4.0-py2.py3-none-any.whl", hash = "sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d"}, {file = "pprintpp-0.4.0.tar.gz", hash = "sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403"}, ] pycodestyle = [ {file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"}, {file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"}, ] pyflakes = [ {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, ] pygments = [ {file = "Pygments-2.11.2-py3-none-any.whl", hash = "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65"}, {file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"}, ] pyparsing = [ {file = "pyparsing-3.0.8-py3-none-any.whl", hash = "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"}, {file = "pyparsing-3.0.8.tar.gz", hash = "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954"}, ] pyproject-flake8 = [ {file = "pyproject-flake8-5.0.4.post1.tar.gz", hash = "sha256:c2dfdf1064f47efbb2e4faf1a32b0b6a6ea67dc4d1debb98d862b0cdee377941"}, {file = "pyproject_flake8-5.0.4.post1-py2.py3-none-any.whl", hash = "sha256:457e52dde1b7a1f84b5230c70d61afa58ced64a44b81a609f19e972319fa68ed"}, ] pytest = [ {file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"}, {file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"}, ] pytest-clarity = [ {file = "pytest-clarity-1.0.1.tar.gz", hash = "sha256:505fe345fad4fe11c6a4187fe683f2c7c52c077caa1e135f3e483fe112db7772"}, ] pytest-cov = [ {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, ] pywin32 = [ {file = "pywin32-305-cp310-cp310-win32.whl", hash = "sha256:421f6cd86e84bbb696d54563c48014b12a23ef95a14e0bdba526be756d89f116"}, {file = "pywin32-305-cp310-cp310-win_amd64.whl", hash = "sha256:73e819c6bed89f44ff1d690498c0a811948f73777e5f97c494c152b850fad478"}, {file = "pywin32-305-cp310-cp310-win_arm64.whl", hash = "sha256:742eb905ce2187133a29365b428e6c3b9001d79accdc30aa8969afba1d8470f4"}, {file = "pywin32-305-cp311-cp311-win32.whl", hash = "sha256:19ca459cd2e66c0e2cc9a09d589f71d827f26d47fe4a9d09175f6aa0256b51c2"}, {file = "pywin32-305-cp311-cp311-win_amd64.whl", hash = "sha256:326f42ab4cfff56e77e3e595aeaf6c216712bbdd91e464d167c6434b28d65990"}, {file = "pywin32-305-cp311-cp311-win_arm64.whl", hash = "sha256:4ecd404b2c6eceaca52f8b2e3e91b2187850a1ad3f8b746d0796a98b4cea04db"}, {file = "pywin32-305-cp36-cp36m-win32.whl", hash = "sha256:48d8b1659284f3c17b68587af047d110d8c44837736b8932c034091683e05863"}, {file = "pywin32-305-cp36-cp36m-win_amd64.whl", hash = "sha256:13362cc5aa93c2beaf489c9c9017c793722aeb56d3e5166dadd5ef82da021fe1"}, {file = "pywin32-305-cp37-cp37m-win32.whl", hash = "sha256:a55db448124d1c1484df22fa8bbcbc45c64da5e6eae74ab095b9ea62e6d00496"}, {file = "pywin32-305-cp37-cp37m-win_amd64.whl", hash = "sha256:109f98980bfb27e78f4df8a51a8198e10b0f347257d1e265bb1a32993d0c973d"}, {file = "pywin32-305-cp38-cp38-win32.whl", hash = "sha256:9dd98384da775afa009bc04863426cb30596fd78c6f8e4e2e5bbf4edf8029504"}, {file = "pywin32-305-cp38-cp38-win_amd64.whl", hash = "sha256:56d7a9c6e1a6835f521788f53b5af7912090674bb84ef5611663ee1595860fc7"}, {file = "pywin32-305-cp39-cp39-win32.whl", hash = "sha256:9d968c677ac4d5cbdaa62fd3014ab241718e619d8e36ef8e11fb930515a1e918"}, {file = "pywin32-305-cp39-cp39-win_amd64.whl", hash = "sha256:50768c6b7c3f0b38b7fb14dd4104da93ebced5f1a50dc0e834594bff6fbe1271"}, ] pyxdg = [ {file = "pyxdg-0.28-py2.py3-none-any.whl", hash = "sha256:bdaf595999a0178ecea4052b7f4195569c1ff4d344567bccdc12dfdf02d545ab"}, {file = "pyxdg-0.28.tar.gz", hash = "sha256:3267bb3074e934df202af2ee0868575484108581e6f3cb006af1da35395e88b4"}, ] rich = [ {file = "rich-12.2.0-py3-none-any.whl", hash = "sha256:c50f3d253bc6a9bb9c79d61a26d510d74abdf1b16881260fab5edfc3edfb082f"}, {file = "rich-12.2.0.tar.gz", hash = "sha256:ea74bc9dad9589d8eea3e3fd0b136d8bf6e428888955f215824c2894f0da8b47"}, ] tomli = [ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] typed-ast = [ {file = "typed_ast-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:183b183b7771a508395d2cbffd6db67d6ad52958a5fdc99f450d954003900266"}, {file = "typed_ast-1.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:676d051b1da67a852c0447621fdd11c4e104827417bf216092ec3e286f7da596"}, {file = "typed_ast-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc2542e83ac8399752bc16e0b35e038bdb659ba237f4222616b4e83fb9654985"}, {file = "typed_ast-1.5.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74cac86cc586db8dfda0ce65d8bcd2bf17b58668dfcc3652762f3ef0e6677e76"}, {file = "typed_ast-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:18fe320f354d6f9ad3147859b6e16649a0781425268c4dde596093177660e71a"}, {file = "typed_ast-1.5.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:31d8c6b2df19a777bc8826770b872a45a1f30cfefcfd729491baa5237faae837"}, {file = "typed_ast-1.5.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:963a0ccc9a4188524e6e6d39b12c9ca24cc2d45a71cfdd04a26d883c922b4b78"}, {file = "typed_ast-1.5.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0eb77764ea470f14fcbb89d51bc6bbf5e7623446ac4ed06cbd9ca9495b62e36e"}, {file = "typed_ast-1.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:294a6903a4d087db805a7656989f613371915fc45c8cc0ddc5c5a0a8ad9bea4d"}, {file = "typed_ast-1.5.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:26a432dc219c6b6f38be20a958cbe1abffcc5492821d7e27f08606ef99e0dffd"}, {file = "typed_ast-1.5.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7407cfcad702f0b6c0e0f3e7ab876cd1d2c13b14ce770e412c0c4b9728a0f88"}, {file = "typed_ast-1.5.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f30ddd110634c2d7534b2d4e0e22967e88366b0d356b24de87419cc4410c41b7"}, {file = "typed_ast-1.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8c08d6625bb258179b6e512f55ad20f9dfef019bbfbe3095247401e053a3ea30"}, {file = "typed_ast-1.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:90904d889ab8e81a956f2c0935a523cc4e077c7847a836abee832f868d5c26a4"}, {file = "typed_ast-1.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bbebc31bf11762b63bf61aaae232becb41c5bf6b3461b80a4df7e791fabb3aca"}, {file = "typed_ast-1.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c29dd9a3a9d259c9fa19d19738d021632d673f6ed9b35a739f48e5f807f264fb"}, {file = "typed_ast-1.5.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:58ae097a325e9bb7a684572d20eb3e1809802c5c9ec7108e85da1eb6c1a3331b"}, {file = "typed_ast-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:da0a98d458010bf4fe535f2d1e367a2e2060e105978873c04c04212fb20543f7"}, {file = "typed_ast-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:33b4a19ddc9fc551ebabca9765d54d04600c4a50eda13893dadf67ed81d9a098"}, {file = "typed_ast-1.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1098df9a0592dd4c8c0ccfc2e98931278a6c6c53cb3a3e2cf7e9ee3b06153344"}, {file = "typed_ast-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42c47c3b43fe3a39ddf8de1d40dbbfca60ac8530a36c9b198ea5b9efac75c09e"}, {file = "typed_ast-1.5.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f290617f74a610849bd8f5514e34ae3d09eafd521dceaa6cf68b3f4414266d4e"}, {file = "typed_ast-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:df05aa5b241e2e8045f5f4367a9f6187b09c4cdf8578bb219861c4e27c443db5"}, {file = "typed_ast-1.5.2.tar.gz", hash = "sha256:525a2d4088e70a9f75b08b3f87a51acc9cde640e19cc523c7e41aa355564ae27"}, ] typing-extensions = [ {file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"}, {file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"}, ] zipp = [ {file = "zipp-3.8.0-py3-none-any.whl", hash = "sha256:c4f6e5bbf48e74f7a38e7cc5b0480ff42b0ae5178957d564d18932525d5cf099"}, {file = "zipp-3.8.0.tar.gz", hash = "sha256:56bf8aadb83c24db6c4b577e13de374ccfb67da2078beba1d037c17980bf43ad"}, ] 07070100000013000081A4000000000000000000000001639CA562000008C9000000000000000000000000000000000000001E00000000browsers-0.5.2/pyproject.toml[tool.poetry] name = "pybrowsers" version = "0.5.2" repository = "https://github.com/roniemartinez/browsers" description = "Python library for detecting and launching browsers" authors = ["Ronie Martinez <ronmarti18@gmail.com>"] license = "MIT" readme = "README.md" classifiers = [ "Development Status :: 3 - Alpha", "License :: OSI Approved :: MIT License", "Topic :: Internet :: WWW/HTTP :: Browsers", "Topic :: Software Development :: Libraries :: Python Modules", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: Implementation :: CPython", ] packages = [ { include = "browsers" }, ] [tool.poetry.urls] "Donate" = "https://github.com/sponsors/roniemartinez" [tool.poetry.dependencies] python = "^3.7" pyxdg = { version = ">=0.27,<0.29", markers = "sys_platform == 'linux'" } pywin32 = { version = ">=303,<306", markers = "sys_platform == 'win32'" } [tool.poetry.dev-dependencies] autoflake = "^1.7.8" black = "^22.12" isort = "^5.11.2" mypy = "^0.991" pyproject-flake8 = "^5.0.4" pytest = "^7.2.0" pytest-clarity = "^1.0.1" pytest-cov = "^4.0.0" [tool.isort] line_length = 120 multi_line_output = 3 force_grid_wrap = 0 use_parentheses = true include_trailing_comma = true ensure_newline_before_comments = true atomic = true [tool.black] line-length = 120 target-version = ['py39'] include = '\.pyi?$' extend-exclude = """ # A regex preceded with ^/ will apply only to files and directories # in the root of the project. ^/setup.py """ [tool.mypy] disallow_untyped_defs = true ignore_missing_imports = true [[tool.mypy.overrides]] module = [ "pkg_resources", ] ignore_missing_imports = true [tool.flake8] max-line-length = 120 extend-ignore = ["E203"] extend-exclude = """ setup.py, """ [tool.pytest.ini_options] addopts = """\ --cov=browsers \ --cov-report=term-missing \ --cov-report=xml \ --cov-report=html \ -vv \ -x \ -s \ """ [build-system] requires = ["poetry-core>=1.0.0"] build-backend = "poetry.core.masonry.api" 07070100000014000041ED000000000000000000000001639CA56200000000000000000000000000000000000000000000001500000000browsers-0.5.2/tests07070100000015000081A4000000000000000000000001639CA56200000000000000000000000000000000000000000000002100000000browsers-0.5.2/tests/__init__.py07070100000016000081A4000000000000000000000001639CA56200001376000000000000000000000000000000000000002400000000browsers-0.5.2/tests/test_detect.pyimport sys from typing import Dict from unittest.mock import ANY import pytest import browsers """ These tests are based on what browsers exists in Github Actions virtual environments. """ @pytest.mark.parametrize( "browser", ( pytest.param("chrome", id="chrome"), pytest.param("firefox", id="firefox"), pytest.param("safari", id="safari", marks=pytest.mark.skipif(sys.platform != "darwin", reason="osx-only")), pytest.param( "msedge", id="msedge", marks=pytest.mark.skipif(sys.platform == "linux", reason="osx-and-windows-only") ), pytest.param("msie", id="msie", marks=pytest.mark.skipif(sys.platform != "win32", reason="windows-only")), ), ) def test_browsers(browser: str) -> None: available_browsers = [b["browser_type"] for b in browsers.browsers()] assert browser in available_browsers @pytest.mark.parametrize( ("browser", "details"), ( pytest.param( "chrome", { "browser_type": "chrome", "display_name": "Google Chrome", "path": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", "version": ANY, }, marks=pytest.mark.skipif(sys.platform != "darwin", reason="osx-only"), id="chrome-osx", ), pytest.param( "firefox", { "browser_type": "firefox", "display_name": "Firefox", "path": "/Applications/Firefox.app/Contents/MacOS/firefox", "version": ANY, }, marks=pytest.mark.skipif(sys.platform != "darwin", reason="osx-only"), id="firefox-osx", ), pytest.param( "safari", { "browser_type": "safari", "display_name": "Safari", "path": "/Applications/Safari.app", "version": ANY, }, marks=pytest.mark.skipif(sys.platform != "darwin", reason="osx-only"), id="safari-osx", ), pytest.param( "msedge", { "browser_type": "msedge", "display_name": "Microsoft Edge", "path": "/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge", "version": ANY, }, marks=pytest.mark.skipif(sys.platform != "darwin", reason="osx-only"), id="msedge-osx", ), pytest.param( "chrome", { "browser_type": "chrome", "display_name": "Google Chrome", "path": "/usr/bin/google-chrome-stable", "version": ANY, }, marks=pytest.mark.skipif(sys.platform != "linux", reason="linux-only"), id="chrome-linux", ), pytest.param( "firefox", { "browser_type": "firefox", "display_name": "Firefox Web Browser", "path": "firefox", "version": ANY, }, marks=pytest.mark.skipif(sys.platform != "linux", reason="linux-only"), id="firefox-linux", ), pytest.param( "chrome", { "browser_type": "chrome", "display_name": "Google Chrome", "path": r"C:\Program Files\Google\Chrome\Application\chrome.exe", "version": ANY, }, marks=pytest.mark.skipif(sys.platform != "win32", reason="windows-only"), id="chrome-win32", ), pytest.param( "firefox", { "browser_type": "firefox", "display_name": "Mozilla Firefox", "path": r"C:\Program Files\Mozilla Firefox\firefox.exe", "version": ANY, }, marks=pytest.mark.skipif(sys.platform != "win32", reason="windows-only"), id="firefox-win32", ), pytest.param( "msedge", { "browser_type": "msedge", "display_name": "Microsoft Edge", "path": r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe", "version": ANY, }, marks=pytest.mark.skipif(sys.platform != "win32", reason="windows-only"), id="msedge-win32", ), pytest.param( "msie", { "browser_type": "msie", "display_name": "Internet Explorer", "path": r"C:\Program Files\Internet Explorer\iexplore.exe", "version": ANY, }, marks=pytest.mark.skipif(sys.platform != "win32", reason="windows-only"), id="msie-win32", ), ), ) def test_get(browser: str, details: Dict) -> None: assert browsers.get(browser) == details 07070100000017000081A4000000000000000000000001639CA56200000550000000000000000000000000000000000000002400000000browsers-0.5.2/tests/test_launch.pyimport sys from unittest import mock import pytest import browsers """ These tests are based on what browsers exists in Github Actions virtual environments. """ @pytest.mark.parametrize( "chrome_path", ( pytest.param( "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", id="osx", marks=pytest.mark.skipif(sys.platform != "darwin", reason="osx-only"), ), pytest.param( "/usr/bin/google-chrome-stable", id="linux", marks=pytest.mark.skipif(sys.platform != "linux", reason="linux-only"), ), pytest.param( r"C:\Program Files\Google\Chrome\Application\chrome.exe", id="windows", marks=pytest.mark.skipif(sys.platform != "win32", reason="windows-only"), ), ), ) @mock.patch.object(browsers, "_launch") def test_launch(mock_launch: mock.MagicMock, chrome_path: str) -> None: browsers.launch("chrome", url="https://github.com/roniemartinez/browsers") mock_launch.assert_called_with("chrome", chrome_path, [], "https://github.com/roniemartinez/browsers") @mock.patch.object(browsers, "_launch") def test_launch_no_browser(mock_launch: mock.MagicMock) -> None: browsers.launch("hello", url="https://github.com/roniemartinez/browsers") mock_launch.assert_not_called() 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!157 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor