Compare commits
3 commits
97db0946da
...
bdedba8d11
Author | SHA1 | Date | |
---|---|---|---|
|
bdedba8d11 | ||
|
146cd71281 | ||
|
81a5e66b60 |
13 changed files with 215 additions and 36 deletions
47
.github/workflows/test.yml
vendored
Normal file
47
.github/workflows/test.yml
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
name: test
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
ci:
|
||||
name: Python-${{ matrix.python }} ${{ matrix.qt.qt_api }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
qt:
|
||||
- package: PyQt5
|
||||
qt_api: "pyqt5"
|
||||
- package: PyQt6
|
||||
qt_api: "pyqt6"
|
||||
- package: PySide2
|
||||
qt_api: "pyside2"
|
||||
- package: PySide6
|
||||
qt_api: "pyside6"
|
||||
python: [3.6, 3.7, 3.8, 3.9]
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python }}
|
||||
architecture: x64
|
||||
- name: Install pipenv
|
||||
run: |
|
||||
python -m pip install --upgrade pipenv wheel
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
pipenv install --dev
|
||||
pipenv run pip install ${{ matrix.qt.package }} pytest
|
||||
- name: Install Libxcb dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install '^libxcb.*-dev' libx11-xcb-dev libglu1-mesa-dev libxrender-dev libxi-dev libxkbcommon-dev libxkbcommon-x11-dev
|
||||
- name: Run headless test
|
||||
uses: GabrielBB/xvfb-action@v1
|
||||
env:
|
||||
QT_API: ${{ matrix.qt.qt_api }}
|
||||
with:
|
||||
run: pipenv run py.test --forked -v
|
16
Pipfile
Normal file
16
Pipfile
Normal file
|
@ -0,0 +1,16 @@
|
|||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
name = "pypi"
|
||||
verify_ssl = true
|
||||
|
||||
[dev-packages]
|
||||
atomicwrites = "*"
|
||||
pytest = "*"
|
||||
pytest-forked = "*"
|
||||
pytest-raises = "*"
|
||||
|
||||
[packages]
|
||||
|
||||
[dev-packages.phantomjs]
|
||||
editable = true
|
||||
path = "."
|
22
appveyor.yml
Normal file
22
appveyor.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
environment:
|
||||
matrix:
|
||||
- PYTHON: "C:\\Python36"
|
||||
- PYTHON: "C:\\Python37"
|
||||
- PYTHON: "C:\\Python38"
|
||||
- PYTHON: "C:\\Python39"
|
||||
|
||||
init:
|
||||
- set PATH=%PYTHON%;%PYTHON%\Scripts;%PATH%
|
||||
|
||||
install:
|
||||
- pip install pipenv
|
||||
- pipenv install --dev
|
||||
- pipenv run pip install PyQt5 PySide2
|
||||
# FIX: colorama not installed by pipenv
|
||||
- pipenv run pip install colorama
|
||||
|
||||
build: off
|
||||
|
||||
test_script:
|
||||
- set QT_API=PyQt5&& pipenv run py.test -v
|
||||
- set QT_API=PySide2&& pipenv run py.test -v
|
3
phantompy/__init__.py
Normal file
3
phantompy/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
# -*-mode: python; indent-tabs-mode: nil; py-indent-offset: 2; coding: utf-8 -*-
|
||||
|
||||
__version__ = "0.1.0"
|
|
@ -1,10 +1,13 @@
|
|||
#!/usr/local/bin/python3.sh
|
||||
# -*-mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*
|
||||
|
||||
from qasync_phantompy import iMain
|
||||
from __future__ import absolute_import
|
||||
import sys
|
||||
|
||||
from .qasync_phantompy import iMain
|
||||
|
||||
try:
|
||||
from support_phantompy import vsetup_logging
|
||||
from .support_phantompy import vsetup_logging
|
||||
d = int(os.environ.get('DEBUG', 0))
|
||||
if d > 0:
|
||||
vsetup_logging(10, stream=sys.stderr)
|
||||
|
@ -14,4 +17,4 @@ try:
|
|||
except: pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
iMain(sys.argv[1:], bgui=False)
|
||||
iMain(sys.argv[1:])
|
|
@ -118,21 +118,20 @@ 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.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import importlib
|
||||
import os
|
||||
import traceback
|
||||
import atexit
|
||||
import time
|
||||
import sys # noqa
|
||||
|
||||
from PyQt5.QtCore import QUrl
|
||||
from PyQt5.QtCore import QTimer
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
from PyQt5.QtPrintSupport import QPrinter
|
||||
from PyQt5.QtWebEngineWidgets import QWebEnginePage
|
||||
from qasync import QtModuleName
|
||||
from qasync.QtCore import QUrl
|
||||
|
||||
QPrinter = importlib.import_module(QtModuleName + ".QtPrintSupport.QPrinter", package=QtModuleName)
|
||||
QWebEnginePage = importlib.import_module(QtModuleName + ".QtWebEngineWidgets.QWebEnginePage", package=QtModuleName)
|
||||
|
||||
global LOG
|
||||
import logging
|
||||
import warnings
|
||||
|
||||
warnings.filterwarnings('ignore')
|
||||
LOG = logging.getLogger()
|
||||
|
||||
|
@ -181,19 +180,19 @@ class Render(QWebEnginePage):
|
|||
self.htmlfile = htmlfile
|
||||
self.pdffile = pdffile
|
||||
self.outfile = pdffile or htmlfile
|
||||
LOG.debug(f"phantom.py: URL={url} OUTFILE={outfile} JSFILE={jsfile}")
|
||||
LOG.debug(f"phantom.py: URL={url} htmlfile={htmlfile} pdffile={pdffile} JSFILE={jsfile}")
|
||||
qurl = QUrl.fromUserInput(url)
|
||||
|
||||
# The PDF generation only happens when the special string __PHANTOM_PY_DONE__
|
||||
# is sent to console.log(). The following JS string will be executed by
|
||||
# default, when no external JavaScript file is specified.
|
||||
self.js_contents = "setTimeout(function() { console.log('__PHANTOM_PY_DONE__') }, 5000);";
|
||||
self.js_contents = "setTimeout(function() { console.log('__PHANTOM_PY_DONE__') }, 5000);"
|
||||
|
||||
if jsfile:
|
||||
try:
|
||||
with open(self.jsfile, 'rt') as f:
|
||||
self.js_contents = f.read()
|
||||
except Exception as e:
|
||||
except Exception as e: # noqa
|
||||
LOG.exception(f"error reading jsfile {self.jsfile}")
|
||||
|
||||
self.loadFinished.connect(self._loadFinished)
|
||||
|
@ -239,7 +238,7 @@ class Render(QWebEnginePage):
|
|||
"""print(self, QPrinter, Callable[[bool], None])"""
|
||||
if type(args[0]) is str:
|
||||
self._save(args[0])
|
||||
self._onConsoleMessage(0, "__PHANTOM_PY_SAVED__", 0 , '')
|
||||
self._onConsoleMessage(0, "__PHANTOM_PY_SAVED__", 0, '')
|
||||
|
||||
def _save(self, html):
|
||||
sfile = self.htmlfile
|
||||
|
@ -254,7 +253,7 @@ class Render(QWebEnginePage):
|
|||
i = 1
|
||||
else:
|
||||
i = 0
|
||||
self._onConsoleMessage(i, "__PHANTOM_PY_PRINTED__", 0 , '')
|
||||
self._onConsoleMessage(i, "__PHANTOM_PY_PRINTED__", 0, '')
|
||||
|
||||
def _print(self):
|
||||
sfile = self.pdffile
|
||||
|
@ -262,7 +261,7 @@ class Render(QWebEnginePage):
|
|||
printer.setPageMargins(10, 10, 10, 10, QPrinter.Millimeter)
|
||||
printer.setPaperSize(QPrinter.A4)
|
||||
printer.setCreator("phantom.py by Michael Karl Franzl")
|
||||
printer.setOutputFormat(QPrinter.PdfFormat);
|
||||
printer.setOutputFormat(QPrinter.PdfFormat)
|
||||
printer.setOutputFileName(sfile)
|
||||
self.print(printer, self._printer_callback)
|
||||
LOG.debug("phantom.py: Printed")
|
||||
|
@ -272,4 +271,3 @@ class Render(QWebEnginePage):
|
|||
LOG.debug(f"phantom.py: Exiting with val {val}")
|
||||
# threadsafe?
|
||||
self._app.ldone.append(self.uri)
|
||||
|
|
@ -1,26 +1,30 @@
|
|||
#!/usr/local/bin/python3.sh
|
||||
# -*-mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*
|
||||
|
||||
import sys
|
||||
import os
|
||||
import asyncio
|
||||
import time
|
||||
import random
|
||||
import os
|
||||
import sys
|
||||
|
||||
# let qasync figure out what Qt we are using - we dont care
|
||||
from qasync import QApplication, QtWidgets, QEventLoop
|
||||
from qasync import QApplication, QEventLoop, QtWidgets
|
||||
|
||||
from phantompy import Render
|
||||
# if you want an example of looking for things in downloaded HTML:
|
||||
# from lookupdns import LookFor as Render
|
||||
from support_phantompy import vsetup_logging, omain_argparser
|
||||
from support_phantompy import omain_argparser, vsetup_logging
|
||||
|
||||
global LOG
|
||||
import logging
|
||||
import warnings
|
||||
|
||||
warnings.filterwarnings('ignore')
|
||||
LOG = logging.getLogger()
|
||||
|
||||
try:
|
||||
import shtab
|
||||
except:
|
||||
shtab = None
|
||||
|
||||
class Widget(QtWidgets.QWidget):
|
||||
def __init__(self):
|
||||
QtWidgets.QWidget.__init__(self)
|
||||
|
@ -38,13 +42,17 @@ class Widget(QtWidgets.QWidget):
|
|||
self.progress.setValue(int(text))
|
||||
|
||||
class ContextManager:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._seconds = 0
|
||||
|
||||
async def __aenter__(self):
|
||||
LOG.debug("ContextManager enter")
|
||||
return self
|
||||
|
||||
async def __aexit__(self, *args):
|
||||
LOG.debug("ContextManager exit")
|
||||
|
||||
async def tick(self):
|
||||
await asyncio.sleep(1)
|
||||
self._seconds += 1
|
||||
|
@ -65,13 +73,15 @@ async def main(widget, app, ilen):
|
|||
# raise asyncio.CancelledError
|
||||
return
|
||||
LOG.debug(f"{app.ldone} {seconds}")
|
||||
except asyncio.CancelledError as ex:
|
||||
except asyncio.CancelledError as ex: # noqa
|
||||
LOG.debug("Task cancelled")
|
||||
|
||||
def iMain(largs):
|
||||
parser = omain_argparser()
|
||||
if shtab:
|
||||
shtab.add_argument_to(parser, ["-s", "--print-completion"]) # magic!
|
||||
oargs = parser.parse_args(largs)
|
||||
bgui=oargs.show_gui
|
||||
bgui = oargs.show_gui
|
||||
|
||||
try:
|
||||
d = int(os.environ.get('DEBUG', 0))
|
||||
|
@ -115,6 +125,4 @@ def iMain(largs):
|
|||
loop.run_until_complete(asyncio.gather(*tasks))
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
iMain(sys.argv[1:])
|
||||
|
|
@ -1,21 +1,22 @@
|
|||
#!/usr/local/bin/python3.sh
|
||||
# -*-mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*
|
||||
|
||||
import sys
|
||||
import os
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
try:
|
||||
if 'COLOREDLOGS_LEVEL_STYLES' not in os.environ:
|
||||
os.environ['COLOREDLOGS_LEVEL_STYLES'] = 'spam=22;debug=28;verbose=34;notice=220;warning=202;success=118,bold;error=124;critical=background=red'
|
||||
# https://pypi.org/project/coloredlogs/
|
||||
import coloredlogs
|
||||
except ImportError as e:
|
||||
except ImportError:
|
||||
coloredlogs = False
|
||||
|
||||
global LOG
|
||||
import logging
|
||||
import warnings
|
||||
|
||||
warnings.filterwarnings('ignore')
|
||||
LOG = logging.getLogger()
|
||||
|
||||
|
@ -24,7 +25,7 @@ def vsetup_logging(log_level, logfile='', stream=sys.stdout):
|
|||
add = True
|
||||
|
||||
# stem fucks up logging
|
||||
from stem.util import log
|
||||
# from stem.util import log
|
||||
logging.getLogger('stem').setLevel(30)
|
||||
|
||||
logging._defaultFormatter = logging.Formatter(datefmt='%m-%d %H:%M:%S')
|
57
setup.cfg
Normal file
57
setup.cfg
Normal file
|
@ -0,0 +1,57 @@
|
|||
[metadata]
|
||||
classifiers =
|
||||
License :: OSI Approved
|
||||
License :: OSI Approved :: BSD 1-clause
|
||||
Intended Audience :: Web Developers
|
||||
Operating System :: Microsoft :: Windows
|
||||
Operating System :: POSIX :: BSD :: FreeBSD
|
||||
Operating System :: POSIX :: Linux
|
||||
Programming Language :: Python :: 3 :: Only
|
||||
Programming Language :: Python :: 3.6
|
||||
Programming Language :: Python :: 3.7
|
||||
Programming Language :: Python :: 3.8
|
||||
Programming Language :: Python :: 3.9
|
||||
Programming Language :: Python :: Implementation :: CPython
|
||||
Framework :: AsyncIO
|
||||
|
||||
[options]
|
||||
zip_safe = false
|
||||
python_requires = ~=3.6
|
||||
packages = find:
|
||||
include_package_data = false
|
||||
install_requires =
|
||||
qasync
|
||||
attrs
|
||||
typing-extensions ; python_version < '3.8'
|
||||
|
||||
[options.entry_points]
|
||||
console_scripts =
|
||||
phantompy = phantompy.__main__:iMain
|
||||
|
||||
[easy_install]
|
||||
zip_ok = false
|
||||
|
||||
[flake8]
|
||||
jobs = 1
|
||||
max-line-length = 88
|
||||
ignore =
|
||||
E111
|
||||
E114
|
||||
E128
|
||||
E225
|
||||
E225
|
||||
E261
|
||||
E302
|
||||
E305
|
||||
E402
|
||||
E501
|
||||
E502
|
||||
E541
|
||||
E701
|
||||
E704
|
||||
E722
|
||||
E741
|
||||
F508
|
||||
F541
|
||||
W503
|
||||
|
8
setup.py
8
setup.py
|
@ -1,8 +1,10 @@
|
|||
# -*-mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*
|
||||
|
||||
import re
|
||||
from setuptools import setup
|
||||
|
||||
__version__ = "0.1.0"
|
||||
with open("qasync/__init__.py") as f:
|
||||
version = re.search(r'__version__\s+=\s+"(.*)"', f.read()).group(1)
|
||||
|
||||
long_description = "\n\n".join([
|
||||
open("README.md").read(),
|
||||
|
@ -20,9 +22,9 @@ if __name__ == '__main__':
|
|||
packages=['phantompy'],
|
||||
# url="",
|
||||
# download_url="https://",
|
||||
keywords=['JavaScript', 'phantomjs'],
|
||||
keywords=['JavaScript', 'phantomjs', 'asyncio'],
|
||||
# maybe less - nothing fancy
|
||||
python_requires=">=3.6",
|
||||
python_requires="~=3.6",
|
||||
# probably works on PyQt6 and PySide2 but untested
|
||||
# https://github.com/CabbageDevelopment/qasync/
|
||||
install_requires=['qasync', 'PyQt5'],
|
||||
|
|
22
tests/conftest.py
Normal file
22
tests/conftest.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
# -*- mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*-
|
||||
|
||||
# (c) 2018 Gerard Marull-Paretas <gerard@teslabs.com>
|
||||
# (c) 2014 Mark Harviston <mark.harviston@gmail.com>
|
||||
# (c) 2014 Arve Knudsen <arve.knudsen@gmail.com>
|
||||
# BSD License
|
||||
|
||||
# phantompy test - just test qasync for now
|
||||
|
||||
import os
|
||||
import logging
|
||||
from pytest import fixture
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG, format="%(asctime)s - %(levelname)s - %(name)s - %(message)s"
|
||||
)
|
||||
|
||||
@fixture(scope="session")
|
||||
def application():
|
||||
from phantompy.qasync_phantompy import QApplication
|
||||
|
||||
return QApplication([])
|
Loading…
Reference in a new issue