update
This commit is contained in:
parent
3b623d4fdf
commit
383764fca2
9 changed files with 306 additions and 37 deletions
36
Makefile
Normal file
36
Makefile
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# to run the tests, run make PASS=controllerpassword test
|
||||||
|
|
||||||
|
PREFIX=/usr/local
|
||||||
|
PYTHON_EXE_MSYS=${PREFIX}/bin/python3.sh
|
||||||
|
PIP_EXE_MSYS=${PREFIX}/bin/pip3.sh
|
||||||
|
LOCAL_DOCTEST=${PREFIX}/bin/toxcore_run_doctest3.bash
|
||||||
|
DOCTEST=${LOCAL_DOCTEST}
|
||||||
|
MOD=phantompy
|
||||||
|
|
||||||
|
check::
|
||||||
|
sh ${PYTHON_EXE_MSYS} -c "import ${MOD}"
|
||||||
|
|
||||||
|
lint::
|
||||||
|
sh .pylint.sh
|
||||||
|
|
||||||
|
install::
|
||||||
|
PYTHONPATH=${PWD}/src \
|
||||||
|
${PIP_EXE_MSYS} install --target ${PREFIX}/lib/python3.11/site-packages/ --upgrade .
|
||||||
|
|
||||||
|
rsync::
|
||||||
|
bash .rsync.sh
|
||||||
|
|
||||||
|
install::
|
||||||
|
PYTHONPATH=${PWD}/src \
|
||||||
|
${PIP_EXE_MSYS} --timeout=30 --disable-pip-version-check --proxy http://127.0.0.1:9128 install --only-binary :none: --progress-bar=off --target /usr/local/lib/python3.11/site-packages --upgrade .
|
||||||
|
|
||||||
|
# execute these tests as: make test PASS=password
|
||||||
|
test::
|
||||||
|
|
||||||
|
doctest:
|
||||||
|
|
||||||
|
veryclean:: clean
|
||||||
|
rm -rf build dist __pycache__ .pylint.err .pylint.out
|
||||||
|
|
||||||
|
clean::
|
||||||
|
find . -name \*~ -delete
|
16
Pipfile
16
Pipfile
|
@ -1,16 +0,0 @@
|
||||||
[[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 = "."
|
|
|
@ -1,32 +1,33 @@
|
||||||
[project]
|
[project]
|
||||||
name = "phantompy"
|
name = "phantompy"
|
||||||
description = "Set the ExcludeNodes or ExcludeExitNodes setting of a running Tor."
|
description = "A simple replacement for phantomjs using PyQt"
|
||||||
authors = [{ name = "emdee", email = "emdee@spm.plastiras.org" } ]
|
authors = [{ name = "emdee", email = "emdee@spm.plastiras.org" } ]
|
||||||
requires-python = ">=3.6"
|
requires-python = ">=3.8"
|
||||||
keywords = ["tor", "python3", "bad exits"]
|
dependencies = [
|
||||||
|
'qasync',
|
||||||
|
# PyQt5 PyQt6
|
||||||
|
]
|
||||||
|
keywords = ["phantomjs", "python3", "qasync"]
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"License :: OSI Approved",
|
"License :: OSI Approved",
|
||||||
"Operating System :: POSIX :: BSD :: FreeBSD",
|
"Operating System :: POSIX :: BSD :: FreeBSD",
|
||||||
"Operating System :: POSIX :: Linux",
|
"Operating System :: POSIX :: Linux",
|
||||||
"Programming Language :: Python :: 3 :: Only",
|
"Programming Language :: Python :: 3 :: Only",
|
||||||
"Programming Language :: Python :: 3.6",
|
|
||||||
"Programming Language :: Python :: 3.7",
|
|
||||||
"Programming Language :: Python :: 3.8",
|
"Programming Language :: Python :: 3.8",
|
||||||
"Programming Language :: Python :: 3.9",
|
"Programming Language :: Python :: 3.9",
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
|
"Classifier: Topic :: Software Development :: Libraries :: Python Modules",
|
||||||
]
|
]
|
||||||
|
#
|
||||||
dynamic = ["version", "readme", ] # cannot be dynamic ['license']
|
dynamic = ["version", "readme", ] # cannot be dynamic ['license']
|
||||||
scripts = { phantompy = "phantompy.phantompy:iMain" }
|
|
||||||
dependencies = ['qasync', 'PyQt5']
|
|
||||||
|
|
||||||
[tool.setuptools.dynamic]
|
[project.scripts]
|
||||||
version = {attr = "phantompy.__version__"}
|
phantompy = "phantompy.qasync_phantompy:iMain"
|
||||||
readme = {file = ["README.md"]}
|
|
||||||
|
|
||||||
[project.license]
|
#[project.license]
|
||||||
file = "LICENSE.md"
|
#file = "LICENSE.md"
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
repository = "https://git.plastiras.org/emdee/phantompy"
|
repository = "https://git.plastiras.org/emdee/phantompy"
|
||||||
|
@ -35,9 +36,12 @@ repository = "https://git.plastiras.org/emdee/phantompy"
|
||||||
requires = ["setuptools >= 61.0"]
|
requires = ["setuptools >= 61.0"]
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
# Either or both of these don't work
|
[tool.setuptools.dynamic]
|
||||||
#[tool.setuptools]
|
version = {attr = "phantompy.__version__"}
|
||||||
#packages = ["phantompy"]
|
readme = {file = ["README.md"]}
|
||||||
|
|
||||||
|
[tool.setuptools]
|
||||||
|
packages = ["phantompy"]
|
||||||
|
|
||||||
#[tool.setuptools.packages.find]
|
#[tool.setuptools.packages.find]
|
||||||
#include = ["src"]
|
#where = "src"
|
||||||
|
|
15
setup.cfg
15
setup.cfg
|
@ -11,19 +11,26 @@ classifiers =
|
||||||
Programming Language :: Python :: 3.7
|
Programming Language :: Python :: 3.7
|
||||||
Programming Language :: Python :: 3.8
|
Programming Language :: Python :: 3.8
|
||||||
Programming Language :: Python :: 3.9
|
Programming Language :: Python :: 3.9
|
||||||
|
Programming Language :: Python :: 3.10
|
||||||
|
Programming Language :: Python :: 3.11
|
||||||
Programming Language :: Python :: Implementation :: CPython
|
Programming Language :: Python :: Implementation :: CPython
|
||||||
Framework :: AsyncIO
|
Framework :: AsyncIO
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
zip_safe = false
|
zip_safe = false
|
||||||
python_requires = ~=3.6
|
python_requires = ~=3.8
|
||||||
packages = find:
|
|
||||||
include_package_data = false
|
include_package_data = false
|
||||||
install_requires =
|
install_requires =
|
||||||
qasync
|
qasync
|
||||||
cryptography
|
cryptography
|
||||||
rsa
|
rsa
|
||||||
stem
|
stem
|
||||||
|
package_dir=
|
||||||
|
=src
|
||||||
|
packages=find:
|
||||||
|
|
||||||
|
[options.packages.find]
|
||||||
|
where=src
|
||||||
|
|
||||||
[options.entry_points]
|
[options.entry_points]
|
||||||
console_scripts =
|
console_scripts =
|
||||||
|
@ -40,7 +47,6 @@ ignore =
|
||||||
E114
|
E114
|
||||||
E128
|
E128
|
||||||
E225
|
E225
|
||||||
E225
|
|
||||||
E261
|
E261
|
||||||
E302
|
E302
|
||||||
E305
|
E305
|
||||||
|
@ -49,10 +55,11 @@ ignore =
|
||||||
E502
|
E502
|
||||||
E541
|
E541
|
||||||
E701
|
E701
|
||||||
|
E702
|
||||||
E704
|
E704
|
||||||
E722
|
E722
|
||||||
E741
|
E741
|
||||||
F508
|
F508
|
||||||
F541
|
F541
|
||||||
W503
|
W503
|
||||||
|
W601
|
||||||
|
|
44
setup.py
Normal file
44
setup.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
# -*-mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*
|
||||||
|
|
||||||
|
import re
|
||||||
|
from setuptools import setup
|
||||||
|
|
||||||
|
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(),
|
||||||
|
])
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
setup(
|
||||||
|
name="phantompy",
|
||||||
|
version=__version__,
|
||||||
|
description="""A simple replacement for phantomjs using PyQt""",
|
||||||
|
long_description=long_description,
|
||||||
|
author="Michael Franzl (originally)",
|
||||||
|
author_email='',
|
||||||
|
license="1clause BSD",
|
||||||
|
packages=['phantompy'],
|
||||||
|
# url="",
|
||||||
|
# download_url="https://",
|
||||||
|
keywords=['JavaScript', 'phantomjs', 'asyncio'],
|
||||||
|
# maybe less - nothing fancy
|
||||||
|
python_requires="~=3.6",
|
||||||
|
# probably works on PyQt6 and PySide2 but untested
|
||||||
|
# https://github.com/CabbageDevelopment/qasync/
|
||||||
|
install_requires=['qasync',
|
||||||
|
'PyQt5'],
|
||||||
|
entry_points={
|
||||||
|
'console_scripts': ['phantompy = phantompy.__main__:iMain', ]},
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 4 - Beta',
|
||||||
|
'Environment :: Console',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'Intended Audience :: Web Developers',
|
||||||
|
'Natural Language :: English',
|
||||||
|
'Operating System :: OS Independent',
|
||||||
|
'Programming Language :: Python :: 3',
|
||||||
|
'Topic :: Software Development :: Documentation',
|
||||||
|
],
|
||||||
|
)
|
0
src/__init__.py
Normal file
0
src/__init__.py
Normal file
|
@ -122,7 +122,9 @@ import importlib
|
||||||
import os
|
import os
|
||||||
import sys # noqa
|
import sys # noqa
|
||||||
|
|
||||||
from qasync import QtModuleName
|
QtModuleName = os.environ.get('QT_API')
|
||||||
|
if not QtModuleName:
|
||||||
|
from qasync import QtModuleName
|
||||||
from qasync.QtCore import QUrl
|
from qasync.QtCore import QUrl
|
||||||
|
|
||||||
QPrinter = importlib.import_module(QtModuleName + ".QtPrintSupport.QPrinter", package=QtModuleName)
|
QPrinter = importlib.import_module(QtModuleName + ".QtPrintSupport.QPrinter", package=QtModuleName)
|
||||||
|
|
143
src/phantompy/qasync_readme.py
Normal file
143
src/phantompy/qasync_readme.py
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
#!/usr/local/bin/python3.sh
|
||||||
|
# -*-mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import atexit
|
||||||
|
import traceback
|
||||||
|
import functools
|
||||||
|
import asyncio
|
||||||
|
import time
|
||||||
|
import qasync
|
||||||
|
import threading
|
||||||
|
|
||||||
|
QtModuleName = os.environ.get('QT_API')
|
||||||
|
if not QtModuleName:
|
||||||
|
from qasync import QtModuleName
|
||||||
|
QtWidgets = importlib.import_module(QtModuleName + ".QtWidgets", package=QtModuleName)
|
||||||
|
# from PyQt5.QtWidgets import (QProgressBar, QWidget, QVBoxLayout)
|
||||||
|
from qasync import QEventLoop, QThreadExecutor
|
||||||
|
from qasync import asyncSlot, asyncClose, QApplication
|
||||||
|
|
||||||
|
from phantompy import Render
|
||||||
|
from lookupdns import LookFor
|
||||||
|
|
||||||
|
global LOG
|
||||||
|
import logging
|
||||||
|
import warnings
|
||||||
|
warnings.filterwarnings('ignore')
|
||||||
|
LOG = logging.getLogger()
|
||||||
|
|
||||||
|
class MainWindow(QWidget.QWidget):
|
||||||
|
"""Main window."""
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.setLayout(QVBoxLayout.QVBoxLayout())
|
||||||
|
self.progress = QtWidgets.QProgressBar()
|
||||||
|
self.progress.setRange(0, 99)
|
||||||
|
self.layout().addWidget(self.progress)
|
||||||
|
|
||||||
|
async def main(app):
|
||||||
|
def close_future(future, loop):
|
||||||
|
loop.call_later(10, future.cancel)
|
||||||
|
future.cancel()
|
||||||
|
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
future = asyncio.Future()
|
||||||
|
app.ldone = []
|
||||||
|
|
||||||
|
getattr(app, "aboutToQuit").connect(
|
||||||
|
functools.partial(close_future, future, loop)
|
||||||
|
)
|
||||||
|
|
||||||
|
if False:
|
||||||
|
progress = QtWidgets.QProgressBar()
|
||||||
|
progress.setRange(0, 99)
|
||||||
|
progress.show()
|
||||||
|
else:
|
||||||
|
mw = MainWindow()
|
||||||
|
progress = mw.progress
|
||||||
|
mw.show()
|
||||||
|
# LOG.info(f"calling first_50 {r}")
|
||||||
|
# await first_50(progress, r)
|
||||||
|
LOG.info(f"calling last_50 {r}")
|
||||||
|
o = QThreadExecutor(max_workers=1)
|
||||||
|
app.o = o
|
||||||
|
with o as executor:
|
||||||
|
await loop.run_in_executor(executor, functools.partial(last_50, progress, sys.argv[1:], app), loop)
|
||||||
|
LOG.info(f" {dir(o)}")
|
||||||
|
|
||||||
|
LOG.info(f"awaiting {future}")
|
||||||
|
await future
|
||||||
|
return True
|
||||||
|
|
||||||
|
async def first_50(progress, r=None):
|
||||||
|
progress.setValue(5)
|
||||||
|
LOG.info(f"first_50 {r}")
|
||||||
|
if r is not None:
|
||||||
|
# loop = asyncio.get_running_loop()
|
||||||
|
# LOG.info(f"first_50.r.run {r}")
|
||||||
|
# loop.call_soon_threadsafe(r.run, r.url, r.outfile, r.jsfile)
|
||||||
|
# r.run( r.url, r.outfile, r.jsfile)
|
||||||
|
for i in range(50):
|
||||||
|
# LOG.info(f"first_50 {r.progress} {i}")
|
||||||
|
# if r.progress >= 100: break
|
||||||
|
# progress.setValue(max(r.progress,i))
|
||||||
|
progress.setValue(i)
|
||||||
|
await asyncio.sleep(.1)
|
||||||
|
return
|
||||||
|
for i in range(50):
|
||||||
|
LOG.info(f"first_50 {r} {i}")
|
||||||
|
loop.call_soon_threadsafe(progress.setValue, i)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
def last_50(progress, largs, app, loop):
|
||||||
|
url = largs[0]
|
||||||
|
outfile = largs[1]
|
||||||
|
jsfile = largs[2] if len(largs) > 2 else None
|
||||||
|
r = Render(app, do_print=False, do_save=True)
|
||||||
|
uri = url.strip()
|
||||||
|
loop.call_soon_threadsafe(r.run, uri, outfile, jsfile)
|
||||||
|
time.sleep(1)
|
||||||
|
for i in range(50, 100):
|
||||||
|
j = len(app.ldone) # r.progress
|
||||||
|
if j == 100:
|
||||||
|
LOG.info(f"last_50 None {i} {j}")
|
||||||
|
else:
|
||||||
|
LOG.debug(f"last_50 None {i} {j}")
|
||||||
|
loop.call_soon_threadsafe(progress.setValue, i)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
url = 'https://dns.google/resolve?name=6D6EC2A2E2ED8BFF2D4834F8D669D82FC2A9FA8D.for-privacy.net&type=TXT&cd=true&do=true'
|
||||||
|
outfile = '/tmp/test1.pdf'
|
||||||
|
jsfile = '/tmp/test1.js'
|
||||||
|
from exclude_badExits import vsetup_logging
|
||||||
|
vsetup_logging(10)
|
||||||
|
app = QApplication([])
|
||||||
|
#?
|
||||||
|
loop = qasync.QEventLoop(app)
|
||||||
|
#NOT loop = asyncio.get_event_loop()
|
||||||
|
asyncio._set_running_loop(loop)
|
||||||
|
asyncio.events._set_running_loop(loop)
|
||||||
|
r = Render(app, do_print=False, do_save=True)
|
||||||
|
#loop.call_soon_threadsafe(r.run, url, outfile, jsfile)
|
||||||
|
r.run(url, outfile, jsfile)
|
||||||
|
app.rs = [r]
|
||||||
|
for i in range(20):
|
||||||
|
for elt in app.rs:
|
||||||
|
print (elt.percent)
|
||||||
|
time.sleep(2)
|
||||||
|
try:
|
||||||
|
qasync.run(main(app))
|
||||||
|
except asyncio.exceptions.CancelledError:
|
||||||
|
sys.exit(0)
|
||||||
|
except RuntimeError as e:
|
||||||
|
LOG.debug('Fixme')
|
||||||
|
sys.exit(0)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
val = 0
|
||||||
|
sys.exit(val)
|
49
src/phantompy/quamash_readme.py
Normal file
49
src/phantompy/quamash_readme.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#!/usr/local/bin/python3.sh
|
||||||
|
# -*-mode: python; indent-tabs-mode: nil; py-indent-offset: 4; coding: utf-8 -*
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from phantompy import Render
|
||||||
|
|
||||||
|
global LOG
|
||||||
|
import logging
|
||||||
|
import warnings
|
||||||
|
warnings.filterwarnings('ignore')
|
||||||
|
LOG = logging.getLogger()
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import asyncio
|
||||||
|
import time
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import QApplication, QProgressBar
|
||||||
|
from quamash import QEventLoop, QThreadExecutor
|
||||||
|
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
loop = QEventLoop(app)
|
||||||
|
asyncio.set_event_loop(loop) # NEW must set the event loop
|
||||||
|
asyncio.events._set_running_loop(loop)
|
||||||
|
|
||||||
|
progress = QProgressBar()
|
||||||
|
progress.setRange(0, 99)
|
||||||
|
progress.show()
|
||||||
|
|
||||||
|
async def master():
|
||||||
|
await first_50()
|
||||||
|
with QThreadExecutor(1) as executor:
|
||||||
|
await loop.run_in_executor(exec, last_50)
|
||||||
|
# TODO announce completion?
|
||||||
|
|
||||||
|
async def first_50():
|
||||||
|
for i in range(50):
|
||||||
|
progress.setValue(i)
|
||||||
|
await asyncio.sleep(.1)
|
||||||
|
|
||||||
|
def last_50():
|
||||||
|
for i in range(50,100):
|
||||||
|
loop.call_soon_threadsafe(progress.setValue, i)
|
||||||
|
time.sleep(.1)
|
||||||
|
|
||||||
|
with loop: ## context manager calls .close() when loop completes, and releases all resources
|
||||||
|
loop.run_until_complete(master())
|
Loading…
Reference in a new issue