This commit is contained in:
emdee 2024-02-02 08:31:47 +00:00
parent 3b623d4fdf
commit 383764fca2
9 changed files with 306 additions and 37 deletions

36
Makefile Normal file
View 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
View File

@ -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 = "."

View File

@ -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"

View File

@ -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
View 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
View File

View 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)

View 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)

View 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())