"""
Geolocate argument parser module.
Programmed by: Dante Signal31
email: dante.signal31@gmail.com
"""
import argparse
import sys
import geolocate.classes.config as config
import geolocate.classes.parser as parser
# These arguments activate functions with their same name. True or False depends
# on passing in user arguments to called function or not.
MUST_PASS_IN_USER_ARGUMENTS = {"show_enabled_locators": False,
"set_locators_preference": True,
"show_disabled_locators": False,
"reset_locators_preference": False,
"set_user": True,
"set_password": True,
"show_user": False,
"show_password": False}
# This arguments don't activate a function with their same name.
NOT_CALLABLE_ARGUMENTS = {"verbosity", "text_to_parse", "stream_mode"}
[docs]def parse_arguments():
verbosity_choices = parser.GeolocateInputParser.VERBOSITY_LEVELS
arg_parser = argparse.ArgumentParser(description="Locate IP adresses "
"in given text.\n",
epilog="This program is possible "
"thanks to Maxmind GeoIP "
"database "
"<http://www.maxmind.com> and "
"their API.")
data_input_arguments = arg_parser.add_mutually_exclusive_group()
data_input_arguments.add_argument(dest="text_to_parse",
metavar="\"text to parse\"",
nargs="?", type=str, default=None,
help="Text to analyze surrounded by "
"double quotes.")
data_input_arguments.add_argument("-s", "--stream",
dest="stream_mode",
action="store_true", default=False,
help="Program will analyze piped output "
"from another program.")
arg_parser.add_argument("-v", "--verbosity", dest="verbosity",
choices=verbosity_choices, type=int, default=0,
help="0-3 The higher the more geodata.")
arg_parser.add_argument("-l", "--show_enabled",
dest="show_enabled_locators",
action="store_true", default=False,
help="Show enabled locators ordered by preference.")
arg_parser.add_argument("-p", "--set_preference",
dest="set_locators_preference",
nargs="*", default=None,
help="Set preferred locator order.",
metavar="locator")
arg_parser.add_argument("-d", "--show_disabled",
dest="show_disabled_locators", action="store_true",
default=False, help="Show disabled locators.")
arg_parser.add_argument("-r", "--reset", dest="reset_locators_preference",
action="store_true", default=False,
help="Restore default locator order.")
arg_parser.add_argument("-u", "--set_user",
dest="set_user",
type=str, default=None,
help="Set user for webservice database access.",
metavar="account_id")
arg_parser.add_argument("-w", "--set_password",
dest="set_password",
type=str, default=None,
help="Set password for webservice database access.",
metavar="account_password")
arg_parser.add_argument("-i", "--show_user",
dest="show_user", action="store_true",
default=False, help="Show user configured for "
"webservice access.")
arg_parser.add_argument("-k", "--show_password",
dest="show_password", action="store_true",
default=False, help="Show password configured for "
"webservice access.")
return arg_parser.parse_args()
[docs]def show_enabled_locators():
""" Print in console enabled locators ordered by preference.
:return: None
"""
enabled_locators = _get_enabled_locators_list()
_print_locators_list("Enabled locators:", enabled_locators)
[docs]def set_locators_preference(arguments):
""" Change locators list with new list given in arguments.
:param arguments: Arguments object returned by ArgumentParser.parse_args()
:type arguments: Namespace
:return: None
"""
with config.OpenConfigurationToUpdate() as f:
f.configuration.locators_preference = arguments.set_locators_preference
[docs]def show_disabled_locators():
""" Print in console enabled locators ordered by preference.
:return: None
"""
enabled_locators_set = set(_get_enabled_locators_list())
complete_locators_set = set(config.DEFAULT_LOCATORS_PREFERENCE)
disabled_locators_set = complete_locators_set - enabled_locators_set
_print_locators_list("Disabled locators:", disabled_locators_set)
[docs]def reset_locators_preference():
""" Sets back locators list to it's default value.
:return: None
"""
with config.OpenConfigurationToUpdate() as f:
f.configuration.reset_locators_preference()
def _get_enabled_locators_list():
"""
:return: Configuration locators preference.
:rtype: list
"""
configuration = config.load_configuration()
enabled_locators = configuration.locators_preference
return enabled_locators
[docs]def set_user(arguments):
""" Set user for webservice database access.
:param arguments: Arguments object returned by ArgumentParser.parse_args()
:type arguments: Namespace
:return: None
"""
with config.OpenConfigurationToUpdate() as f:
f.configuration.user_id = arguments.set_user
[docs]def set_password(arguments):
""" Set password for webservice database access.
:param arguments: Arguments object returned by ArgumentParser.parse_args()
:type arguments: Namespace
:return: None
"""
with config.OpenConfigurationToUpdate() as f:
f.configuration.license_key = arguments.set_password
[docs]def show_user():
""" Print on console user configured for webservice database access.
:return: None
"""
configuration = config.load_configuration()
output_string = "User:\n" \
"{0}".format(configuration.user_id)
print(output_string)
[docs]def show_password():
""" Print on console password configured for webservice database access.
:return: None
"""
configuration = config.load_configuration()
output_string = "Password:\n" \
"{0}".format(configuration.license_key)
print(output_string)
def _print_locators_list(header, locators_list):
""" Print on console a formatted list of locators.
:param header: Title of list.
:type header: str
:param locators_list: Locators list.
:type locators_list: list or set
:return: None
"""
components = list(locators_list)
components.insert(0, header)
message = "\n".join(components)
print(message)
[docs]def process_optional_parameters(arguments):
""" Take all optional arguments given by user and run one by one all
functions assigned to each of them.
:param arguments: Arguments object returned by ArgumentParser.parse_args()
:type arguments: Namespace
:return: None
"""
functions_to_execute = _get_functions_to_execute(arguments)
for functions in functions_to_execute:
try:
_execute_function(functions, arguments)
except (NoFunctionAssignedToArgument, config.UnknownLocators) as e:
sys.exit(". ".join([e.message, "Exiting"]))
def _get_functions_to_execute(arguments):
"""
:param arguments: Arguments object returned by ArgumentParser.parse_args()
:type arguments: Namespace
:return: Function names set to execute.
:rtype: set
"""
valid_arguments = _get_user_arguments(arguments)
functions_names_set = {argument for argument in valid_arguments
if getattr(arguments, argument)}
return functions_names_set
def _get_user_arguments(arguments):
""" Get public user attributes of arguments object.
Arguments set by user are defined public in object returned by
ArgumentParser.parse_args(). Built-in attributes in that object are defined
"private" with "_" o "__" prefix.
:param arguments: Arguments object returned by ArgumentParser.parse_args()
:type arguments: Namespace
:return: Public attribute list of arguments object.
:rtype: set
"""
attribute_list = dir(arguments)
public_attributes_set = {argument for argument in attribute_list
if not argument.startswith("_")}
public_attributes_set = _remove_non_user_attributes(public_attributes_set)
return public_attributes_set
def _remove_non_user_attributes(attributes_set):
""" Takes out from attribute set public attributes not defined by user.
:param attributes_set: Public attribute list of arguments object.
:type attributes_set: set
:return: Public attribute list of arguments object without non user attributes.
:rtype: set
"""
# Arguments object returned by ArgumentParser.parse_args() include by
# default "index" and "count" public attributes. We don't need them so we
# strip them off. Arguments "verbosity", "text_to_parse" and "stream_mode"
# is not an optional parameter and shouldn't be processed as one.
non_user_attributes = {"index", "count"} | NOT_CALLABLE_ARGUMENTS
user_attributes = attributes_set.difference(non_user_attributes)
return user_attributes
def _execute_function(argument, arguments):
""" Execute function assigned to given argument.
:param argument: Argument to search a function assigned for.
:param arguments: Arguments object returned by ArgumentParser.parse_args()
:type arguments: Namespace
:return: None
:raise: NoFunctionAssignedToArgument
"""
try:
if MUST_PASS_IN_USER_ARGUMENTS[argument]:
# Arguments names are equal to names of functions to call.
_call_function(argument, arguments)
else:
_call_function(argument)
except KeyError:
raise NoFunctionAssignedToArgument(argument)
def _call_function(function_name, arguments=None):
""" Call given function and pass it in arguments if they are given.
:param function_name: Function to call.
:type function_name: str
:param arguments: Arguments object returned by ArgumentParser.parse_args()
:type arguments: Namespace
:return: None
"""
function = globals().get(function_name)
if arguments is None:
function()
else:
function(arguments)
[docs]class NoFunctionAssignedToArgument(Exception):
""" User has given and argument that has no function assigned yet."""
[docs] def __init__(self, argument):
self.argument = argument
self.message = "Sorry, I don't know what to do " \
"with argument: {0}".format(self.argument)
Exception.__init__(self, self.message)