# coding: utf-8 """ Main entry point of the Flatisfy code. """ from __future__ import absolute_import, print_function, unicode_literals import argparse import logging import sys logging.basicConfig() # pylint: disable=locally-disabled,wrong-import-position import flatisfy.config from flatisfy import cmds from flatisfy import data from flatisfy import fetch from flatisfy import tools from flatisfy import tests # pylint: enable=locally-disabled,wrong-import-position LOGGER = logging.getLogger("flatisfy") def parse_args(argv=None): """ Create parser and parse arguments. """ parser = argparse.ArgumentParser(prog="Flatisfy", description="Find the perfect flat.") # Parent parser containing arguments common to any subcommand parent_parser = argparse.ArgumentParser(add_help=False) parent_parser.add_argument("--data-dir", help="Location of Flatisfy data directory.") parent_parser.add_argument("--config", help="Configuration file to use.") parent_parser.add_argument( "--passes", choices=[0, 1, 2, 3], type=int, help="Number of passes to do on the filtered data.", ) parent_parser.add_argument("--max-entries", type=int, help="Maximum number of entries to fetch.") parent_parser.add_argument("-v", "--verbose", action="store_true", help="Verbose logging output.") parent_parser.add_argument("-vv", action="store_true", help="Debug logging output.") parent_parser.add_argument( "--constraints", type=str, help="Comma-separated list of constraints to consider.", ) # Subcommands subparsers = parser.add_subparsers(dest="cmd", help="Available subcommands") # Build data subcommand subparsers.add_parser("build-data", parents=[parent_parser], help="Build necessary data") # Init config subcommand parser_init_config = subparsers.add_parser( "init-config", parents=[parent_parser], help="Initialize empty configuration." ) parser_init_config.add_argument("output", nargs="?", help="Output config file. Use '-' for stdout.") # Fetch subcommand parser subparsers.add_parser("fetch", parents=[parent_parser], help="Fetch housings posts") # Filter subcommand parser parser_filter = subparsers.add_parser( "filter", parents=[parent_parser], help="Filter housings posts according to constraints in config.", ) parser_filter.add_argument( "--input", help=( "Optional JSON dump of the housings post to filter. If provided, " "no additional fetching of infos is done, and the script outputs " "a filtered JSON dump on stdout. If not provided, update status " "of the flats in the database." ), ) # Import subcommand parser import_filter = subparsers.add_parser("import", parents=[parent_parser], help="Import housing posts in database.") import_filter.add_argument( "--new-only", action="store_true", help=("Download new housing posts only but do not refresh existing ones"), ) # Purge subcommand parser subparsers.add_parser("purge", parents=[parent_parser], help="Purge database.") # Serve subcommand parser parser_serve = subparsers.add_parser("serve", parents=[parent_parser], help="Serve the web app.") parser_serve.add_argument("--port", type=int, help="Port to bind to.") parser_serve.add_argument("--host", help="Host to listen on.") # Test subcommand parser subparsers.add_parser("test", parents=[parent_parser], help="Unit testing.") return parser, parser.parse_args(argv) def main(): """ Main module code. """ # pylint: disable=locally-disabled,too-many-branches # Parse arguments parser, args = parse_args() # Set logger if getattr(args, 'vv', False): logging.getLogger("").setLevel(logging.DEBUG) logging.getLogger("titlecase").setLevel(logging.INFO) logging.getLogger("sqlalchemy.engine").setLevel(logging.INFO) elif getattr(args, 'verbose', False): logging.getLogger("").setLevel(logging.INFO) # sqlalchemy INFO level is way too loud, just stick with WARNING logging.getLogger("sqlalchemy.engine").setLevel(logging.WARNING) else: logging.getLogger("").setLevel(logging.WARNING) logging.getLogger("sqlalchemy.engine").setLevel(logging.WARNING) # Init-config command if args.cmd == "init-config": flatisfy.config.init_config(args.output) sys.exit(0) else: if not args.cmd: parser.print_help() sys.exit(0) # Load config if args.cmd == "build-data": # Data not yet built, do not use it in config checks config = flatisfy.config.load_config(args, check_with_data=False) else: config = flatisfy.config.load_config(args, check_with_data=True) if config is None: LOGGER.error( "Invalid configuration. Exiting. " "Run init-config before if this is the first time " "you run Flatisfy." ) sys.exit(1) # Purge command if args.cmd == "purge": cmds.purge_db(config) return # Build data files command if args.cmd == "build-data": data.preprocess_data(config, force=True) return # Fetch command if args.cmd == "fetch": # Fetch and filter flats list fetched_flats = fetch.fetch_flats(config) fetched_flats = cmds.filter_fetched_flats(config, fetched_flats=fetched_flats, fetch_details=True) # Sort by cost fetched_flats = {k: tools.sort_list_of_dicts_by(v["new"], "cost") for k, v in fetched_flats.items()} print(tools.pretty_json(fetched_flats)) return # Filter command elif args.cmd == "filter": # Load and filter flats list if args.input: fetched_flats = fetch.load_flats_from_file(args.input, config) fetched_flats = cmds.filter_fetched_flats(config, fetched_flats=fetched_flats, fetch_details=False) # Sort by cost fetched_flats = {k: tools.sort_list_of_dicts_by(v["new"], "cost") for k, v in fetched_flats.items()} # Output to stdout print(tools.pretty_json(fetched_flats)) else: cmds.import_and_filter(config, load_from_db=True) return # Import command elif args.cmd == "import": cmds.import_and_filter(config, load_from_db=False, new_only=args.new_only) return # Serve command elif args.cmd == "serve": cmds.serve(config) return # Tests command elif args.cmd == "test": tests.run() return if __name__ == "__main__": try: main() except KeyboardInterrupt: pass