# Path: pypi_portal/blueprints.py
# def _factory(partial_module_string, url_prefix):
# 
# Path: pypi_portal/core/flash.py
# def _escape(message):
# def default(message):
# def success(message):
# def info(message):
# def warning(message):
# def danger(message):
# def well(message):
# def modal(message):
# 
# Path: pypi_portal/extensions.py
# LOG = getLogger(__name__)
# def _on_connect(dbapi_connection, **_):
# 
# Path: pypi_portal/models/pypi.py
# class Package(Base):
#     """Holds all of the packages on PyPI."""
#     name = Column(String(255), unique=True, nullable=False)
#     summary = Column(Text, nullable=False)
#     latest_version = Column(String(128), nullable=False)
# 
# Path: pypi_portal/models/redis.py
# POLL_SIMPLE_THROTTLE = 'pypi_portal:poll_simple_throttle'  # Lock.
# 
# Path: pypi_portal/tasks/pypi.py
# @celery.task(bind=True, soft_time_limit=120)
# @single_instance
# def update_package_list():
#     """Get a list of all packages from PyPI through their XMLRPC API.
# 
#     This task returns something in case the user schedules it from a view. The view can wait up to a certain amount of
#     time for this task to finish, and if nothing times out, it can tell the user if it found any new packages.
# 
#     Since views can schedule this task, we don't want some rude person hammering PyPI or our application with repeated
#     requests. This task is limited to one run per 1 hour at most.
# 
#     Returns:
#     List of new packages found. Returns None if task is rate-limited.
#     """
#     # Rate limit.
#     lock = redis.lock(POLL_SIMPLE_THROTTLE, timeout=int(THROTTLE))
#     have_lock = lock.acquire(blocking=False)
#     if not have_lock:
#         LOG.warning('poll_simple() task has already executed in the past 4 hours. Rate limiting.')
#         return None
# 
#     # Query API.
#     client = xmlrpclib.ServerProxy('https://pypi.python.org/pypi')
#     results = client.search(dict(summary=''))
#     if not results:
#         LOG.error('Reply from API had no results.')
#         return list()
# 
#     LOG.debug('Sorting results.')
#     results.sort(key=lambda x: (x['name'], LooseVersion(x['version'])))
#     filtered = (r for r in results if r['version'][0].isdigit())
#     packages = {r['name']: dict(summary=r['summary'], version=r['version'], id=0) for r in filtered}
# 
#     LOG.debug('Pruning unchanged packages.')
#     for row in db.session.query(Package.id, Package.name, Package.summary, Package.latest_version):
#         if packages.get(row[1]) == dict(summary=row[2], version=row[3], id=0):
#             packages.pop(row[1])
#         elif row[1] in packages:
#             packages[row[1]]['id'] = row[0]
#     new_package_names = {n for n, d in packages.items() if not d['id']}
# 
#     # Merge into database.
#     LOG.debug('Found {} new packages in PyPI, updating {} total.'.format(len(new_package_names), len(packages)))
#     with db.session.begin_nested():
#         for name, data in packages.items():
#             db.session.merge(Package(id=data['id'], name=name, summary=data['summary'], latest_version=data['version']))
#     db.session.commit()
#     return list(new_package_names)


import time
from flask import redirect, render_template, url_for
from pypi_portal.blueprints import pypi_packages
from pypi_portal.core import flash
from pypi_portal.extensions import redis
from pypi_portal.models.pypi import Package
from pypi_portal.models.redis import POLL_SIMPLE_THROTTLE
from pypi_portal.tasks.pypi import update_package_list



SLEEP_FOR = 0.1  # Seconds to wait in between checks.
WAIT_UP_TO = 5  # Wait up to these many seconds for task to finish. Won't block view for more than this.


@pypi_packages.route('/', defaults=dict(page=1))
@pypi_packages.route('/page/<int:page>')
def index(page):
    pagination = Package.query.order_by('name').paginate(page, per_page=25, error_out=False)
    return render_template('pypi_packages.html', pagination=pagination)



# Path: pypi_portal/blueprints.py
# def _factory(partial_module_string, url_prefix):
# 
# Path: pypi_portal/core/flash.py
# def _escape(message):
# def default(message):
# def success(message):
# def info(message):
# def warning(message):
# def danger(message):
# def well(message):
# def modal(message):
# 
# Path: pypi_portal/extensions.py
# LOG = getLogger(__name__)
# def _on_connect(dbapi_connection, **_):
# 
# Path: pypi_portal/models/pypi.py
# class Package(Base):
#     """Holds all of the packages on PyPI."""
#     name = Column(String(255), unique=True, nullable=False)
#     summary = Column(Text, nullable=False)
#     latest_version = Column(String(128), nullable=False)
# 
# Path: pypi_portal/models/redis.py
# POLL_SIMPLE_THROTTLE = 'pypi_portal:poll_simple_throttle'  # Lock.
# 
# Path: pypi_portal/tasks/pypi.py
# @celery.task(bind=True, soft_time_limit=120)
# @single_instance
# def update_package_list():
#     """Get a list of all packages from PyPI through their XMLRPC API.
# 
#     This task returns something in case the user schedules it from a view. The view can wait up to a certain amount of
#     time for this task to finish, and if nothing times out, it can tell the user if it found any new packages.
# 
#     Since views can schedule this task, we don't want some rude person hammering PyPI or our application with repeated
#     requests. This task is limited to one run per 1 hour at most.
# 
#     Returns:
#     List of new packages found. Returns None if task is rate-limited.
#     """
#     # Rate limit.
#     lock = redis.lock(POLL_SIMPLE_THROTTLE, timeout=int(THROTTLE))
#     have_lock = lock.acquire(blocking=False)
#     if not have_lock:
#         LOG.warning('poll_simple() task has already executed in the past 4 hours. Rate limiting.')
#         return None
# 
#     # Query API.
#     client = xmlrpclib.ServerProxy('https://pypi.python.org/pypi')
#     results = client.search(dict(summary=''))
#     if not results:
#         LOG.error('Reply from API had no results.')
#         return list()
# 
#     LOG.debug('Sorting results.')
#     results.sort(key=lambda x: (x['name'], LooseVersion(x['version'])))
#     filtered = (r for r in results if r['version'][0].isdigit())
#     packages = {r['name']: dict(summary=r['summary'], version=r['version'], id=0) for r in filtered}
# 
#     LOG.debug('Pruning unchanged packages.')
#     for row in db.session.query(Package.id, Package.name, Package.summary, Package.latest_version):
#         if packages.get(row[1]) == dict(summary=row[2], version=row[3], id=0):
#             packages.pop(row[1])
#         elif row[1] in packages:
#             packages[row[1]]['id'] = row[0]
#     new_package_names = {n for n, d in packages.items() if not d['id']}
# 
#     # Merge into database.
#     LOG.debug('Found {} new packages in PyPI, updating {} total.'.format(len(new_package_names), len(packages)))
#     with db.session.begin_nested():
#         for name, data in packages.items():
#             db.session.merge(Package(id=data['id'], name=name, summary=data['summary'], latest_version=data['version']))
#     db.session.commit()
#     return list(new_package_names)


# Path: pypi_portal/views/pypi/packages.py
import time
from flask import redirect, render_template, url_for
from pypi_portal.blueprints import pypi_packages
from pypi_portal.core import flash
from pypi_portal.extensions import redis
from pypi_portal.models.pypi import Package
from pypi_portal.models.redis import POLL_SIMPLE_THROTTLE
from pypi_portal.tasks.pypi import update_package_list




SLEEP_FOR = 0.1  # Seconds to wait in between checks.
WAIT_UP_TO = 5  # Wait up to these many seconds for task to finish. Won't block view for more than this.


@pypi_packages.route('/', defaults=dict(page=1))
@pypi_packages.route('/page/<int:page>')
def index(page):
    pagination = Package.query.order_by('name').paginate(page, per_page=25, error_out=False)
    return render_template('pypi_packages.html', pagination=pagination)



@pypi_packages.route('/sync')