Blacken'd
parent
2712c717d7
commit
f02bfb1968
|
@ -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"
|
||||
|
|
|
@ -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,10 +61,9 @@ def _is_present(driver: wd.Firefox, xpath: str) -> bool:
|
|||
return False
|
||||
|
||||
|
||||
def is_present(driver: wd.Firefox,
|
||||
xpath: str,
|
||||
timeout: T.Optional[timedelta]=None
|
||||
) -> bool:
|
||||
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,
|
||||
returns true. False otherwise.
|
||||
|
@ -83,22 +85,24 @@ def is_present(driver: wd.Firefox,
|
|||
|
||||
class Operator(wd.Firefox):
|
||||
def __init__(
|
||||
self,
|
||||
base_uri: str,
|
||||
name: str = None,
|
||||
timeout: int=20,
|
||||
proxy: T.Optional[T.Tuple[str, int]] = None,
|
||||
headless: bool = True,
|
||||
debug: bool = False,
|
||||
*args, **kwargs) -> None:
|
||||
self,
|
||||
base_uri: str,
|
||||
name: str = None,
|
||||
timeout: int = 20,
|
||||
proxy: T.Optional[T.Tuple[str, int]] = None,
|
||||
headless: bool = True,
|
||||
debug: bool = False,
|
||||
*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__
|
||||
|
@ -127,7 +133,7 @@ class Operator(wd.Firefox):
|
|||
self._checked_in = False
|
||||
|
||||
@safely
|
||||
def login(self, user: str, password: str, force: bool=False) -> None:
|
||||
def login(self, user: str, password: str, force: bool = False) -> None:
|
||||
"""
|
||||
Do the login and proceed.
|
||||
"""
|
||||
|
@ -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()
|
||||
|
@ -178,7 +184,7 @@ class Operator(wd.Firefox):
|
|||
self.logger.error("Login failed: %s", user)
|
||||
|
||||
@safely
|
||||
def logout(self, user: str, force: bool=False) -> None:
|
||||
def logout(self, user: str, force: bool = False) -> None:
|
||||
"""
|
||||
Do the logout.
|
||||
"""
|
||||
|
@ -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,14 +213,14 @@ 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
|
||||
|
||||
@safely
|
||||
def check_in(self, force: bool=False) -> None:
|
||||
def check_in(self, force: bool = False) -> None:
|
||||
"""
|
||||
Click the check in button.
|
||||
"""
|
||||
|
@ -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()
|
||||
|
@ -232,7 +242,7 @@ class Operator(wd.Firefox):
|
|||
pass
|
||||
|
||||
@safely
|
||||
def check_out(self, force: bool=False) -> None:
|
||||
def check_out(self, force: bool = False) -> None:
|
||||
"""
|
||||
Click the check out button.
|
||||
"""
|
||||
|
@ -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()
|
||||
|
|
|
@ -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/")
|
||||
|
||||
|
||||
|
|
129
docs/conf.py
129
docs/conf.py
|
@ -20,7 +20,7 @@ import os
|
|||
# directory, add these directories to sys.path here. If the directory is
|
||||
# relative to the documentation root, use os.path.abspath to make it
|
||||
# absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# Get the project root dir, which is the parent dir of this
|
||||
cwd = os.getcwd()
|
||||
|
@ -36,26 +36,26 @@ import bot_z
|
|||
# -- General configuration ---------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# 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'
|
||||
# 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
|
||||
|
@ -69,126 +69,126 @@ release = bot_z.__version__
|
|||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
# language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to
|
||||
# some non-false value, then it is used:
|
||||
#today = ''
|
||||
# today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
# today_fmt = '%B %d, %Y'
|
||||
|
||||
# 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.
|
||||
#default_role = None
|
||||
# default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
# add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
# add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
# 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 = []
|
||||
# modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built
|
||||
# documents.
|
||||
#keep_warnings = False
|
||||
# keep_warnings = False
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------
|
||||
|
||||
# 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
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
# html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
# html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as
|
||||
# html_title.
|
||||
#html_short_title = None
|
||||
# html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the
|
||||
# top of the sidebar.
|
||||
#html_logo = None
|
||||
# html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon
|
||||
# of the docs. This file should be a Windows icon file (.ico) being
|
||||
# 16x16 or 32x32 pixels large.
|
||||
#html_favicon = None
|
||||
# html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets)
|
||||
# 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.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
# html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
# html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
# html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names
|
||||
# to template names.
|
||||
#html_additional_pages = {}
|
||||
# html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
# html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
# html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
# html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
# html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer.
|
||||
# Default is True.
|
||||
#html_show_sphinx = True
|
||||
# html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer.
|
||||
# Default is True.
|
||||
#html_show_copyright = True
|
||||
# html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages
|
||||
# will contain a <link> tag referring to it. The value of this option
|
||||
# must be the base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
# html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
# 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,44 +206,38 @@ 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
|
||||
# the top of the title page.
|
||||
#latex_logo = None
|
||||
# latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings
|
||||
# are parts, not chapters.
|
||||
#latex_use_parts = False
|
||||
# latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
# latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
# latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
# latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
# latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output ------------------------------------
|
||||
|
||||
# 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
|
||||
# man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output ----------------------------------------
|
||||
|
@ -254,22 +246,25 @@ 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.
|
||||
#texinfo_appendices = []
|
||||
# texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
# texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
# texinfo_show_urls = 'footnote'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
||||
# texinfo_no_detailmenu = False
|
||||
|
|
112
setup.py
112
setup.py
|
@ -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,9 +104,8 @@ def ensure_local_folder() -> None:
|
|||
|
||||
|
||||
def assemble_driver_uri(
|
||||
version: T.Optional[str]=None,
|
||||
platform: T.Optional[str]=None
|
||||
) -> str:
|
||||
version: T.Optional[str] = None, platform: T.Optional[str] = None
|
||||
) -> str:
|
||||
"""
|
||||
Selects the right geckodriver URI.
|
||||
"""
|
||||
|
@ -120,20 +114,17 @@ def assemble_driver_uri(
|
|||
version = find_latest_version(GECKO_RELEASE_PATH)
|
||||
if not platform:
|
||||
s_platform = sys.platform
|
||||
is_64bits = sys.maxsize > 2**32
|
||||
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)
|
||||
|
@ -160,15 +151,15 @@ def download_driver_bin(uri: str, path: str) -> None:
|
|||
os.remove(filepath)
|
||||
|
||||
|
||||
def preinstall(platform: T.Optional[str]=None) -> None:
|
||||
def preinstall(platform: T.Optional[str] = None) -> None:
|
||||
"""
|
||||
Performs all the postintallation flow, donwloading in the
|
||||
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,
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue