<commit_before>'''Persistent token cache management for the Flickr API'''

import os.path
import logging
import time
import sqlite3

from .exceptions import LockingError, CacheDatabaseError
from auth import FlickrAccessToken

LOG = logging.getLogger(__name__)

__all__ = ('SimpleTokenCache', 'OAuthTokenCache')


class SimpleTokenCache(object):
    '''In-memory token cache.'''

    def __init__(self):
        self._token = None

    @property
    def token(self):
        return self._token

    @token.setter
    def token(self, token):
        self._token = token

    @token.deleter
    def token(self):
        self._token = None

    def forget(self):
        '''Removes the cached token'''

        del self.token


class TokenCache(object):
    '''On-disk persistent token cache for a single application.

    The application is identified by the API key used. Per
    application multiple users are supported, with a single
    token per user.
    '''

    def __init__(self, api_key, username=None):
        '''Creates a new token cache instance'''

        self.api_key = api_key
        self.username = username
        self.memory = {}
        self.path = os.path.join("~", ".flickr")

    def get_cached_token_path(self):
        """Return the directory holding the app data."""
        return os.path.expanduser(os.path.join(self.path, self.api_key))

    def get_cached_token_filename(self):
        """Return the full pathname of the cached token file."""

        if self.username:
            filename = 'auth-%s.token' % self.username
        else:
            filename = 'auth.token'

        return os.path.join(self.get_cached_token_path(), filename)

    def get_cached_token(self):
        """Read and return a cached token, or None if not found.

        The token is read from the cached token file.
        """

        # Only read the token once
        if self.username in self.memory:
            return self.memory[self.username]

        try:
            f = open(self.get_cached_token_filename(), "r")
            token = f.read()
            f.close()

            return token.strip()
        except IOError:
            return None

    def set_cached_token(self, token):
        """Cache a token for later use."""

        # Remember for later use
        self.memory[self.username] = token

        path = self.get_cached_token_path()
        if not os.path.exists(path):
            os.makedirs(path)

        f = open(self.get_cached_token_filename(), "w")
        f.write(token)
        f.close()

    def forget(self):
        '''Removes the cached token'''

        if self.username in self.memory:
            del self.memory[self.username]
        filename = self.get_cached_token_filename()
        if os.path.exists(filename):
            os.unlink(filename)

    token = property(get_cached_token, set_cached_token, forget,
                     "The cached token")


class OAuthTokenCache(object):
    '''TokenCache for OAuth tokens; stores them in a SQLite database.'''

    DB_VERSION = 1

    # Mapping from (api_key, lookup_key) to FlickrAccessToken object.
    RAM_CACHE = {}

    def __init__(self, api_key, lookup_key=''):
        '''Creates a new token cache instance'''

        assert lookup_key is not None

        self.api_key = api_key
        self.lookup_key = lookup_key
        self.path = os.path.expanduser(os.path.join("~", ".flickr"))
        self.filename = os.path.join(self.path, 'oauth-tokens.sqlite')

        if not os.path.exists(self.path):
            os.makedirs(self.path)

        self.create_table()

    def create_table(self):
        '''Creates the DB table, if it doesn't exist already.'''

        db = sqlite3.connect(self.filename)
        curs = db.cursor()

        # Check DB version
        curs.execute('CREATE TABLE IF NOT EXISTS oauth_cache_db_version '
                     '(version int not null)')
        curs.execute('select version from oauth_cache_db_version')
        oauth_cache_db_version = curs.fetchone()
        if not oauth_cache_db_version:
            curs.execute('INSERT INTO oauth_cache_db_version (version)'
                         'values (?)', str(self.DB_VERSION))
        elif int(oauth_cache_db_version[0]) != self.DB_VERSION:
            raise CacheDatabaseError('Unsupported database version %s' %
                                     oauth_cache_db_version[0])

        # Create cache table if it doesn't exist already
        curs.execute('''CREATE TABLE IF NOT EXISTS oauth_tokens (
                        api_key varchar(64) not null,
                        lookup_key varchar(64) not null default '',
                        oauth_token varchar(64) not null,
                        oauth_token_secret varchar(64) not null,
                        access_level varchar(6) not null,
                        fullname varchar(255) not null,
                        username varchar(255) not null,
                        user_nsid varchar(64) not null,
                        PRIMARY KEY(api_key, lookup_key))''')

    @property
    def token(self):
        '''Return the cached token for this API key, or None if not found.'''

        # Only read the token once
        if (self.api_key, self.lookup_key) in self.RAM_CACHE:
            return self.RAM_CACHE[self.api_key, self.lookup_key]

        db = sqlite3.connect(self.filename)
        curs = db.cursor()
        curs.execute("SELECT oauth_token, oauth_token_secret, access_level, "
                     "fullname, username, user_nsid"
                     "FROM oauth_tokens WHERE api_key=? and lookup_key=?",
                     (self.api_key, self.lookup_key))
        token_data = curs.fetchone()

        if token_data is None:
            return None

        return FlickrAccessToken(*token_data)

    @token.setter
    def token(self, token):
        """Cache a token for later use."""

        assert isinstance(token, FlickrAccessToken)

        # Remember for later use
        self.RAM_CACHE[self.api_key, self.lookup_key] = token

        db = sqlite3.connect(self.filename)
        curs = db.cursor()
        curs.execute('''INSERT OR REPLACE INTO oauth_tokens
                     (api_key, lookup_key, oauth_token, oauth_token_secret,
                     access_level, fullname, username, user_nsid)
                     values (?, ?, ?, ?, ?, ?, ?, ?)''',<commit_msg>Fix PEP8 overcleaning in flickrapi<commit_after>'''Persistent token cache management for the Flickr API'''

import os.path
import logging
import time
import sqlite3

from .exceptions import LockingError, CacheDatabaseError
from auth import FlickrAccessToken

LOG = logging.getLogger(__name__)

__all__ = ('SimpleTokenCache', 'OAuthTokenCache')


class SimpleTokenCache(object):
    '''In-memory token cache.'''

    def __init__(self):
        self._token = None

    @property
    def token(self):
        return self._token

    @token.setter
    def token(self, token):
        self._token = token

    @token.deleter
    def token(self):
        self._token = None

    def forget(self):
        '''Removes the cached token'''

        del self.token


class TokenCache(object):
    '''On-disk persistent token cache for a single application.

    The application is identified by the API key used. Per
    application multiple users are supported, with a single
    token per user.
    '''

    def __init__(self, api_key, username=None):
        '''Creates a new token cache instance'''

        self.api_key = api_key
        self.username = username
        self.memory = {}
        self.path = os.path.join("~", ".flickr")

    def get_cached_token_path(self):
        """Return the directory holding the app data."""
        return os.path.expanduser(os.path.join(self.path, self.api_key))

    def get_cached_token_filename(self):
        """Return the full pathname of the cached token file."""

        if self.username:
            filename = 'auth-%s.token' % self.username
        else:
            filename = 'auth.token'

        return os.path.join(self.get_cached_token_path(), filename)

    def get_cached_token(self):
        """Read and return a cached token, or None if not found.

        The token is read from the cached token file.
        """

        # Only read the token once
        if self.username in self.memory:
            return self.memory[self.username]

        try:
            f = open(self.get_cached_token_filename(), "r")
            token = f.read()
            f.close()

            return token.strip()
        except IOError:
            return None

    def set_cached_token(self, token):
        """Cache a token for later use."""

        # Remember for later use
        self.memory[self.username] = token

        path = self.get_cached_token_path()
        if not os.path.exists(path):
            os.makedirs(path)

        f = open(self.get_cached_token_filename(), "w")
        f.write(token)
        f.close()

    def forget(self):
        '''Removes the cached token'''

        if self.username in self.memory:
            del self.memory[self.username]
        filename = self.get_cached_token_filename()
        if os.path.exists(filename):
            os.unlink(filename)

    token = property(get_cached_token, set_cached_token, forget,
                     "The cached token")


class OAuthTokenCache(object):
    '''TokenCache for OAuth tokens; stores them in a SQLite database.'''

    DB_VERSION = 1

    # Mapping from (api_key, lookup_key) to FlickrAccessToken object.
    RAM_CACHE = {}

    def __init__(self, api_key, lookup_key=''):
        '''Creates a new token cache instance'''

        assert lookup_key is not None

        self.api_key = api_key
        self.lookup_key = lookup_key
        self.path = os.path.expanduser(os.path.join("~", ".flickr"))
        self.filename = os.path.join(self.path, 'oauth-tokens.sqlite')

        if not os.path.exists(self.path):
            os.makedirs(self.path)

        self.create_table()

    def create_table(self):
        '''Creates the DB table, if it doesn't exist already.'''

        db = sqlite3.connect(self.filename)
        curs = db.cursor()

        # Check DB version
        curs.execute('CREATE TABLE IF NOT EXISTS oauth_cache_db_version '
                     '(version int not null)')
        curs.execute('select version from oauth_cache_db_version')
        oauth_cache_db_version = curs.fetchone()
        if not oauth_cache_db_version:
            curs.execute('INSERT INTO oauth_cache_db_version (version)'
                         'values (?)', str(self.DB_VERSION))
        elif int(oauth_cache_db_version[0]) != self.DB_VERSION:
            raise CacheDatabaseError('Unsupported database version %s' %
                                     oauth_cache_db_version[0])

        # Create cache table if it doesn't exist already
        curs.execute('''CREATE TABLE IF NOT EXISTS oauth_tokens (
                        api_key varchar(64) not null,
                        lookup_key varchar(64) not null default '',
                        oauth_token varchar(64) not null,
                        oauth_token_secret varchar(64) not null,
                        access_level varchar(6) not null,
                        fullname varchar(255) not null,
                        username varchar(255) not null,
                        user_nsid varchar(64) not null,
                        PRIMARY KEY(api_key, lookup_key))''')

    @property
    def token(self):
        '''Return the cached token for this API key, or None if not found.'''

        # Only read the token once
        if (self.api_key, self.lookup_key) in self.RAM_CACHE:
            return self.RAM_CACHE[self.api_key, self.lookup_key]

        db = sqlite3.connect(self.filename)
        curs = db.cursor()
        curs.execute('''SELECT oauth_token, oauth_token_secret, access_level,
        fullname, username, user_nsid
        FROM oauth_tokens WHERE api_key=? and lookup_key=?''',
                     (self.api_key, self.lookup_key))
        token_data = curs.fetchone()

        if token_data is None:
            return None

        return FlickrAccessToken(*token_data)

    @token.setter
    def token(self, token):
        """Cache a token for later use."""

        assert isinstance(token, FlickrAccessToken)

        # Remember for later use
        self.RAM_CACHE[self.api_key, self.lookup_key] = token

        db = sqlite3.connect(self.filename)
        curs = db.cursor()
        curs.execute('''INSERT OR REPLACE INTO oauth_tokens
                     (api_key, lookup_key, oauth_token, oauth_token_secret,
                     access_level, fullname, username, user_nsid)
                     values (?, ?, ?, ?, ?, ?, ?, ?)''',
{'fraction_non_alphanumeric': 0.09761456371625864, 'fraction_numerical': 0.003844946641556811, 'mean_word_length': 2.111572265625, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1784988', 'n_tokens_mistral': 3731, 'n_tokens_neox': 3497, 'n_words': 988}