Blacken'd

Leonardo Barcaroli 2019-01-21 17:59:44 +01:00
parent 2712c717d7
commit f02bfb1968
6 changed files with 174 additions and 178 deletions

View File

@ -3,5 +3,5 @@
"""Top-level package for Bot_Z."""
__author__ = """Leonardo Barcaroli"""
__email__ = 'leonardo.barcaroli@deustechnology.com'
__version__ = '0.1.0'
__email__ = "leonardo.barcaroli@deustechnology.com"
__version__ = "0.1.0"

View File

@ -15,29 +15,32 @@ import time
import typing as T
from urllib.parse import urlparse
geckoexe = shutil.which('geckodriver')
geckoexe = shutil.which("geckodriver")
if geckoexe is None:
local_path = pkg_resources.resource_filename(__name__, 'bin')
local_path = pkg_resources.resource_filename(__name__, "bin")
try:
os.stat(os.path.join(local_path, 'geckodriver'))
os.environ['PATH'] = os.environ['PATH'] + \
':' + local_path
os.stat(os.path.join(local_path, "geckodriver"))
os.environ["PATH"] = os.environ["PATH"] + ":" + local_path
except FileNotFoundError:
print("Missing geckodriver executable in path", file=sys.stderr)
raise
from selenium import webdriver as wd # noqa
from selenium.common.exceptions import WebDriverException, NoSuchElementException # noqa
from selenium.common.exceptions import (
WebDriverException,
NoSuchElementException,
) # noqa
logging.basicConfig(
level=os.environ.get('BOTZ_LOGLEVEL', logging.INFO),
format='%(levelname)s: [%(name)s] -> %(message)s'
level=os.environ.get("BOTZ_LOGLEVEL", logging.INFO),
format="%(levelname)s: [%(name)s] -> %(message)s",
)
m_logger = logging.getLogger(__name__)
m_logger.debug("Init at debug")
def safely(f: T.Callable) -> T.Callable:
def _protection(self, *args, **kwargs):
try:
@ -58,9 +61,8 @@ def _is_present(driver: wd.Firefox, xpath: str) -> bool:
return False
def is_present(driver: wd.Firefox,
xpath: str,
timeout: T.Optional[timedelta]=None
def is_present(
driver: wd.Firefox, xpath: str, timeout: T.Optional[timedelta] = None
) -> bool:
"""
Helper function. If an element is present in the DOM tree,
@ -90,15 +92,17 @@ class Operator(wd.Firefox):
proxy: T.Optional[T.Tuple[str, int]] = None,
headless: bool = True,
debug: bool = False,
*args, **kwargs) -> None:
*args,
**kwargs
) -> None:
"""
Adds some configuration to Firefox.
"""
self.profile = wd.FirefoxProfile()
# Do not send telemetry
self.profile.set_preference('datareporting.policy.dataSubmissionEnabled', False)
self.profile.set_preference('datareporting.healthreport.service.enabled', False)
self.profile.set_preference('datareporting.healthreport.uploadEnabled', False)
self.profile.set_preference("datareporting.policy.dataSubmissionEnabled", False)
self.profile.set_preference("datareporting.healthreport.service.enabled", False)
self.profile.set_preference("datareporting.healthreport.uploadEnabled", False)
self.opts = wd.firefox.options.Options()
self.opts.headless = headless
@ -109,13 +113,15 @@ class Operator(wd.Firefox):
self.timeout = timedelta(seconds=timeout)
if proxy:
self.profile.set_preference('network.proxy.type', 1)
self.profile.set_preference('network.proxy.http', proxy[0])
self.profile.set_preference('network.proxy.http_port', proxy[1])
self.profile.set_preference('network.proxy.ssl', proxy[0])
self.profile.set_preference('network.proxy.ssl_port', proxy[1])
self.profile.set_preference("network.proxy.type", 1)
self.profile.set_preference("network.proxy.http", proxy[0])
self.profile.set_preference("network.proxy.http_port", proxy[1])
self.profile.set_preference("network.proxy.ssl", proxy[0])
self.profile.set_preference("network.proxy.ssl_port", proxy[1])
super().__init__(firefox_profile=self.profile, options=self.opts, *args, **kwargs)
super().__init__(
firefox_profile=self.profile, options=self.opts, *args, **kwargs
)
self.fullscreen_window()
self.z_name = name if name is not None else __name__
@ -138,22 +144,22 @@ class Operator(wd.Firefox):
self.logger.info("Forcing login: %s", user)
# Retrieve login page
self.get(self.base_uri)
_correct_url = 'cpccchk' in self.current_url
_correct_url = "cpccchk" in self.current_url
_now = datetime.now()
_elapsed = timedelta(seconds=0)
while not _correct_url:
self.logger.debug("Not yet on login page: %s", self.current_url)
time.sleep(0.5)
_correct_url = 'cpccchk' in self.current_url
_correct_url = "cpccchk" in self.current_url
_elapsed = datetime.now() - _now
if _elapsed > self.timeout:
break
self.logger.debug("After login get: %s", self.current_url)
time.sleep(1)
# Username
user_form = self.find_element_by_name('m_cUserName')
user_form = self.find_element_by_name("m_cUserName")
# Password
pass_form = self.find_element_by_name('m_cPassword')
pass_form = self.find_element_by_name("m_cPassword")
# Login button
login_butt = self.find_element_by_xpath('//input[contains(@id, "_Accedi")]')
# Compile and submit
@ -167,7 +173,7 @@ class Operator(wd.Firefox):
login_butt.submit()
time.sleep(5)
self.logger.debug("Login result: %s", self.title)
if 'Routine window' in self.title:
if "Routine window" in self.title:
self.logger.debug("Reloading...")
self.refresh()
self.switch_to.alert.accept()
@ -188,7 +194,9 @@ class Operator(wd.Firefox):
return
self.logger.info("Forcing logout: %s", user)
# Find the Profile menu and open it
profile_butt = self.find_element_by_xpath('//span[contains(@id, "imgNoPhotoLabel")]')
profile_butt = self.find_element_by_xpath(
'//span[contains(@id, "imgNoPhotoLabel")]'
)
profile_butt.click()
time.sleep(1)
# Find the logout button
@ -205,8 +213,8 @@ class Operator(wd.Firefox):
Check if already logged in. Checks if page is '/jsp/home.jsp'
and if login cookie is set (and not expired).
"""
_base_domain = '.'.join(self.uri.netloc.split('.')[-2:])
cookies = [c['name'] for c in self.get_cookies() if _base_domain in c['domain']]
_base_domain = ".".join(self.uri.netloc.split(".")[-2:])
cookies = [c["name"] for c in self.get_cookies() if _base_domain in c["domain"]]
_right_url = "/jsp/home.jsp" in self.current_url
_cookies = "dtLatC" in cookies
return _right_url and _cookies
@ -223,7 +231,9 @@ class Operator(wd.Firefox):
self.logger.warn("Already checked in!")
if not force:
return
iframe = self.find_element_by_xpath('//iframe[contains(@id, "gsmd_container.jsp")]')
iframe = self.find_element_by_xpath(
'//iframe[contains(@id, "gsmd_container.jsp")]'
)
self.switch_to.frame(iframe)
enter_butt = self.find_element_by_xpath('//input[@value="Entrata"]')
enter_butt.click()
@ -243,7 +253,9 @@ class Operator(wd.Firefox):
self.logger.warn("Not yet checked in!")
if not force:
return
iframe = self.find_element_by_xpath('//iframe[contains(@id, "gsmd_container.jsp")]')
iframe = self.find_element_by_xpath(
'//iframe[contains(@id, "gsmd_container.jsp")]'
)
self.switch_to.frame(iframe)
exit_butt = self.find_element_by_xpath('//input[@value="Uscita"]')
exit_butt.click()

View File

@ -8,8 +8,7 @@ import click
@click.command()
def main(args=None):
"""Console script for bot_z."""
click.echo("Replace this message by putting your code into "
"bot_z.cli.main")
click.echo("Replace this message by putting your code into " "bot_z.cli.main")
click.echo("See click documentation at http://click.pocoo.org/")

View File

@ -40,22 +40,22 @@ import bot_z
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
extensions = ["sphinx.ext.autodoc", "sphinx.ext.viewcode"]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
templates_path = ["_templates"]
# The suffix of source filenames.
source_suffix = '.rst'
source_suffix = ".rst"
# The encoding of source files.
# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
master_doc = "index"
# General information about the project.
project = u'Bot_Z'
project = u"Bot_Z"
copyright = u"2019, Leonardo Barcaroli"
# The version info for the project you're documenting, acts as replacement
@ -79,7 +79,7 @@ release = bot_z.__version__
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
exclude_patterns = ["_build"]
# The reST default role (used for this markup: `text`) to use for all
# documents.
@ -97,7 +97,7 @@ exclude_patterns = ['_build']
# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
pygments_style = "sphinx"
# A list of ignored prefixes for module index sorting.
# modindex_common_prefix = []
@ -111,7 +111,7 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
html_theme = "default"
# Theme options are theme-specific and customize the look and feel of a
# theme further. For a list of options available for each theme, see the
@ -142,7 +142,7 @@ html_theme = 'default'
# here, relative to this directory. They are copied after the builtin
# static files, so a file named "default.css" will overwrite the builtin
# "default.css".
html_static_path = ['_static']
html_static_path = ["_static"]
# If not '', a 'Last updated on:' timestamp is inserted at every page
# bottom, using the given strftime format.
@ -188,7 +188,7 @@ html_static_path = ['_static']
# html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'bot_zdoc'
htmlhelp_basename = "bot_zdoc"
# -- Options for LaTeX output ------------------------------------------
@ -196,10 +196,8 @@ htmlhelp_basename = 'bot_zdoc'
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
@ -208,9 +206,7 @@ latex_elements = {
# (source start file, target name, title, author, documentclass
# [howto/manual]).
latex_documents = [
('index', 'bot_z.tex',
u'Bot_Z Documentation',
u'Leonardo Barcaroli', 'manual'),
("index", "bot_z.tex", u"Bot_Z Documentation", u"Leonardo Barcaroli", "manual")
]
# The name of an image file (relative to this directory) to place at
@ -238,11 +234,7 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'bot_z',
u'Bot_Z Documentation',
[u'Leonardo Barcaroli'], 1)
]
man_pages = [("index", "bot_z", u"Bot_Z Documentation", [u"Leonardo Barcaroli"], 1)]
# If true, show URL addresses after external links.
# man_show_urls = False
@ -254,12 +246,15 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'bot_z',
u'Bot_Z Documentation',
u'Leonardo Barcaroli',
'bot_z',
'One line description of project.',
'Miscellaneous'),
(
"index",
"bot_z",
u"Bot_Z Documentation",
u"Leonardo Barcaroli",
"bot_z",
"One line description of project.",
"Miscellaneous",
)
]
# Documents to append as an appendix to all manuals.

106
setup.py
View File

@ -21,25 +21,20 @@ import zipfile
GECKO_RELEASE_PATH = "https://github.com/mozilla/geckodriver"
PKG_NAME = 'bot_z'
VERSION = '0.1.0'
AUTHOR = 'blallo'
AUTHOR_EMAIL = 'blallo@autistici.org'
BIN_PATH = 'bin/geckodriver'
PKG_NAME = "bot_z"
VERSION = "0.1.0"
AUTHOR = "blallo"
AUTHOR_EMAIL = "blallo@autistici.org"
BIN_PATH = "bin/geckodriver"
with open('README.md') as readme_file:
with open("README.md") as readme_file:
readme = readme_file.read()
requirements = [
'Click>=6.0',
'selenium>=3.141.0',
]
requirements = ["Click>=6.0", "selenium>=3.141.0"]
setup_requirements = [
] # type: T.List[str]
setup_requirements = [] # type: T.List[str]
test_requirements = [
] # type: T.List[str]
test_requirements = [] # type: T.List[str]
class GitTags(HTMLParser):
@ -48,7 +43,7 @@ class GitTags(HTMLParser):
def handle_starttag(self, tag, attrs):
dattrs = dict(attrs)
if 'commit-title' in dattrs.get('class', ''):
if "commit-title" in dattrs.get("class", ""):
self.take_next = 1
def handle_data(self, data):
@ -57,7 +52,7 @@ class GitTags(HTMLParser):
elif self.take_next == 1:
self.take_next = 2
elif self.take_next == 2:
self.tags.append(data.strip('\n').strip(' ').strip('\n'))
self.tags.append(data.strip("\n").strip(" ").strip("\n"))
self.take_next = 0
@ -83,9 +78,9 @@ def find_latest_version(url: str) -> str:
"""
Retrieves latest geckodriver tag.
"""
tag_page = retrieve_page('{}/tags'.format(url))
tag_page = retrieve_page("{}/tags".format(url))
gt = GitTags()
gt.feed(tag_page.decode('utf-8'))
gt.feed(tag_page.decode("utf-8"))
gt.tags.sort()
return gt.tags[-1]
@ -109,8 +104,7 @@ def ensure_local_folder() -> None:
def assemble_driver_uri(
version: T.Optional[str]=None,
platform: T.Optional[str]=None
version: T.Optional[str] = None, platform: T.Optional[str] = None
) -> str:
"""
Selects the right geckodriver URI.
@ -122,18 +116,15 @@ def assemble_driver_uri(
s_platform = sys.platform
is_64bits = sys.maxsize > 2 ** 32
if is_64bits:
platform = '{}64'.format(s_platform)
platform = "{}64".format(s_platform)
else:
platform = '{}64'.format(s_platform)
if 'win' in platform:
ext = 'zip'
platform = "{}64".format(s_platform)
if "win" in platform:
ext = "zip"
else:
ext = 'tar.gz'
return '{base}/releases/download/{vers}/geckodriver-{vers}-{platform}.{ext}'.format(
base=GECKO_RELEASE_PATH,
vers=version,
platform=platform,
ext=ext
ext = "tar.gz"
return "{base}/releases/download/{vers}/geckodriver-{vers}-{platform}.{ext}".format(
base=GECKO_RELEASE_PATH, vers=version, platform=platform, ext=ext
)
@ -141,18 +132,18 @@ def download_driver_bin(uri: str, path: str) -> None:
"""
Donwloads the geckodriver binary.
"""
name = uri.split('/')[-1]
name = uri.split("/")[-1]
filepath = os.path.join(path, name)
print("[DRIVER] downloading '{}' to {}".format(uri, filepath))
content = retrieve_page(uri)
try:
with open(filepath, 'wb') as f:
with open(filepath, "wb") as f:
f.write(content)
if name.endswith(".zip"):
with zipfile.ZipFile(filepath, 'r') as z:
with zipfile.ZipFile(filepath, "r") as z:
z.extractall(path)
elif name.endswith(".tar.gz"):
with tarfile.open(filepath, 'r') as r:
with tarfile.open(filepath, "r") as r:
r.extractall(path)
else:
raise RuntimeError("Unrecognized file extension: %s", name)
@ -166,9 +157,9 @@ def preinstall(platform: T.Optional[str]=None) -> None:
right place the geckodriver binary.
"""
# target_path = os.path.join(os.path.abspath(os.path.curdir), 'bot_z', 'bin')
target_path = pkg_resources.resource_filename('bot_z', 'bin')
target_path = pkg_resources.resource_filename("bot_z", "bin")
ensure_local_folder()
version = os.environ.get('BOTZ_GECKO_VERSION')
version = os.environ.get("BOTZ_GECKO_VERSION")
gecko_uri = assemble_driver_uri(version, platform)
print("[POSTINSTALL] gecko_uri: {}".format(gecko_uri))
download_driver_bin(gecko_uri, target_path)
@ -199,6 +190,7 @@ def translate_platform_to_gecko_vers(plat: str) -> str:
# From: https://stackoverflow.com/a/36902139
class CustomDevelopCommand(develop):
"""Custom installation for development mode."""
def run(self):
print("POSTINSTALL")
preinstall()
@ -207,12 +199,13 @@ class CustomDevelopCommand(develop):
class CustomInstallCommand(install):
"""Custom installation for installation mode."""
def run(self):
opts = self.distribution.get_cmdline_options()
platform = None
if 'bdist_wheel' in opts:
if "bdist_wheel" in opts:
platform = translate_platform_to_gecko_vers(
opts['bdist_wheel'].get('plat-name')
opts["bdist_wheel"].get("plat-name")
)
preinstall(platform)
super().run()
@ -224,13 +217,14 @@ class CustomBDistWheel(bdist_wheel):
Custom bdist_wheel command to ship the right binary
of geckodriver.
"""
def finalize_options(self):
super().finalize_options()
self.root_is_pure = False
def get_tag(self):
python, abi, plat = super().get_tag()
python, abi = 'py3', 'none'
python, abi = "py3", "none"
return python, abi, plat
@ -241,33 +235,29 @@ setup(
long_description=readme,
author=AUTHOR,
author_email=AUTHOR_EMAIL,
url='https://git.abbiamoundominio.org/blallo/BotZ',
packages=find_packages(include=['bot_z']),
url="https://git.abbiamoundominio.org/blallo/BotZ",
packages=find_packages(include=["bot_z"]),
cmdclass={
'develop': CustomDevelopCommand,
'install': CustomInstallCommand,
'bdist_wheel': CustomBDistWheel,
"develop": CustomDevelopCommand,
"install": CustomInstallCommand,
"bdist_wheel": CustomBDistWheel,
},
entry_points={
'console_scripts': [
'bot_z=bot_z.cli:main'
]
},
package_data = {'bot_z': ['bin/geckodriver']},
entry_points={"console_scripts": ["bot_z=bot_z.cli:main"]},
package_data={"bot_z": ["bin/geckodriver"]},
include_package_data=True,
install_requires=requirements,
license="GLWTS Public Licence",
zip_safe=False,
keywords='bot_z',
keywords="bot_z",
classifiers=[
'Development Status :: 2 - Pre-Alpha',
'Intended Audience :: Developers',
'License :: GLWTS Public Licence',
'Natural Language :: English',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
"Development Status :: 2 - Pre-Alpha",
"Intended Audience :: Developers",
"License :: GLWTS Public Licence",
"Natural Language :: English",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
],
test_suite='pytest',
test_suite="pytest",
tests_require=test_requirements,
setup_requires=setup_requirements,
)

View File

@ -28,7 +28,7 @@ class TestBot_z(unittest.TestCase):
runner = CliRunner()
result = runner.invoke(cli.main)
assert result.exit_code == 0
assert 'bot_z.cli.main' in result.output
help_result = runner.invoke(cli.main, ['--help'])
assert "bot_z.cli.main" in result.output
help_result = runner.invoke(cli.main, ["--help"])
assert help_result.exit_code == 0
assert '--help Show this message and exit.' in help_result.output
assert "--help Show this message and exit." in help_result.output