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]
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" } ]
requires-python = ">=3.6"
keywords = ["tor", "python3", "bad exits"]
requires-python = ">=3.8"
dependencies = [
'qasync',
# PyQt5 PyQt6
]
keywords = ["phantomjs", "python3", "qasync"]
classifiers = [
"License :: OSI Approved",
"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 :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: Implementation :: CPython",
"Classifier: Topic :: Software Development :: Libraries :: Python Modules",
]
#
dynamic = ["version", "readme", ] # cannot be dynamic ['license']
scripts = { phantompy = "phantompy.phantompy:iMain" }
dependencies = ['qasync', 'PyQt5']
[tool.setuptools.dynamic]
version = {attr = "phantompy.__version__"}
readme = {file = ["README.md"]}
[project.scripts]
phantompy = "phantompy.qasync_phantompy:iMain"
[project.license]
file = "LICENSE.md"
#[project.license]
#file = "LICENSE.md"
[project.urls]
repository = "https://git.plastiras.org/emdee/phantompy"
@ -35,9 +36,12 @@ repository = "https://git.plastiras.org/emdee/phantompy"
requires = ["setuptools >= 61.0"]
build-backend = "setuptools.build_meta"
# Either or both of these don't work
#[tool.setuptools]
#packages = ["phantompy"]
[tool.setuptools.dynamic]
version = {attr = "phantompy.__version__"}
readme = {file = ["README.md"]}
[tool.setuptools]
packages = ["phantompy"]
#[tool.setuptools.packages.find]
#include = ["src"]
#where = "src"

View File

@ -11,19 +11,26 @@ classifiers =
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
Programming Language :: Python :: 3.11
Programming Language :: Python :: Implementation :: CPython
Framework :: AsyncIO
[options]
zip_safe = false
python_requires = ~=3.6
packages = find:
python_requires = ~=3.8
include_package_data = false
install_requires =
qasync
cryptography
rsa
stem
package_dir=
=src
packages=find:
[options.packages.find]
where=src
[options.entry_points]
console_scripts =
@ -40,7 +47,6 @@ ignore =
E114
E128
E225
E225
E261
E302
E305
@ -49,10 +55,11 @@ ignore =
E502
E541
E701
E702
E704
E722
E741
F508
F541
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,6 +122,8 @@ import importlib
import os
import sys # noqa
QtModuleName = os.environ.get('QT_API')
if not QtModuleName:
from qasync import QtModuleName
from qasync.QtCore import QUrl

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