diff --git a/flatisfy/config.py b/flatisfy/config.py index be1cee0..aa97508 100644 --- a/flatisfy/config.py +++ b/flatisfy/config.py @@ -34,6 +34,7 @@ DEFAULT_CONFIG = { "cost": (None, None), # (min, max) in currency unit "rooms": (None, None), # (min, max) "bedrooms": (None, None), # (min, max) + "minimum_photos": None, "time_to": {} # Dict mapping names to {"gps": [lat, lng], # "time": (min, max) } # Time is in seconds @@ -138,6 +139,11 @@ def validate_config(config, check_with_data): assert isinstance(constraint["type"], str) assert constraint["type"].upper() in ["RENT", "SALE", "SHARING"] + assert "minimum_photos" in constraint + if constraint["minimum_photos"]: + assert isinstance(constraint["minimum_photos"], int) + assert constraint["minimum_photos"] >= 0 + assert "house_types" in constraint assert constraint["house_types"] for house_type in constraint["house_types"]: diff --git a/flatisfy/filters/__init__.py b/flatisfy/filters/__init__.py index 0086dde..2bbf2f0 100644 --- a/flatisfy/filters/__init__.py +++ b/flatisfy/filters/__init__.py @@ -26,7 +26,6 @@ def refine_with_housing_criteria(flats_list, constraint): :param flats_list: A list of flats dict to filter. :param constraint: The constraint that the ``flats_list`` should satisfy. - :param config: A config dict. :return: A tuple of flats to keep and flats to delete. """ # For each flat, the associated `is_ok` value indicate whether it should be @@ -80,6 +79,52 @@ def refine_with_housing_criteria(flats_list, constraint): ] ) + +def refine_with_minimum_photos(flats_list, constraint): + """ + Filter a list of flats according to the minimum number of photos criterion. + + .. note :: This has to be done in a separate function and not with the + other criterias as photos are only fetched in the second pass. + + :param flats_list: A list of flats dict to filter. + :param constraint: The constraint that the ``flats_list`` should satisfy. + :return: A tuple of flats to keep and flats to delete. + """ + # For each flat, the associated `is_ok` value indicate whether it should be + # kept or discarded. + is_ok = [True for _ in flats_list] + + for i, flat in enumerate(flats_list): + # Check number of pictures + has_enough_photos = tools.is_within_interval( + flat.get('photos', []), + constraint['minimum_photos'], + None + ) + if not has_enough_photos: + LOGGER.info( + "Flat %s only has %d photos, it should have at least %d.", + flat["id"], + len(flat['photos']), + constraint['minimum_photos'] + ) + is_ok[i] = False + + return ( + [ + flat + for i, flat in enumerate(flats_list) + if is_ok[i] + ], + [ + flat + for i, flat in enumerate(flats_list) + if not is_ok[i] + ] + ) + + @tools.timeit def first_pass(flats_list, constraint, config): """ @@ -157,6 +202,10 @@ def second_pass(flats_list, constraint, config): flats_list, ignored_list = refine_with_housing_criteria(flats_list, constraint) + # Remove return housing posts which do not have enough photos + flats_list, ignored_list = refine_with_minimum_photos(flats_list, + constraint) + return { "new": flats_list, "ignored": ignored_list,