Blacken'd
parent
2712c717d7
commit
f02bfb1968
|
@ -3,5 +3,5 @@
|
||||||
"""Top-level package for Bot_Z."""
|
"""Top-level package for Bot_Z."""
|
||||||
|
|
||||||
__author__ = """Leonardo Barcaroli"""
|
__author__ = """Leonardo Barcaroli"""
|
||||||
__email__ = 'leonardo.barcaroli@deustechnology.com'
|
__email__ = "leonardo.barcaroli@deustechnology.com"
|
||||||
__version__ = '0.1.0'
|
__version__ = "0.1.0"
|
||||||
|
|
|
@ -15,29 +15,32 @@ import time
|
||||||
import typing as T
|
import typing as T
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
geckoexe = shutil.which('geckodriver')
|
geckoexe = shutil.which("geckodriver")
|
||||||
if geckoexe is None:
|
if geckoexe is None:
|
||||||
local_path = pkg_resources.resource_filename(__name__, 'bin')
|
local_path = pkg_resources.resource_filename(__name__, "bin")
|
||||||
try:
|
try:
|
||||||
os.stat(os.path.join(local_path, 'geckodriver'))
|
os.stat(os.path.join(local_path, "geckodriver"))
|
||||||
os.environ['PATH'] = os.environ['PATH'] + \
|
os.environ["PATH"] = os.environ["PATH"] + ":" + local_path
|
||||||
':' + local_path
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print("Missing geckodriver executable in path", file=sys.stderr)
|
print("Missing geckodriver executable in path", file=sys.stderr)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
from selenium import webdriver as wd # noqa
|
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(
|
logging.basicConfig(
|
||||||
level=os.environ.get('BOTZ_LOGLEVEL', logging.INFO),
|
level=os.environ.get("BOTZ_LOGLEVEL", logging.INFO),
|
||||||
format='%(levelname)s: [%(name)s] -> %(message)s'
|
format="%(levelname)s: [%(name)s] -> %(message)s",
|
||||||
)
|
)
|
||||||
|
|
||||||
m_logger = logging.getLogger(__name__)
|
m_logger = logging.getLogger(__name__)
|
||||||
m_logger.debug("Init at debug")
|
m_logger.debug("Init at debug")
|
||||||
|
|
||||||
|
|
||||||
def safely(f: T.Callable) -> T.Callable:
|
def safely(f: T.Callable) -> T.Callable:
|
||||||
def _protection(self, *args, **kwargs):
|
def _protection(self, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
|
@ -58,10 +61,9 @@ def _is_present(driver: wd.Firefox, xpath: str) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def is_present(driver: wd.Firefox,
|
def is_present(
|
||||||
xpath: str,
|
driver: wd.Firefox, xpath: str, timeout: T.Optional[timedelta] = None
|
||||||
timeout: T.Optional[timedelta]=None
|
) -> bool:
|
||||||
) -> bool:
|
|
||||||
"""
|
"""
|
||||||
Helper function. If an element is present in the DOM tree,
|
Helper function. If an element is present in the DOM tree,
|
||||||
returns true. False otherwise.
|
returns true. False otherwise.
|
||||||
|
@ -83,22 +85,24 @@ def is_present(driver: wd.Firefox,
|
||||||
|
|
||||||
class Operator(wd.Firefox):
|
class Operator(wd.Firefox):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
base_uri: str,
|
base_uri: str,
|
||||||
name: str = None,
|
name: str = None,
|
||||||
timeout: int=20,
|
timeout: int = 20,
|
||||||
proxy: T.Optional[T.Tuple[str, int]] = None,
|
proxy: T.Optional[T.Tuple[str, int]] = None,
|
||||||
headless: bool = True,
|
headless: bool = True,
|
||||||
debug: bool = False,
|
debug: bool = False,
|
||||||
*args, **kwargs) -> None:
|
*args,
|
||||||
|
**kwargs
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Adds some configuration to Firefox.
|
Adds some configuration to Firefox.
|
||||||
"""
|
"""
|
||||||
self.profile = wd.FirefoxProfile()
|
self.profile = wd.FirefoxProfile()
|
||||||
# Do not send telemetry
|
# Do not send telemetry
|
||||||
self.profile.set_preference('datareporting.policy.dataSubmissionEnabled', False)
|
self.profile.set_preference("datareporting.policy.dataSubmissionEnabled", False)
|
||||||
self.profile.set_preference('datareporting.healthreport.service.enabled', False)
|
self.profile.set_preference("datareporting.healthreport.service.enabled", False)
|
||||||
self.profile.set_preference('datareporting.healthreport.uploadEnabled', False)
|
self.profile.set_preference("datareporting.healthreport.uploadEnabled", False)
|
||||||
|
|
||||||
self.opts = wd.firefox.options.Options()
|
self.opts = wd.firefox.options.Options()
|
||||||
self.opts.headless = headless
|
self.opts.headless = headless
|
||||||
|
@ -109,13 +113,15 @@ class Operator(wd.Firefox):
|
||||||
self.timeout = timedelta(seconds=timeout)
|
self.timeout = timedelta(seconds=timeout)
|
||||||
|
|
||||||
if proxy:
|
if proxy:
|
||||||
self.profile.set_preference('network.proxy.type', 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", proxy[0])
|
||||||
self.profile.set_preference('network.proxy.http_port', proxy[1])
|
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", proxy[0])
|
||||||
self.profile.set_preference('network.proxy.ssl_port', proxy[1])
|
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.fullscreen_window()
|
||||||
|
|
||||||
self.z_name = name if name is not None else __name__
|
self.z_name = name if name is not None else __name__
|
||||||
|
@ -127,7 +133,7 @@ class Operator(wd.Firefox):
|
||||||
self._checked_in = False
|
self._checked_in = False
|
||||||
|
|
||||||
@safely
|
@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.
|
Do the login and proceed.
|
||||||
"""
|
"""
|
||||||
|
@ -138,22 +144,22 @@ class Operator(wd.Firefox):
|
||||||
self.logger.info("Forcing login: %s", user)
|
self.logger.info("Forcing login: %s", user)
|
||||||
# Retrieve login page
|
# Retrieve login page
|
||||||
self.get(self.base_uri)
|
self.get(self.base_uri)
|
||||||
_correct_url = 'cpccchk' in self.current_url
|
_correct_url = "cpccchk" in self.current_url
|
||||||
_now = datetime.now()
|
_now = datetime.now()
|
||||||
_elapsed = timedelta(seconds=0)
|
_elapsed = timedelta(seconds=0)
|
||||||
while not _correct_url:
|
while not _correct_url:
|
||||||
self.logger.debug("Not yet on login page: %s", self.current_url)
|
self.logger.debug("Not yet on login page: %s", self.current_url)
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
_correct_url = 'cpccchk' in self.current_url
|
_correct_url = "cpccchk" in self.current_url
|
||||||
_elapsed = datetime.now() - _now
|
_elapsed = datetime.now() - _now
|
||||||
if _elapsed > self.timeout:
|
if _elapsed > self.timeout:
|
||||||
break
|
break
|
||||||
self.logger.debug("After login get: %s", self.current_url)
|
self.logger.debug("After login get: %s", self.current_url)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
# Username
|
# Username
|
||||||
user_form = self.find_element_by_name('m_cUserName')
|
user_form = self.find_element_by_name("m_cUserName")
|
||||||
# Password
|
# Password
|
||||||
pass_form = self.find_element_by_name('m_cPassword')
|
pass_form = self.find_element_by_name("m_cPassword")
|
||||||
# Login button
|
# Login button
|
||||||
login_butt = self.find_element_by_xpath('//input[contains(@id, "_Accedi")]')
|
login_butt = self.find_element_by_xpath('//input[contains(@id, "_Accedi")]')
|
||||||
# Compile and submit
|
# Compile and submit
|
||||||
|
@ -167,7 +173,7 @@ class Operator(wd.Firefox):
|
||||||
login_butt.submit()
|
login_butt.submit()
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
self.logger.debug("Login result: %s", self.title)
|
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.logger.debug("Reloading...")
|
||||||
self.refresh()
|
self.refresh()
|
||||||
self.switch_to.alert.accept()
|
self.switch_to.alert.accept()
|
||||||
|
@ -178,7 +184,7 @@ class Operator(wd.Firefox):
|
||||||
self.logger.error("Login failed: %s", user)
|
self.logger.error("Login failed: %s", user)
|
||||||
|
|
||||||
@safely
|
@safely
|
||||||
def logout(self, user: str, force: bool=False) -> None:
|
def logout(self, user: str, force: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
Do the logout.
|
Do the logout.
|
||||||
"""
|
"""
|
||||||
|
@ -188,7 +194,9 @@ class Operator(wd.Firefox):
|
||||||
return
|
return
|
||||||
self.logger.info("Forcing logout: %s", user)
|
self.logger.info("Forcing logout: %s", user)
|
||||||
# Find the Profile menu and open it
|
# 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()
|
profile_butt.click()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
# Find the logout button
|
# Find the logout button
|
||||||
|
@ -205,14 +213,14 @@ class Operator(wd.Firefox):
|
||||||
Check if already logged in. Checks if page is '/jsp/home.jsp'
|
Check if already logged in. Checks if page is '/jsp/home.jsp'
|
||||||
and if login cookie is set (and not expired).
|
and if login cookie is set (and not expired).
|
||||||
"""
|
"""
|
||||||
_base_domain = '.'.join(self.uri.netloc.split('.')[-2:])
|
_base_domain = ".".join(self.uri.netloc.split(".")[-2:])
|
||||||
cookies = [c['name'] for c in self.get_cookies() if _base_domain in c['domain']]
|
cookies = [c["name"] for c in self.get_cookies() if _base_domain in c["domain"]]
|
||||||
_right_url = "/jsp/home.jsp" in self.current_url
|
_right_url = "/jsp/home.jsp" in self.current_url
|
||||||
_cookies = "dtLatC" in cookies
|
_cookies = "dtLatC" in cookies
|
||||||
return _right_url and _cookies
|
return _right_url and _cookies
|
||||||
|
|
||||||
@safely
|
@safely
|
||||||
def check_in(self, force: bool=False) -> None:
|
def check_in(self, force: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
Click the check in button.
|
Click the check in button.
|
||||||
"""
|
"""
|
||||||
|
@ -223,7 +231,9 @@ class Operator(wd.Firefox):
|
||||||
self.logger.warn("Already checked in!")
|
self.logger.warn("Already checked in!")
|
||||||
if not force:
|
if not force:
|
||||||
return
|
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)
|
self.switch_to.frame(iframe)
|
||||||
enter_butt = self.find_element_by_xpath('//input[@value="Entrata"]')
|
enter_butt = self.find_element_by_xpath('//input[@value="Entrata"]')
|
||||||
enter_butt.click()
|
enter_butt.click()
|
||||||
|
@ -232,7 +242,7 @@ class Operator(wd.Firefox):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@safely
|
@safely
|
||||||
def check_out(self, force: bool=False) -> None:
|
def check_out(self, force: bool = False) -> None:
|
||||||
"""
|
"""
|
||||||
Click the check out button.
|
Click the check out button.
|
||||||
"""
|
"""
|
||||||
|
@ -243,7 +253,9 @@ class Operator(wd.Firefox):
|
||||||
self.logger.warn("Not yet checked in!")
|
self.logger.warn("Not yet checked in!")
|
||||||
if not force:
|
if not force:
|
||||||
return
|
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)
|
self.switch_to.frame(iframe)
|
||||||
exit_butt = self.find_element_by_xpath('//input[@value="Uscita"]')
|
exit_butt = self.find_element_by_xpath('//input[@value="Uscita"]')
|
||||||
exit_butt.click()
|
exit_butt.click()
|
||||||
|
|
|
@ -8,8 +8,7 @@ import click
|
||||||
@click.command()
|
@click.command()
|
||||||
def main(args=None):
|
def main(args=None):
|
||||||
"""Console script for bot_z."""
|
"""Console script for bot_z."""
|
||||||
click.echo("Replace this message by putting your code into "
|
click.echo("Replace this message by putting your code into " "bot_z.cli.main")
|
||||||
"bot_z.cli.main")
|
|
||||||
click.echo("See click documentation at http://click.pocoo.org/")
|
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
|
# directory, add these directories to sys.path here. If the directory is
|
||||||
# relative to the documentation root, use os.path.abspath to make it
|
# relative to the documentation root, use os.path.abspath to make it
|
||||||
# absolute, like shown here.
|
# 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
|
# Get the project root dir, which is the parent dir of this
|
||||||
cwd = os.getcwd()
|
cwd = os.getcwd()
|
||||||
|
@ -36,26 +36,26 @@ import bot_z
|
||||||
# -- General configuration ---------------------------------------------
|
# -- General configuration ---------------------------------------------
|
||||||
|
|
||||||
# If your documentation needs a minimal Sphinx version, state it here.
|
# 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
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
# 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.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ["_templates"]
|
||||||
|
|
||||||
# The suffix of source filenames.
|
# The suffix of source filenames.
|
||||||
source_suffix = '.rst'
|
source_suffix = ".rst"
|
||||||
|
|
||||||
# The encoding of source files.
|
# The encoding of source files.
|
||||||
#source_encoding = 'utf-8-sig'
|
# source_encoding = 'utf-8-sig'
|
||||||
|
|
||||||
# The master toctree document.
|
# The master toctree document.
|
||||||
master_doc = 'index'
|
master_doc = "index"
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = u'Bot_Z'
|
project = u"Bot_Z"
|
||||||
copyright = u"2019, Leonardo Barcaroli"
|
copyright = u"2019, Leonardo Barcaroli"
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement
|
# 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
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
#language = None
|
# language = None
|
||||||
|
|
||||||
# There are two options for replacing |today|: either, you set today to
|
# There are two options for replacing |today|: either, you set today to
|
||||||
# some non-false value, then it is used:
|
# some non-false value, then it is used:
|
||||||
#today = ''
|
# today = ''
|
||||||
# Else, today_fmt is used as the format for a strftime call.
|
# 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
|
# List of patterns, relative to source directory, that match files and
|
||||||
# directories to ignore when looking for source files.
|
# 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
|
# The reST default role (used for this markup: `text`) to use for all
|
||||||
# documents.
|
# documents.
|
||||||
#default_role = None
|
# default_role = None
|
||||||
|
|
||||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
# 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
|
# If true, the current module name will be prepended to all description
|
||||||
# unit titles (such as .. function::).
|
# unit titles (such as .. function::).
|
||||||
#add_module_names = True
|
# add_module_names = True
|
||||||
|
|
||||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||||
# output. They are ignored by default.
|
# output. They are ignored by default.
|
||||||
#show_authors = False
|
# show_authors = False
|
||||||
|
|
||||||
# The name of the Pygments (syntax highlighting) style to use.
|
# 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.
|
# 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
|
# If true, keep warnings as "system message" paragraphs in the built
|
||||||
# documents.
|
# documents.
|
||||||
#keep_warnings = False
|
# keep_warnings = False
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output -------------------------------------------
|
# -- Options for HTML output -------------------------------------------
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# 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 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
|
# theme further. For a list of options available for each theme, see the
|
||||||
# documentation.
|
# documentation.
|
||||||
#html_theme_options = {}
|
# html_theme_options = {}
|
||||||
|
|
||||||
# Add any paths that contain custom themes here, relative to this directory.
|
# 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
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
# "<project> v<release> documentation".
|
# "<project> v<release> documentation".
|
||||||
#html_title = None
|
# html_title = None
|
||||||
|
|
||||||
# A shorter title for the navigation bar. Default is the same as
|
# A shorter title for the navigation bar. Default is the same as
|
||||||
# html_title.
|
# html_title.
|
||||||
#html_short_title = None
|
# html_short_title = None
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at the
|
# The name of an image file (relative to this directory) to place at the
|
||||||
# top of the sidebar.
|
# top of the sidebar.
|
||||||
#html_logo = None
|
# html_logo = None
|
||||||
|
|
||||||
# The name of an image file (within the static path) to use as favicon
|
# 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
|
# of the docs. This file should be a Windows icon file (.ico) being
|
||||||
# 16x16 or 32x32 pixels large.
|
# 16x16 or 32x32 pixels large.
|
||||||
#html_favicon = None
|
# html_favicon = None
|
||||||
|
|
||||||
# Add any paths that contain custom static files (such as style sheets)
|
# Add any paths that contain custom static files (such as style sheets)
|
||||||
# here, relative to this directory. They are copied after the builtin
|
# here, relative to this directory. They are copied after the builtin
|
||||||
# static files, so a file named "default.css" will overwrite the builtin
|
# static files, so a file named "default.css" will overwrite the builtin
|
||||||
# "default.css".
|
# "default.css".
|
||||||
html_static_path = ['_static']
|
html_static_path = ["_static"]
|
||||||
|
|
||||||
# If not '', a 'Last updated on:' timestamp is inserted at every page
|
# If not '', a 'Last updated on:' timestamp is inserted at every page
|
||||||
# bottom, using the given strftime format.
|
# 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
|
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||||
# typographically correct entities.
|
# typographically correct entities.
|
||||||
#html_use_smartypants = True
|
# html_use_smartypants = True
|
||||||
|
|
||||||
# Custom sidebar templates, maps document names to template names.
|
# Custom sidebar templates, maps document names to template names.
|
||||||
#html_sidebars = {}
|
# html_sidebars = {}
|
||||||
|
|
||||||
# Additional templates that should be rendered to pages, maps page names
|
# Additional templates that should be rendered to pages, maps page names
|
||||||
# to template names.
|
# to template names.
|
||||||
#html_additional_pages = {}
|
# html_additional_pages = {}
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#html_domain_indices = True
|
# html_domain_indices = True
|
||||||
|
|
||||||
# If false, no index is generated.
|
# 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.
|
# 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.
|
# 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.
|
# If true, "Created using Sphinx" is shown in the HTML footer.
|
||||||
# Default is True.
|
# Default is True.
|
||||||
#html_show_sphinx = True
|
# html_show_sphinx = True
|
||||||
|
|
||||||
# If true, "(C) Copyright ..." is shown in the HTML footer.
|
# If true, "(C) Copyright ..." is shown in the HTML footer.
|
||||||
# Default is True.
|
# Default is True.
|
||||||
#html_show_copyright = True
|
# html_show_copyright = True
|
||||||
|
|
||||||
# If true, an OpenSearch description file will be output, and all pages
|
# 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
|
# 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.
|
# 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").
|
# 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.
|
# Output file base name for HTML help builder.
|
||||||
htmlhelp_basename = 'bot_zdoc'
|
htmlhelp_basename = "bot_zdoc"
|
||||||
|
|
||||||
|
|
||||||
# -- Options for LaTeX output ------------------------------------------
|
# -- Options for LaTeX output ------------------------------------------
|
||||||
|
@ -196,10 +196,8 @@ htmlhelp_basename = 'bot_zdoc'
|
||||||
latex_elements = {
|
latex_elements = {
|
||||||
# The paper size ('letterpaper' or 'a4paper').
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
#'papersize': 'letterpaper',
|
#'papersize': 'letterpaper',
|
||||||
|
|
||||||
# The font size ('10pt', '11pt' or '12pt').
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
#'pointsize': '10pt',
|
#'pointsize': '10pt',
|
||||||
|
|
||||||
# Additional stuff for the LaTeX preamble.
|
# Additional stuff for the LaTeX preamble.
|
||||||
#'preamble': '',
|
#'preamble': '',
|
||||||
}
|
}
|
||||||
|
@ -208,44 +206,38 @@ latex_elements = {
|
||||||
# (source start file, target name, title, author, documentclass
|
# (source start file, target name, title, author, documentclass
|
||||||
# [howto/manual]).
|
# [howto/manual]).
|
||||||
latex_documents = [
|
latex_documents = [
|
||||||
('index', 'bot_z.tex',
|
("index", "bot_z.tex", u"Bot_Z Documentation", u"Leonardo Barcaroli", "manual")
|
||||||
u'Bot_Z Documentation',
|
|
||||||
u'Leonardo Barcaroli', 'manual'),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# The name of an image file (relative to this directory) to place at
|
# The name of an image file (relative to this directory) to place at
|
||||||
# the top of the title page.
|
# the top of the title page.
|
||||||
#latex_logo = None
|
# latex_logo = None
|
||||||
|
|
||||||
# For "manual" documents, if this is true, then toplevel headings
|
# For "manual" documents, if this is true, then toplevel headings
|
||||||
# are parts, not chapters.
|
# are parts, not chapters.
|
||||||
#latex_use_parts = False
|
# latex_use_parts = False
|
||||||
|
|
||||||
# If true, show page references after internal links.
|
# If true, show page references after internal links.
|
||||||
#latex_show_pagerefs = False
|
# latex_show_pagerefs = False
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# 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.
|
# Documents to append as an appendix to all manuals.
|
||||||
#latex_appendices = []
|
# latex_appendices = []
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#latex_domain_indices = True
|
# latex_domain_indices = True
|
||||||
|
|
||||||
|
|
||||||
# -- Options for manual page output ------------------------------------
|
# -- Options for manual page output ------------------------------------
|
||||||
|
|
||||||
# One entry per manual page. List of tuples
|
# One entry per manual page. List of tuples
|
||||||
# (source start file, name, description, authors, manual section).
|
# (source start file, name, description, authors, manual section).
|
||||||
man_pages = [
|
man_pages = [("index", "bot_z", u"Bot_Z Documentation", [u"Leonardo Barcaroli"], 1)]
|
||||||
('index', 'bot_z',
|
|
||||||
u'Bot_Z Documentation',
|
|
||||||
[u'Leonardo Barcaroli'], 1)
|
|
||||||
]
|
|
||||||
|
|
||||||
# If true, show URL addresses after external links.
|
# If true, show URL addresses after external links.
|
||||||
#man_show_urls = False
|
# man_show_urls = False
|
||||||
|
|
||||||
|
|
||||||
# -- Options for Texinfo output ----------------------------------------
|
# -- Options for Texinfo output ----------------------------------------
|
||||||
|
@ -254,22 +246,25 @@ man_pages = [
|
||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [
|
||||||
('index', 'bot_z',
|
(
|
||||||
u'Bot_Z Documentation',
|
"index",
|
||||||
u'Leonardo Barcaroli',
|
"bot_z",
|
||||||
'bot_z',
|
u"Bot_Z Documentation",
|
||||||
'One line description of project.',
|
u"Leonardo Barcaroli",
|
||||||
'Miscellaneous'),
|
"bot_z",
|
||||||
|
"One line description of project.",
|
||||||
|
"Miscellaneous",
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
# Documents to append as an appendix to all manuals.
|
# Documents to append as an appendix to all manuals.
|
||||||
#texinfo_appendices = []
|
# texinfo_appendices = []
|
||||||
|
|
||||||
# If false, no module index is generated.
|
# If false, no module index is generated.
|
||||||
#texinfo_domain_indices = True
|
# texinfo_domain_indices = True
|
||||||
|
|
||||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
# 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.
|
# 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"
|
GECKO_RELEASE_PATH = "https://github.com/mozilla/geckodriver"
|
||||||
PKG_NAME = 'bot_z'
|
PKG_NAME = "bot_z"
|
||||||
VERSION = '0.1.0'
|
VERSION = "0.1.0"
|
||||||
AUTHOR = 'blallo'
|
AUTHOR = "blallo"
|
||||||
AUTHOR_EMAIL = 'blallo@autistici.org'
|
AUTHOR_EMAIL = "blallo@autistici.org"
|
||||||
BIN_PATH = 'bin/geckodriver'
|
BIN_PATH = "bin/geckodriver"
|
||||||
|
|
||||||
with open('README.md') as readme_file:
|
with open("README.md") as readme_file:
|
||||||
readme = readme_file.read()
|
readme = readme_file.read()
|
||||||
|
|
||||||
requirements = [
|
requirements = ["Click>=6.0", "selenium>=3.141.0"]
|
||||||
'Click>=6.0',
|
|
||||||
'selenium>=3.141.0',
|
|
||||||
]
|
|
||||||
|
|
||||||
setup_requirements = [
|
setup_requirements = [] # type: T.List[str]
|
||||||
] # type: T.List[str]
|
|
||||||
|
|
||||||
test_requirements = [
|
test_requirements = [] # type: T.List[str]
|
||||||
] # type: T.List[str]
|
|
||||||
|
|
||||||
|
|
||||||
class GitTags(HTMLParser):
|
class GitTags(HTMLParser):
|
||||||
|
@ -48,7 +43,7 @@ class GitTags(HTMLParser):
|
||||||
|
|
||||||
def handle_starttag(self, tag, attrs):
|
def handle_starttag(self, tag, attrs):
|
||||||
dattrs = dict(attrs)
|
dattrs = dict(attrs)
|
||||||
if 'commit-title' in dattrs.get('class', ''):
|
if "commit-title" in dattrs.get("class", ""):
|
||||||
self.take_next = 1
|
self.take_next = 1
|
||||||
|
|
||||||
def handle_data(self, data):
|
def handle_data(self, data):
|
||||||
|
@ -57,7 +52,7 @@ class GitTags(HTMLParser):
|
||||||
elif self.take_next == 1:
|
elif self.take_next == 1:
|
||||||
self.take_next = 2
|
self.take_next = 2
|
||||||
elif 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
|
self.take_next = 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,9 +78,9 @@ def find_latest_version(url: str) -> str:
|
||||||
"""
|
"""
|
||||||
Retrieves latest geckodriver tag.
|
Retrieves latest geckodriver tag.
|
||||||
"""
|
"""
|
||||||
tag_page = retrieve_page('{}/tags'.format(url))
|
tag_page = retrieve_page("{}/tags".format(url))
|
||||||
gt = GitTags()
|
gt = GitTags()
|
||||||
gt.feed(tag_page.decode('utf-8'))
|
gt.feed(tag_page.decode("utf-8"))
|
||||||
gt.tags.sort()
|
gt.tags.sort()
|
||||||
return gt.tags[-1]
|
return gt.tags[-1]
|
||||||
|
|
||||||
|
@ -109,9 +104,8 @@ def ensure_local_folder() -> None:
|
||||||
|
|
||||||
|
|
||||||
def assemble_driver_uri(
|
def assemble_driver_uri(
|
||||||
version: T.Optional[str]=None,
|
version: T.Optional[str] = None, platform: T.Optional[str] = None
|
||||||
platform: T.Optional[str]=None
|
) -> str:
|
||||||
) -> str:
|
|
||||||
"""
|
"""
|
||||||
Selects the right geckodriver URI.
|
Selects the right geckodriver URI.
|
||||||
"""
|
"""
|
||||||
|
@ -120,20 +114,17 @@ def assemble_driver_uri(
|
||||||
version = find_latest_version(GECKO_RELEASE_PATH)
|
version = find_latest_version(GECKO_RELEASE_PATH)
|
||||||
if not platform:
|
if not platform:
|
||||||
s_platform = sys.platform
|
s_platform = sys.platform
|
||||||
is_64bits = sys.maxsize > 2**32
|
is_64bits = sys.maxsize > 2 ** 32
|
||||||
if is_64bits:
|
if is_64bits:
|
||||||
platform = '{}64'.format(s_platform)
|
platform = "{}64".format(s_platform)
|
||||||
else:
|
else:
|
||||||
platform = '{}64'.format(s_platform)
|
platform = "{}64".format(s_platform)
|
||||||
if 'win' in platform:
|
if "win" in platform:
|
||||||
ext = 'zip'
|
ext = "zip"
|
||||||
else:
|
else:
|
||||||
ext = 'tar.gz'
|
ext = "tar.gz"
|
||||||
return '{base}/releases/download/{vers}/geckodriver-{vers}-{platform}.{ext}'.format(
|
return "{base}/releases/download/{vers}/geckodriver-{vers}-{platform}.{ext}".format(
|
||||||
base=GECKO_RELEASE_PATH,
|
base=GECKO_RELEASE_PATH, vers=version, platform=platform, ext=ext
|
||||||
vers=version,
|
|
||||||
platform=platform,
|
|
||||||
ext=ext
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -141,18 +132,18 @@ def download_driver_bin(uri: str, path: str) -> None:
|
||||||
"""
|
"""
|
||||||
Donwloads the geckodriver binary.
|
Donwloads the geckodriver binary.
|
||||||
"""
|
"""
|
||||||
name = uri.split('/')[-1]
|
name = uri.split("/")[-1]
|
||||||
filepath = os.path.join(path, name)
|
filepath = os.path.join(path, name)
|
||||||
print("[DRIVER] downloading '{}' to {}".format(uri, filepath))
|
print("[DRIVER] downloading '{}' to {}".format(uri, filepath))
|
||||||
content = retrieve_page(uri)
|
content = retrieve_page(uri)
|
||||||
try:
|
try:
|
||||||
with open(filepath, 'wb') as f:
|
with open(filepath, "wb") as f:
|
||||||
f.write(content)
|
f.write(content)
|
||||||
if name.endswith(".zip"):
|
if name.endswith(".zip"):
|
||||||
with zipfile.ZipFile(filepath, 'r') as z:
|
with zipfile.ZipFile(filepath, "r") as z:
|
||||||
z.extractall(path)
|
z.extractall(path)
|
||||||
elif name.endswith(".tar.gz"):
|
elif name.endswith(".tar.gz"):
|
||||||
with tarfile.open(filepath, 'r') as r:
|
with tarfile.open(filepath, "r") as r:
|
||||||
r.extractall(path)
|
r.extractall(path)
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Unrecognized file extension: %s", name)
|
raise RuntimeError("Unrecognized file extension: %s", name)
|
||||||
|
@ -160,15 +151,15 @@ def download_driver_bin(uri: str, path: str) -> None:
|
||||||
os.remove(filepath)
|
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
|
Performs all the postintallation flow, donwloading in the
|
||||||
right place the geckodriver binary.
|
right place the geckodriver binary.
|
||||||
"""
|
"""
|
||||||
# target_path = os.path.join(os.path.abspath(os.path.curdir), 'bot_z', 'bin')
|
# 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()
|
ensure_local_folder()
|
||||||
version = os.environ.get('BOTZ_GECKO_VERSION')
|
version = os.environ.get("BOTZ_GECKO_VERSION")
|
||||||
gecko_uri = assemble_driver_uri(version, platform)
|
gecko_uri = assemble_driver_uri(version, platform)
|
||||||
print("[POSTINSTALL] gecko_uri: {}".format(gecko_uri))
|
print("[POSTINSTALL] gecko_uri: {}".format(gecko_uri))
|
||||||
download_driver_bin(gecko_uri, target_path)
|
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
|
# From: https://stackoverflow.com/a/36902139
|
||||||
class CustomDevelopCommand(develop):
|
class CustomDevelopCommand(develop):
|
||||||
"""Custom installation for development mode."""
|
"""Custom installation for development mode."""
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
print("POSTINSTALL")
|
print("POSTINSTALL")
|
||||||
preinstall()
|
preinstall()
|
||||||
|
@ -207,12 +199,13 @@ class CustomDevelopCommand(develop):
|
||||||
|
|
||||||
class CustomInstallCommand(install):
|
class CustomInstallCommand(install):
|
||||||
"""Custom installation for installation mode."""
|
"""Custom installation for installation mode."""
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
opts = self.distribution.get_cmdline_options()
|
opts = self.distribution.get_cmdline_options()
|
||||||
platform = None
|
platform = None
|
||||||
if 'bdist_wheel' in opts:
|
if "bdist_wheel" in opts:
|
||||||
platform = translate_platform_to_gecko_vers(
|
platform = translate_platform_to_gecko_vers(
|
||||||
opts['bdist_wheel'].get('plat-name')
|
opts["bdist_wheel"].get("plat-name")
|
||||||
)
|
)
|
||||||
preinstall(platform)
|
preinstall(platform)
|
||||||
super().run()
|
super().run()
|
||||||
|
@ -224,13 +217,14 @@ class CustomBDistWheel(bdist_wheel):
|
||||||
Custom bdist_wheel command to ship the right binary
|
Custom bdist_wheel command to ship the right binary
|
||||||
of geckodriver.
|
of geckodriver.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def finalize_options(self):
|
def finalize_options(self):
|
||||||
super().finalize_options()
|
super().finalize_options()
|
||||||
self.root_is_pure = False
|
self.root_is_pure = False
|
||||||
|
|
||||||
def get_tag(self):
|
def get_tag(self):
|
||||||
python, abi, plat = super().get_tag()
|
python, abi, plat = super().get_tag()
|
||||||
python, abi = 'py3', 'none'
|
python, abi = "py3", "none"
|
||||||
return python, abi, plat
|
return python, abi, plat
|
||||||
|
|
||||||
|
|
||||||
|
@ -241,33 +235,29 @@ setup(
|
||||||
long_description=readme,
|
long_description=readme,
|
||||||
author=AUTHOR,
|
author=AUTHOR,
|
||||||
author_email=AUTHOR_EMAIL,
|
author_email=AUTHOR_EMAIL,
|
||||||
url='https://git.abbiamoundominio.org/blallo/BotZ',
|
url="https://git.abbiamoundominio.org/blallo/BotZ",
|
||||||
packages=find_packages(include=['bot_z']),
|
packages=find_packages(include=["bot_z"]),
|
||||||
cmdclass={
|
cmdclass={
|
||||||
'develop': CustomDevelopCommand,
|
"develop": CustomDevelopCommand,
|
||||||
'install': CustomInstallCommand,
|
"install": CustomInstallCommand,
|
||||||
'bdist_wheel': CustomBDistWheel,
|
"bdist_wheel": CustomBDistWheel,
|
||||||
},
|
},
|
||||||
entry_points={
|
entry_points={"console_scripts": ["bot_z=bot_z.cli:main"]},
|
||||||
'console_scripts': [
|
package_data={"bot_z": ["bin/geckodriver"]},
|
||||||
'bot_z=bot_z.cli:main'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
package_data = {'bot_z': ['bin/geckodriver']},
|
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
install_requires=requirements,
|
install_requires=requirements,
|
||||||
license="GLWTS Public Licence",
|
license="GLWTS Public Licence",
|
||||||
zip_safe=False,
|
zip_safe=False,
|
||||||
keywords='bot_z',
|
keywords="bot_z",
|
||||||
classifiers=[
|
classifiers=[
|
||||||
'Development Status :: 2 - Pre-Alpha',
|
"Development Status :: 2 - Pre-Alpha",
|
||||||
'Intended Audience :: Developers',
|
"Intended Audience :: Developers",
|
||||||
'License :: GLWTS Public Licence',
|
"License :: GLWTS Public Licence",
|
||||||
'Natural Language :: English',
|
"Natural Language :: English",
|
||||||
'Programming Language :: Python :: 3',
|
"Programming Language :: Python :: 3",
|
||||||
'Programming Language :: Python :: 3.7',
|
"Programming Language :: Python :: 3.7",
|
||||||
],
|
],
|
||||||
test_suite='pytest',
|
test_suite="pytest",
|
||||||
tests_require=test_requirements,
|
tests_require=test_requirements,
|
||||||
setup_requires=setup_requirements,
|
setup_requires=setup_requirements,
|
||||||
)
|
)
|
||||||
|
|
|
@ -28,7 +28,7 @@ class TestBot_z(unittest.TestCase):
|
||||||
runner = CliRunner()
|
runner = CliRunner()
|
||||||
result = runner.invoke(cli.main)
|
result = runner.invoke(cli.main)
|
||||||
assert result.exit_code == 0
|
assert result.exit_code == 0
|
||||||
assert 'bot_z.cli.main' in result.output
|
assert "bot_z.cli.main" in result.output
|
||||||
help_result = runner.invoke(cli.main, ['--help'])
|
help_result = runner.invoke(cli.main, ["--help"])
|
||||||
assert help_result.exit_code == 0
|
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