Exemple #1
0
    def _convert_data(self, raw_data: RawImageData) -> ImageData:
        """
        Cleans data from a picture that a user sends

        :param raw_data: object with raw info about a picture
        :return: object with formatted info about a picture
        """

        date_time = (str(raw_data.date_time) if raw_data.date_time else None)

        # Merge a brand and model together
        camera = f'{raw_data.camera_brand} {raw_data.camera_model}'
        lens = f'{raw_data.lens_brand} {raw_data.lens_model}'

        # Get rid of repetitive words
        camera = (self._dedupe_string(camera) if camera != ' ' else None)
        lens = (self._dedupe_string(lens) if lens != ' ' else None)

        camera, lens = self._check_camera_tags(camera, lens)

        try:
            latitude, longitude = self._convert_coordinates(raw_data)
        except (InvalidCoordinates, NoCoordinates):
            address = country = latitude = longitude = None
        else:
            try:
                address, country = self._get_address(latitude, longitude)
            except Exception as e:
                log.warning(e)
                address = country = None

        return ImageData(self.user, date_time, camera, lens, address, country,
                         latitude, longitude)
Exemple #2
0
    def execute_query(self,
                      query: str,
                      parameters: tuple = None,
                      trials: int = 0):
        """
        Executes a given query

        :param query: query to execute
        :param parameters: parameters for query
        :param trials: integer that denotes number of trials to execute
        a query in case of known errors
        :return: cursor object
        """
        if not self.conn or not self.conn.open:
            self.connect()

        try:
            cursor = self.conn.cursor()
            cursor.execute(query, parameters)

        # try to reconnect if MySQL server has gone away
        except MySQLdb.OperationalError as e:

            # (2013, Lost connection to MySQL server during query)
            # (2006, Server has gone away)
            if e.args[0] in [2006, 2013]:
                log.info(e)

                self.connect()
                if trials <= 3:
                    # trying to execute query one more time
                    trials += 1
                    log.warning(e)
                    log.info("Trying execute the query again...")
                    return self.execute_query(query, parameters, trials)

                if trials > 3:
                    log.error(e)
                    log.warning("Ran out of limit of trials...")
                    raise DatabaseConnectionError("Cannot connect to the "
                                                  "database")
            else:
                log.error(e)
                raise
        except Exception as e:
            log.error(e)
            raise
        else:
            return cursor
Exemple #3
0
    def clean_cache(self, limit: int) -> None:
        """
        Method that remove several User objects from cache - the least 
        active users

        :param limit: number of the users that the method should remove
        from cache
        :return: None
        """

        log.info('Figuring out the least active users...')
        # Select users that the least active recently
        user_ids = tuple(self.users.keys())
        query = ('SELECT chat_id '
                 'FROM photo_queries_table2 '
                 f'WHERE chat_id in {user_ids} '
                 'GROUP BY chat_id '
                 'ORDER BY MAX(time) '
                 f'LIMIT %s')

        parameters = limit,

        try:
            cursor = db.execute_query(query, parameters)
        except DatabaseConnectionError:
            log.error("Can't figure out the least active users...")
            return

        if not cursor.rowcount:
            log.warning("There are no users in the db")
            return

        # Make list out of tuple of tuples that is returned by MySQL
        least_active_users = [chat_id[0] for chat_id in cursor.fetchall()]
        log.info('Removing %d least active users from cache...', limit)
        num_deleted_entries = 0
        for entry in least_active_users:
            log.debug('Deleting %s...', entry)
            deleted_entry = self.users.pop(entry, None)
            if deleted_entry:
                num_deleted_entries += 1
        log.debug("%d users were removed from cache.", num_deleted_entries)
Exemple #4
0
    def start_bot(self) -> None:
        """
        Method to get the bot started

        Wrapper around self._run just for the sake of making it more reliable
        and reconnect in case of errors. And to store time when bot started to
        work

        :return: None
        """
        try:
            self.start_time = datetime.now()
            self._run()

        except requests.exceptions.ReadTimeout as e:
            log.error(e)
            self.stop_polling()
            log.warning('Pausing bot for 30 seconds...')
            time.sleep(30)
            log.warning('Try to start the bot again...')
            self._run()
Exemple #5
0
    def _check_camera_tags(*tags: str) -> List[str]:
        """
        Converts camera and lens name to proper ones

        Function that convert stupid code name of a smartphone or a camera
        from EXIF to a meaningful one by looking a collation in a special MySQL
        table For example instead of just Nikon there can be
        NIKON CORPORATION in EXIF

        :param tags: a tuple with a name of a camera and lens from EXIF
        :return: list with one or two strings which are name of
        camera and/or lens. If there is not better name for the gadget
        in database, function just returns name how it is
        """
        checked_tags = []

        for tag in tags:
            if tag:  # If there was this information inside EXIF of the photo
                tag = str(tag).strip()
                log.info('Looking up collation for %s', tag)
                query = ('SELECT right_tag '
                         'FROM tag_table '
                         'WHERE wrong_tag=%s')
                parameters = tag,
                cursor = db.execute_query(query, parameters)
                if not cursor:
                    log.error("Can't check the tag because of the db error")
                    log.warning("Tag will stay as is.")
                    continue
                if cursor.rowcount:
                    # Get appropriate tag from the table
                    tag = cursor.fetchone()[0]
                    log.info('Tag after looking up in tag_tables - %s.', tag)

            checked_tags.append(tag)
        return checked_tags
Exemple #6
0
def get_most_popular_items(item_type: str, message: Message) -> str:
    """
    Get the most common cameras/lenses/countries from database and
    make list of them

    :param item_type: string with column name to choose between cameras,
    lenses and countries
    :param message: telebot object with info about user and his message
    :return: string which is either list of most common
    cameras/lenses/countries or message which states that list is
    empty
    """

    user = users.find_one(message)

    def tuple_to_ordered_str_list(list_of_gadgets: Tuple[Tuple[str]]) -> str:
        """
        Converts Python list to ordered list as a string

        Example:
        1. Canon 80D
        2. iPhone 4S

        :param list_of_gadgets: tuple of tuples with string where every string
        is a name of a camera or lens or a country
        :return: ordered list as a string
        """

        string_roaster = ''
        index = 1
        for item in list_of_gadgets:
            if not item[0]:
                continue
            string_roaster += '{}. {}\n'.format(index, item[0])
            index += 1
        return string_roaster

    log.debug('Evaluating most popular things...')

    # This query returns item types in order where the first one item
    # has the highest number of occurrences
    # in a given column

    query = (f'SELECT {item_type} FROM photo_queries_table2 '
             f'GROUP BY {item_type} '
             f'ORDER BY count({item_type}) '
             'DESC')

    try:
        cursor = db.execute_query(query)
    except DatabaseConnectionError:
        log.error("Can't evaluate a list of the most popular items")
        return messages[user.language]['doesnt work']

    # Almost impossible case but still
    if not cursor.rowcount:
        log.warning('There is nothing in the main database table')
        bot.send_message(chat_id=config.MY_TELEGRAM,
                         text='There is nothing in the main database table')
        return messages[user.language]['no_top']

    popular_items = cursor.fetchall()
    log.info('Finish evaluating the most popular items')
    return tuple_to_ordered_str_list(popular_items[:30])