pax_global_header 0000666 0000000 0000000 00000000064 14570505254 0014521 g ustar 00root root 0000000 0000000 52 comment=6ed7b6227c2cd0959340fda471147d7e8760eb92
browsers-0.6.0/ 0000775 0000000 0000000 00000000000 14570505254 0013372 5 ustar 00root root 0000000 0000000 browsers-0.6.0/.all-contributorsrc 0000664 0000000 0000000 00000001516 14570505254 0017226 0 ustar 00root root 0000000 0000000 {
"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"
}
browsers-0.6.0/.github/ 0000775 0000000 0000000 00000000000 14570505254 0014732 5 ustar 00root root 0000000 0000000 browsers-0.6.0/.github/dependabot.yml 0000664 0000000 0000000 00000001226 14570505254 0017563 0 ustar 00root root 0000000 0000000 # 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:
# Version updates for Python
- package-ecosystem: "pip"
directory: "/" # Location of package manifests
schedule:
interval: "daily"
# Version updates for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/" # Location of package manifests
schedule:
interval: "daily"
browsers-0.6.0/.github/workflows/ 0000775 0000000 0000000 00000000000 14570505254 0016767 5 ustar 00root root 0000000 0000000 browsers-0.6.0/.github/workflows/codeql-analysis.yml 0000664 0000000 0000000 00000004441 14570505254 0022605 0 ustar 00root root 0000000 0000000 # 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@v4
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
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@v3
# âšī¸ 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@v3
browsers-0.6.0/.github/workflows/pypi.yml 0000664 0000000 0000000 00000001357 14570505254 0020501 0 ustar 00root root 0000000 0000000 # 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@v4
- name: Set up Python
uses: actions/setup-python@v5
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
browsers-0.6.0/.github/workflows/python.yml 0000664 0000000 0000000 00000004413 14570505254 0021035 0 ustar 00root root 0000000 0000000 # 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.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@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- uses: actions/cache@v4
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@v4
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@v4
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@v4.0.1
if: ${{ success() }}
browsers-0.6.0/.github/workflows/testpypi.yml 0000664 0000000 0000000 00000001527 14570505254 0021400 0 ustar 00root root 0000000 0000000 # 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@v4
- name: Set up Python
uses: actions/setup-python@v5
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
browsers-0.6.0/.gitignore 0000664 0000000 0000000 00000004010 14570505254 0015355 0 ustar 00root root 0000000 0000000 ### 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/
browsers-0.6.0/LICENSE 0000664 0000000 0000000 00000002057 14570505254 0014403 0 ustar 00root root 0000000 0000000 MIT 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.
browsers-0.6.0/Makefile 0000664 0000000 0000000 00000001441 14570505254 0015032 0 ustar 00root root 0000000 0000000 .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 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";
browsers-0.6.0/README.md 0000664 0000000 0000000 00000014442 14570505254 0014656 0 ustar 00root root 0000000 0000000
License |
 |
Version |
 |
Github Actions |
 |
Coverage |
 |
Supported versions |
 |
Wheel |
 |
Status |
 |
Downloads |
 |
All Contributors |
 |
# 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 installed 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)):
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
browsers-0.6.0/browsers/ 0000775 0000000 0000000 00000000000 14570505254 0015240 5 ustar 00root root 0000000 0000000 browsers-0.6.0/browsers/__init__.py 0000664 0000000 0000000 00000005716 14570505254 0017362 0 ustar 00root root 0000000 0000000 import 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)
browsers-0.6.0/browsers/common.py 0000664 0000000 0000000 00000000204 14570505254 0017076 0 ustar 00root root 0000000 0000000 from typing import TypedDict
class Browser(TypedDict):
browser_type: str
path: str
display_name: str
version: str
browsers-0.6.0/browsers/linux.py 0000664 0000000 0000000 00000004076 14570505254 0016760 0 ustar 00root root 0000000 0000000 import 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
)
browsers-0.6.0/browsers/osx.py 0000664 0000000 0000000 00000004613 14570505254 0016427 0 ustar 00root root 0000000 0000000 import 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,
)
browsers-0.6.0/browsers/windows.py 0000664 0000000 0000000 00000005672 14570505254 0017316 0 ustar 00root root 0000000 0000000 import 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))))
browsers-0.6.0/poetry.lock 0000664 0000000 0000000 00000100344 14570505254 0015570 0 ustar 00root root 0000000 0000000 # This file is automatically @generated by Poetry 1.8.1 and should not be changed by hand.
[[package]]
name = "autoflake"
version = "2.3.0"
description = "Removes unused imports and unused variables"
optional = false
python-versions = ">=3.8"
files = [
{file = "autoflake-2.3.0-py3-none-any.whl", hash = "sha256:79a51eb8c0744759d2efe052455ab20aa6a314763510c3fd897499a402126327"},
{file = "autoflake-2.3.0.tar.gz", hash = "sha256:8c2011fa34701b9d7dcf05b9873bc4859d4fce4e62dfea90dffefd1576f5f01d"},
]
[package.dependencies]
pyflakes = ">=3.0.0"
tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""}
[[package]]
name = "black"
version = "24.2.0"
description = "The uncompromising code formatter."
optional = false
python-versions = ">=3.8"
files = [
{file = "black-24.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6981eae48b3b33399c8757036c7f5d48a535b962a7c2310d19361edeef64ce29"},
{file = "black-24.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d533d5e3259720fdbc1b37444491b024003e012c5173f7d06825a77508085430"},
{file = "black-24.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61a0391772490ddfb8a693c067df1ef5227257e72b0e4108482b8d41b5aee13f"},
{file = "black-24.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:992e451b04667116680cb88f63449267c13e1ad134f30087dec8527242e9862a"},
{file = "black-24.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:163baf4ef40e6897a2a9b83890e59141cc8c2a98f2dda5080dc15c00ee1e62cd"},
{file = "black-24.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e37c99f89929af50ffaf912454b3e3b47fd64109659026b678c091a4cd450fb2"},
{file = "black-24.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9de21bafcba9683853f6c96c2d515e364aee631b178eaa5145fc1c61a3cc92"},
{file = "black-24.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:9db528bccb9e8e20c08e716b3b09c6bdd64da0dd129b11e160bf082d4642ac23"},
{file = "black-24.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d84f29eb3ee44859052073b7636533ec995bd0f64e2fb43aeceefc70090e752b"},
{file = "black-24.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e08fb9a15c914b81dd734ddd7fb10513016e5ce7e6704bdd5e1251ceee51ac9"},
{file = "black-24.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:810d445ae6069ce64030c78ff6127cd9cd178a9ac3361435708b907d8a04c693"},
{file = "black-24.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ba15742a13de85e9b8f3239c8f807723991fbfae24bad92d34a2b12e81904982"},
{file = "black-24.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7e53a8c630f71db01b28cd9602a1ada68c937cbf2c333e6ed041390d6968faf4"},
{file = "black-24.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93601c2deb321b4bad8f95df408e3fb3943d85012dddb6121336b8e24a0d1218"},
{file = "black-24.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0057f800de6acc4407fe75bb147b0c2b5cbb7c3ed110d3e5999cd01184d53b0"},
{file = "black-24.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:faf2ee02e6612577ba0181f4347bcbcf591eb122f7841ae5ba233d12c39dcb4d"},
{file = "black-24.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:057c3dc602eaa6fdc451069bd027a1b2635028b575a6c3acfd63193ced20d9c8"},
{file = "black-24.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:08654d0797e65f2423f850fc8e16a0ce50925f9337fb4a4a176a7aa4026e63f8"},
{file = "black-24.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca610d29415ee1a30a3f30fab7a8f4144e9d34c89a235d81292a1edb2b55f540"},
{file = "black-24.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:4dd76e9468d5536abd40ffbc7a247f83b2324f0c050556d9c371c2b9a9a95e31"},
{file = "black-24.2.0-py3-none-any.whl", hash = "sha256:e8a6ae970537e67830776488bca52000eaa37fa63b9988e8c487458d9cd5ace6"},
{file = "black-24.2.0.tar.gz", hash = "sha256:bce4f25c27c3435e4dace4815bcb2008b87e167e3bf4ee47ccdc5ce906eb4894"},
]
[package.dependencies]
click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
packaging = ">=22.0"
pathspec = ">=0.9.0"
platformdirs = ">=2"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
[package.extras]
colorama = ["colorama (>=0.4.3)"]
d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "click"
version = "8.1.7"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
files = [
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
]
[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}
[[package]]
name = "colorama"
version = "0.4.6"
description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "coverage"
version = "7.4.3"
description = "Code coverage measurement for Python"
optional = false
python-versions = ">=3.8"
files = [
{file = "coverage-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8580b827d4746d47294c0e0b92854c85a92c2227927433998f0d3320ae8a71b6"},
{file = "coverage-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:718187eeb9849fc6cc23e0d9b092bc2348821c5e1a901c9f8975df0bc785bfd4"},
{file = "coverage-7.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:767b35c3a246bcb55b8044fd3a43b8cd553dd1f9f2c1eeb87a302b1f8daa0524"},
{file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae7f19afe0cce50039e2c782bff379c7e347cba335429678450b8fe81c4ef96d"},
{file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba3a8aaed13770e970b3df46980cb068d1c24af1a1968b7818b69af8c4347efb"},
{file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ee866acc0861caebb4f2ab79f0b94dbfbdbfadc19f82e6e9c93930f74e11d7a0"},
{file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:506edb1dd49e13a2d4cac6a5173317b82a23c9d6e8df63efb4f0380de0fbccbc"},
{file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd6545d97c98a192c5ac995d21c894b581f1fd14cf389be90724d21808b657e2"},
{file = "coverage-7.4.3-cp310-cp310-win32.whl", hash = "sha256:f6a09b360d67e589236a44f0c39218a8efba2593b6abdccc300a8862cffc2f94"},
{file = "coverage-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:18d90523ce7553dd0b7e23cbb28865db23cddfd683a38fb224115f7826de78d0"},
{file = "coverage-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbbe5e739d45a52f3200a771c6d2c7acf89eb2524890a4a3aa1a7fa0695d2a47"},
{file = "coverage-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:489763b2d037b164846ebac0cbd368b8a4ca56385c4090807ff9fad817de4113"},
{file = "coverage-7.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451f433ad901b3bb00184d83fd83d135fb682d780b38af7944c9faeecb1e0bfe"},
{file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcc66e222cf4c719fe7722a403888b1f5e1682d1679bd780e2b26c18bb648cdc"},
{file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ec74cfef2d985e145baae90d9b1b32f85e1741b04cd967aaf9cfa84c1334f3"},
{file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:abbbd8093c5229c72d4c2926afaee0e6e3140de69d5dcd918b2921f2f0c8baba"},
{file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:35eb581efdacf7b7422af677b92170da4ef34500467381e805944a3201df2079"},
{file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8249b1c7334be8f8c3abcaaa996e1e4927b0e5a23b65f5bf6cfe3180d8ca7840"},
{file = "coverage-7.4.3-cp311-cp311-win32.whl", hash = "sha256:cf30900aa1ba595312ae41978b95e256e419d8a823af79ce670835409fc02ad3"},
{file = "coverage-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:18c7320695c949de11a351742ee001849912fd57e62a706d83dfc1581897fa2e"},
{file = "coverage-7.4.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b51bfc348925e92a9bd9b2e48dad13431b57011fd1038f08316e6bf1df107d10"},
{file = "coverage-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d6cdecaedea1ea9e033d8adf6a0ab11107b49571bbb9737175444cea6eb72328"},
{file = "coverage-7.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b2eccb883368f9e972e216c7b4c7c06cabda925b5f06dde0650281cb7666a30"},
{file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c00cdc8fa4e50e1cc1f941a7f2e3e0f26cb2a1233c9696f26963ff58445bac7"},
{file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4a8dd3dcf4cbd3165737358e4d7dfbd9d59902ad11e3b15eebb6393b0446e"},
{file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:062b0a75d9261e2f9c6d071753f7eef0fc9caf3a2c82d36d76667ba7b6470003"},
{file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ebe7c9e67a2d15fa97b77ea6571ce5e1e1f6b0db71d1d5e96f8d2bf134303c1d"},
{file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0a120238dd71c68484f02562f6d446d736adcc6ca0993712289b102705a9a3a"},
{file = "coverage-7.4.3-cp312-cp312-win32.whl", hash = "sha256:37389611ba54fd6d278fde86eb2c013c8e50232e38f5c68235d09d0a3f8aa352"},
{file = "coverage-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:d25b937a5d9ffa857d41be042b4238dd61db888533b53bc76dc082cb5a15e914"},
{file = "coverage-7.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28ca2098939eabab044ad68850aac8f8db6bf0b29bc7f2887d05889b17346454"},
{file = "coverage-7.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:280459f0a03cecbe8800786cdc23067a8fc64c0bd51dc614008d9c36e1659d7e"},
{file = "coverage-7.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c0cdedd3500e0511eac1517bf560149764b7d8e65cb800d8bf1c63ebf39edd2"},
{file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a9babb9466fe1da12417a4aed923e90124a534736de6201794a3aea9d98484e"},
{file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dec9de46a33cf2dd87a5254af095a409ea3bf952d85ad339751e7de6d962cde6"},
{file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:16bae383a9cc5abab9bb05c10a3e5a52e0a788325dc9ba8499e821885928968c"},
{file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2c854ce44e1ee31bda4e318af1dbcfc929026d12c5ed030095ad98197eeeaed0"},
{file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ce8c50520f57ec57aa21a63ea4f325c7b657386b3f02ccaedeccf9ebe27686e1"},
{file = "coverage-7.4.3-cp38-cp38-win32.whl", hash = "sha256:708a3369dcf055c00ddeeaa2b20f0dd1ce664eeabde6623e516c5228b753654f"},
{file = "coverage-7.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:1bf25fbca0c8d121a3e92a2a0555c7e5bc981aee5c3fdaf4bb7809f410f696b9"},
{file = "coverage-7.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b253094dbe1b431d3a4ac2f053b6d7ede2664ac559705a704f621742e034f1f"},
{file = "coverage-7.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77fbfc5720cceac9c200054b9fab50cb2a7d79660609200ab83f5db96162d20c"},
{file = "coverage-7.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6679060424faa9c11808598504c3ab472de4531c571ab2befa32f4971835788e"},
{file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4af154d617c875b52651dd8dd17a31270c495082f3d55f6128e7629658d63765"},
{file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8640f1fde5e1b8e3439fe482cdc2b0bb6c329f4bb161927c28d2e8879c6029ee"},
{file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:69b9f6f66c0af29642e73a520b6fed25ff9fd69a25975ebe6acb297234eda501"},
{file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0842571634f39016a6c03e9d4aba502be652a6e4455fadb73cd3a3a49173e38f"},
{file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a78ed23b08e8ab524551f52953a8a05d61c3a760781762aac49f8de6eede8c45"},
{file = "coverage-7.4.3-cp39-cp39-win32.whl", hash = "sha256:c0524de3ff096e15fcbfe8f056fdb4ea0bf497d584454f344d59fce069d3e6e9"},
{file = "coverage-7.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:0209a6369ccce576b43bb227dc8322d8ef9e323d089c6f3f26a597b09cb4d2aa"},
{file = "coverage-7.4.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:7cbde573904625509a3f37b6fecea974e363460b556a627c60dc2f47e2fffa51"},
{file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"},
]
[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.2.0"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
files = [
{file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"},
{file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"},
]
[package.extras]
test = ["pytest (>=6)"]
[[package]]
name = "flake8"
version = "6.1.0"
description = "the modular source code checker: pep8 pyflakes and co"
optional = false
python-versions = ">=3.8.1"
files = [
{file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"},
{file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"},
]
[package.dependencies]
mccabe = ">=0.7.0,<0.8.0"
pycodestyle = ">=2.11.0,<2.12.0"
pyflakes = ">=3.1.0,<3.2.0"
[[package]]
name = "iniconfig"
version = "2.0.0"
description = "brain-dead simple config-ini parsing"
optional = false
python-versions = ">=3.7"
files = [
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
]
[[package]]
name = "isort"
version = "5.13.2"
description = "A Python utility / library to sort Python imports."
optional = false
python-versions = ">=3.8.0"
files = [
{file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
{file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
]
[package.extras]
colors = ["colorama (>=0.4.6)"]
[[package]]
name = "markdown-it-py"
version = "3.0.0"
description = "Python port of markdown-it. Markdown parsing, done right!"
optional = false
python-versions = ">=3.8"
files = [
{file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
{file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
]
[package.dependencies]
mdurl = ">=0.1,<1.0"
[package.extras]
benchmarking = ["psutil", "pytest", "pytest-benchmark"]
code-style = ["pre-commit (>=3.0,<4.0)"]
compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
linkify = ["linkify-it-py (>=1,<3)"]
plugins = ["mdit-py-plugins"]
profiling = ["gprof2dot"]
rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
[[package]]
name = "mccabe"
version = "0.7.0"
description = "McCabe checker, plugin for flake8"
optional = false
python-versions = ">=3.6"
files = [
{file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
]
[[package]]
name = "mdurl"
version = "0.1.2"
description = "Markdown URL utilities"
optional = false
python-versions = ">=3.7"
files = [
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
]
[[package]]
name = "mypy"
version = "1.8.0"
description = "Optional static typing for Python"
optional = false
python-versions = ">=3.8"
files = [
{file = "mypy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:485a8942f671120f76afffff70f259e1cd0f0cfe08f81c05d8816d958d4577d3"},
{file = "mypy-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:df9824ac11deaf007443e7ed2a4a26bebff98d2bc43c6da21b2b64185da011c4"},
{file = "mypy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afecd6354bbfb6e0160f4e4ad9ba6e4e003b767dd80d85516e71f2e955ab50d"},
{file = "mypy-1.8.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8963b83d53ee733a6e4196954502b33567ad07dfd74851f32be18eb932fb1cb9"},
{file = "mypy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:e46f44b54ebddbeedbd3d5b289a893219065ef805d95094d16a0af6630f5d410"},
{file = "mypy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:855fe27b80375e5c5878492f0729540db47b186509c98dae341254c8f45f42ae"},
{file = "mypy-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4c886c6cce2d070bd7df4ec4a05a13ee20c0aa60cb587e8d1265b6c03cf91da3"},
{file = "mypy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d19c413b3c07cbecf1f991e2221746b0d2a9410b59cb3f4fb9557f0365a1a817"},
{file = "mypy-1.8.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9261ed810972061388918c83c3f5cd46079d875026ba97380f3e3978a72f503d"},
{file = "mypy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:51720c776d148bad2372ca21ca29256ed483aa9a4cdefefcef49006dff2a6835"},
{file = "mypy-1.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:52825b01f5c4c1c4eb0db253ec09c7aa17e1a7304d247c48b6f3599ef40db8bd"},
{file = "mypy-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f5ac9a4eeb1ec0f1ccdc6f326bcdb464de5f80eb07fb38b5ddd7b0de6bc61e55"},
{file = "mypy-1.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afe3fe972c645b4632c563d3f3eff1cdca2fa058f730df2b93a35e3b0c538218"},
{file = "mypy-1.8.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:42c6680d256ab35637ef88891c6bd02514ccb7e1122133ac96055ff458f93fc3"},
{file = "mypy-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:720a5ca70e136b675af3af63db533c1c8c9181314d207568bbe79051f122669e"},
{file = "mypy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:028cf9f2cae89e202d7b6593cd98db6759379f17a319b5faf4f9978d7084cdc6"},
{file = "mypy-1.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4e6d97288757e1ddba10dd9549ac27982e3e74a49d8d0179fc14d4365c7add66"},
{file = "mypy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f1478736fcebb90f97e40aff11a5f253af890c845ee0c850fe80aa060a267c6"},
{file = "mypy-1.8.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42419861b43e6962a649068a61f4a4839205a3ef525b858377a960b9e2de6e0d"},
{file = "mypy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:2b5b6c721bd4aabaadead3a5e6fa85c11c6c795e0c81a7215776ef8afc66de02"},
{file = "mypy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c1538c38584029352878a0466f03a8ee7547d7bd9f641f57a0f3017a7c905b8"},
{file = "mypy-1.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ef4be7baf08a203170f29e89d79064463b7fc7a0908b9d0d5114e8009c3a259"},
{file = "mypy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7178def594014aa6c35a8ff411cf37d682f428b3b5617ca79029d8ae72f5402b"},
{file = "mypy-1.8.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ab3c84fa13c04aeeeabb2a7f67a25ef5d77ac9d6486ff33ded762ef353aa5592"},
{file = "mypy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:99b00bc72855812a60d253420d8a2eae839b0afa4938f09f4d2aa9bb4654263a"},
{file = "mypy-1.8.0-py3-none-any.whl", hash = "sha256:538fd81bb5e430cc1381a443971c0475582ff9f434c16cd46d2c66763ce85d9d"},
{file = "mypy-1.8.0.tar.gz", hash = "sha256:6ff8b244d7085a0b425b56d327b480c3b29cafbd2eff27316a004f9a7391ae07"},
]
[package.dependencies]
mypy-extensions = ">=1.0.0"
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
typing-extensions = ">=4.1.0"
[package.extras]
dmypy = ["psutil (>=4.0)"]
install-types = ["pip"]
mypyc = ["setuptools (>=50)"]
reports = ["lxml"]
[[package]]
name = "mypy-extensions"
version = "1.0.0"
description = "Type system extensions for programs checked with the mypy type checker."
optional = false
python-versions = ">=3.5"
files = [
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
]
[[package]]
name = "packaging"
version = "23.2"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.7"
files = [
{file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"},
{file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
]
[[package]]
name = "pathspec"
version = "0.12.1"
description = "Utility library for gitignore style pattern matching of file paths."
optional = false
python-versions = ">=3.8"
files = [
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
]
[[package]]
name = "platformdirs"
version = "4.2.0"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
optional = false
python-versions = ">=3.8"
files = [
{file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"},
{file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"},
]
[package.extras]
docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
[[package]]
name = "pluggy"
version = "1.4.0"
description = "plugin and hook calling mechanisms for python"
optional = false
python-versions = ">=3.8"
files = [
{file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"},
{file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"},
]
[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"
optional = false
python-versions = "*"
files = [
{file = "pprintpp-0.4.0-py2.py3-none-any.whl", hash = "sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d"},
{file = "pprintpp-0.4.0.tar.gz", hash = "sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403"},
]
[[package]]
name = "pycodestyle"
version = "2.11.1"
description = "Python style guide checker"
optional = false
python-versions = ">=3.8"
files = [
{file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"},
{file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"},
]
[[package]]
name = "pyflakes"
version = "3.1.0"
description = "passive checker of Python programs"
optional = false
python-versions = ">=3.8"
files = [
{file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"},
{file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"},
]
[[package]]
name = "pygments"
version = "2.17.2"
description = "Pygments is a syntax highlighting package written in Python."
optional = false
python-versions = ">=3.7"
files = [
{file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"},
{file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"},
]
[package.extras]
plugins = ["importlib-metadata"]
windows-terminal = ["colorama (>=0.4.6)"]
[[package]]
name = "pyproject-flake8"
version = "6.1.0"
description = "pyproject-flake8 (`pflake8`), a monkey patching wrapper to connect flake8 with pyproject.toml configuration"
optional = false
python-versions = ">=3.8.1"
files = [
{file = "pyproject_flake8-6.1.0-py3-none-any.whl", hash = "sha256:86ea5559263c098e1aa4f866776aa2cf45362fd91a576b9fd8fbbbb55db12c4e"},
{file = "pyproject_flake8-6.1.0.tar.gz", hash = "sha256:6da8e5a264395e0148bc11844c6fb50546f1fac83ac9210f7328664135f9e70f"},
]
[package.dependencies]
flake8 = "6.1.0"
tomli = {version = "*", markers = "python_version < \"3.11\""}
[[package]]
name = "pytest"
version = "8.0.2"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.8"
files = [
{file = "pytest-8.0.2-py3-none-any.whl", hash = "sha256:edfaaef32ce5172d5466b5127b42e0d6d35ebbe4453f0e3505d96afd93f6b096"},
{file = "pytest-8.0.2.tar.gz", hash = "sha256:d4051d623a2e0b7e51960ba963193b09ce6daeb9759a451844a21e4ddedfc1bd"},
]
[package.dependencies]
colorama = {version = "*", markers = "sys_platform == \"win32\""}
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
iniconfig = "*"
packaging = "*"
pluggy = ">=1.3.0,<2.0"
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
[package.extras]
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
[[package]]
name = "pytest-clarity"
version = "1.0.1"
description = "A plugin providing an alternative, colourful diff output for failing assertions."
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [
{file = "pytest-clarity-1.0.1.tar.gz", hash = "sha256:505fe345fad4fe11c6a4187fe683f2c7c52c077caa1e135f3e483fe112db7772"},
]
[package.dependencies]
pprintpp = ">=0.4.0"
pytest = ">=3.5.0"
rich = ">=8.0.0"
[[package]]
name = "pytest-cov"
version = "4.1.0"
description = "Pytest plugin for measuring coverage."
optional = false
python-versions = ">=3.7"
files = [
{file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"},
{file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"},
]
[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 = "306"
description = "Python for Window Extensions"
optional = false
python-versions = "*"
files = [
{file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"},
{file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"},
{file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"},
{file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"},
{file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"},
{file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"},
{file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"},
{file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"},
{file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"},
{file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"},
{file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"},
{file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"},
{file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"},
{file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"},
]
[[package]]
name = "pyxdg"
version = "0.28"
description = "PyXDG contains implementations of freedesktop.org standards in python."
optional = false
python-versions = "*"
files = [
{file = "pyxdg-0.28-py2.py3-none-any.whl", hash = "sha256:bdaf595999a0178ecea4052b7f4195569c1ff4d344567bccdc12dfdf02d545ab"},
{file = "pyxdg-0.28.tar.gz", hash = "sha256:3267bb3074e934df202af2ee0868575484108581e6f3cb006af1da35395e88b4"},
]
[[package]]
name = "rich"
version = "13.7.1"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
optional = false
python-versions = ">=3.7.0"
files = [
{file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"},
{file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"},
]
[package.dependencies]
markdown-it-py = ">=2.2.0"
pygments = ">=2.13.0,<3.0.0"
typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""}
[package.extras]
jupyter = ["ipywidgets (>=7.5.1,<9)"]
[[package]]
name = "tomli"
version = "2.0.1"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.7"
files = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]
[[package]]
name = "typing-extensions"
version = "4.10.0"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
files = [
{file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"},
{file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"},
]
[metadata]
lock-version = "2.0"
python-versions = "^3.8.1"
content-hash = "29b9b982b70a7b201bf69df2eff965bd89cb55500874ad79d8524e7624c8c559"
browsers-0.6.0/pyproject.toml 0000664 0000000 0000000 00000004243 14570505254 0016311 0 ustar 00root root 0000000 0000000 [tool.poetry]
name = "pybrowsers"
version = "0.6.0"
repository = "https://github.com/roniemartinez/browsers"
description = "Python library for detecting and launching browsers"
authors = ["Ronie Martinez "]
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.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.8.1"
pywin32 = { version = ">=303,<307", markers = "sys_platform == 'win32'" }
pyxdg = { version = ">=0.27,<0.29", markers = "sys_platform == 'linux'" }
[tool.poetry.group.dev.dependencies]
autoflake = "^2.3.0"
black = "^24.2.0"
isort = "^5.11.5"
mypy = "^1.4"
pyproject-flake8 = "^6.1.0"
pytest = "^8.0.2"
pytest-clarity = "^1.0.1"
pytest-cov = "^4.1.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"
browsers-0.6.0/tests/ 0000775 0000000 0000000 00000000000 14570505254 0014534 5 ustar 00root root 0000000 0000000 browsers-0.6.0/tests/__init__.py 0000664 0000000 0000000 00000000000 14570505254 0016633 0 ustar 00root root 0000000 0000000 browsers-0.6.0/tests/test_detect.py 0000664 0000000 0000000 00000011566 14570505254 0017426 0 ustar 00root root 0000000 0000000 import 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
browsers-0.6.0/tests/test_launch.py 0000664 0000000 0000000 00000002520 14570505254 0017416 0 ustar 00root root 0000000 0000000 import 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()