<commit_before>import matplotlib.pyplot as plt
import numpy

def percentilize(x):
	return numpy.argsort(numpy.argsort(x)) / len(x) * 100.0

def homogeneous_size_bins(nbins, arr, robustness=0):
	"""
	Find bins with homogeneous size

	Parameters
	----------
	nbins : int
		number of bins to create
	arr : array-like
		the data to get binned
	robustness : int
		chop this many percentiles off the top and bottom of the range

	Returns
	-------
	ndarray
		the bin edges (length nbins+1)

	"""
	if robustness:
		bottom = numpy.nanpercentile(arr, robustness)
		top = numpy.nanpercentile(arr, 100-robustness)
	else:
		bottom = numpy.nanmin(arr)
		top = numpy.nanmax(arr)
	return numpy.linspace(bottom, top, nbins+1)

def homogeneous_mass_bins(nbins, arr, robustness=0):
	"""
	Find bins with homogeneous mass

	Parameters
	----------
	nbins : int
		number of bins to create
	arr : array-like
		the data to get binned
	robustness : int
		chop this many percentiles off the top and bottom of the range

	Returns
	-------
	ndarray
		the bin edges (length nbins+1)

	"""
	bottom = robustness
	top = 100-robustness
	return numpy.nanpercentile(arr, numpy.linspace(bottom, top, nbins+1))

def n_uniques(arr, stop_at=10):
	u = set()
	for i in arr:
		u.add(i)
		if len(u)>=stop_at:
			return stop_at, u
	return len(u), sorted(u)

def punique(arr, uniq):
	digitizer = list(uniq)
	digitizer.append(numpy.inf)
	bins = numpy.arange(len(uniq) + 1)
	ticks = bins[:-1] + 0.5, uniq
	a = numpy.digitize(arr, digitizer, right=False)
	return a, bins, ticks

def psize(arr, nbins, robustness=0):
	n_uniq, uniq = n_uniques(arr, nbins+1)
	if n_uniq <= nbins:
		return punique(arr, uniq)
	else:
		bins = homogeneous_size_bins(nbins, arr, robustness=robustness)
		a = numpy.digitize(arr, bins, right=True)
		ticks = None
	return a, bins, ticks

def pmass(arr, nbins, robustness=0):
	n_uniq, uniq = n_uniques(arr, nbins+1)
	if n_uniq <= nbins:
		return punique(arr, uniq)
	else:
		bins = homogeneous_mass_bins(nbins, arr, robustness=robustness)
		a = numpy.digitize(arr, bins, right=True)
		ticks = None
	return a, bins, ticks

def pmass_even(arr, nbins, robustness=0):
	a, _, ticks = pmass(arr, nbins, robustness)
	bins = numpy.linspace(robustness, 100-robustness, nbins+1)
	return a, bins, ticks

def _generate_heatmap(
		x_digitized,
		x_bins,
		x_ticks,
		y_digitized,
		y_bins,
		y_ticks,
		normalize_dim='',
		cmap='jet',
		z_robustness=2,
		z_min=None,
		z_max=None,
		clf=True,
		subplot=(1,1,1),
		x_label=None,
		y_label=None,
		title=None,
		**kwargs
):
	bins = (numpy.arange(1,len(x_bins)+1)-0.5, numpy.arange(1,len(y_bins)+1)-0.5)

	# print("bins", bins)
	# print("x_bins", x_bins)
	# print("y_bins", y_bins)
	# print("x_", numpy.unique(x_digitized, return_counts=True))
	# print("y_", numpy.unique(y_digitized, return_counts=True))

	h,h1,h2 = numpy.histogram2d(
		x_digitized, y_digitized,
		bins=bins,
	)

	if normalize_dim.lower()=='y':
		h /= h.sum(0)[None,:]
	elif normalize_dim.lower()=='x':
		h /= h.sum(1)[:,None]

	if z_min is None:
		z_min = numpy.percentile(h,z_robustness)
	if z_max is None:
		z_max = numpy.percentile(h,100-z_robustness)

	if clf:
		plt.clf()
	ax = plt.subplot(*subplot)

	heatmap_ = numpy.zeros([h.shape[0]+1, h.shape[1]+1], dtype=h.dtype)
	heatmap_[:-1,:-1] = h

	quads = ax.pcolormesh(x_bins, y_bins, heatmap_.T, cmap=cmap, vmin=z_min, vmax=z_max, **kwargs)

	cbar = plt.colorbar(quads, ax=ax)
	if x_label:
		plt.xlabel(f'{x_label}')
	if y_label:
		plt.ylabel(f'{y_label}')
	if title:
		plt.title(title)
	if x_ticks:
		plt.xticks(*x_ticks, rotation='vertical')
	if y_ticks:
		plt.yticks(*y_ticks)

	#return h,h1,h2

def heatmapper( x, y, x_robustness=0, y_robustness=0, **kwargs ):
	"""
	Create a heatmap

	Parameters
	----------
	x, y : array or tuple
		Either an array or a tuple generated from psize, pmass, or pmass_even
	x_robustness, y_robustness : numeric
		if x or y is an array, use this robustness value to trim the extremes
	kwargs
		passed to _generate_heatmap

	"""
	if isinstance(x, numpy.ndarray):
		x = psize(x,10,x_robustness)
	if isinstance(y, numpy.ndarray):
		y = psize(y,10,y_robustness)
	return _generate_heatmap( *x, *y, **kwargs)

def heatmap(x,y, xlabel=None, ylabel=None, title=None, bins=(100,100),
			pctile=(True, False), rpctile=(False,False), cmap='jet', # 'viridis',
			robustness=2, trim_y=1, docx_writer=None,
			zmin=None, zmax=None,
			y_normalize=True, **kwargs):
	"""Plot a heatmap figure

	Parameters
	----------
	x
	y
	xlabel, ylabel : str, optional
		Axis labels
	title : str, optional
		Figure title
	bins
	pctile
	rpctile : 2-tuple
		For (x,y), should the values be rescaled into percentiles instead of the original values.
		This will cause the output to be plotted on a 0-100 scale instead of the original scale
		of the given values.
	cmap : str
		Name of a colormap to pass to `pcolormesh`
	robustness : numeric
		Amount to trim from the z-scale range, in percentile amounts
	trim_y : numeric
		Amount to trim from the y axis range, in percentile amounts
	docx_writer
	zmin
	zmax
	y_normalize
	kwargs

	Returns
	-------

	"""

	plt.clf()
	# ax = plt.subplot(2,1,1)
	ax = plt.subplot(1,1,1)
	if rpctile[0] or pctile[0]:
		binsX = numpy.percentile(x, numpy.linspace(0,100,bins[0]))
		for i in range(1,len(binsX)):
			if binsX[i] <= binsX[i-1]:
				binsX[i] = binsX[i - 1] + numpy.abs(binsX[i - 1])*1e-4 + 1e-7
	else:
		binsX = bins[0]
	if rpctile[0]:
		x = numpy.argsort(numpy.argsort(x)) / len(x) * 100.0
		binsX_ = numpy.linspace(0,100,bins[0])
	else:
		binsX_ = binsX

	if isinstance(binsX_, int):
		binsX_ = numpy.linspace(numpy.nanmin(x), numpy.nanmax(x), binsX_)

	if pctile[1] or pctile[1]:
		binsY = numpy.percentile(y, numpy.linspace(0,100,bins[1]))
		for i in range(1,len(binsY)):
			if binsY[i] <= binsY[i-1]:
				binsY[i] = binsY[i - 1] + numpy.abs(binsY[i - 1])*1e-4 + 1e-7
	else:
		binsY = bins[1]
	if rpctile[1]:
		y = numpy.argsort(numpy.argsort(y)) / len(y) * 100.0
		binsY_ = numpy.linspace(0,100,bins[1])
		trim_y = 0
	else:
		binsY_ = binsY

	if isinstance(binsY_, int):
		binsY_ = numpy.linspace(numpy.nanmin(y), numpy.nanmax(y), binsY_)

	try:
		heatmap, yedges, xedges = numpy.histogram2d(y, x, bins=(binsY_,binsX_))
	except ValueError:
		print('binsY')
		print(binsY)
		print('binsX')
		print(binsX)
		raise

	if y_normalize:
		heatmap /= heatmap.sum(0)[None,:]

	if zmin is None:
		zmin = numpy.percentile(heatmap,robustness)
	if zmax is None:
		zmax = numpy.percentile(heatmap,100-robustness)

	heatmap_ = numpy.zeros([heatmap.shape[0]+1, heatmap.shape[1]+1], dtype=heatmap.dtype)
	heatmap_[:-1,:-1] = heatmap
	try:
		quads = ax.pcolormesh(binsX_, binsY_, heatmap_, cmap=cmap, vmin=zmin, vmax=zmax, **kwargs)
	except:
		print(binsX_)
		print(binsY_)
		print(heatmap_)
		raise

	ymin, ymax = numpy.percentile(y, [trim_y, 100-trim_y])

	ax.set_ylim(ymin, ymax)
	cbar = plt.colorbar(quads, ax=ax)
	if xlabel:
		if rpctile[0]:
			plt.xlabel(f'Percentile {xlabel}')
		else:
			plt.xlabel(f'{xlabel}')
	if ylabel:
		if rpctile[1]:
			plt.ylabel(f'Percentile {ylabel}')
		else:
			plt.xlabel(f'{ylabel}')
	if title:
		plt.title(title)

	if docx_writer is not None:
		docx_writer.write_plt()
	plt.show()
<commit_msg>heatmap sns<commit_after>import matplotlib.pyplot as plt
import numpy

def percentilize(x):
	return numpy.argsort(numpy.argsort(x)) / len(x) * 100.0

def homogeneous_size_bins(nbins, arr, robustness=0):
	"""
	Find bins with homogeneous size

	Parameters
	----------
	nbins : int
		number of bins to create
	arr : array-like
		the data to get binned
	robustness : int
		chop this many percentiles off the top and bottom of the range

	Returns
	-------
	ndarray
		the bin edges (length nbins+1)

	"""
	if robustness:
		bottom = numpy.nanpercentile(arr, robustness)
		top = numpy.nanpercentile(arr, 100-robustness)
	else:
		bottom = numpy.nanmin(arr)
		top = numpy.nanmax(arr)
	return numpy.linspace(bottom, top, nbins+1)

def homogeneous_mass_bins(nbins, arr, robustness=0):
	"""
	Find bins with homogeneous mass

	Parameters
	----------
	nbins : int
		number of bins to create
	arr : array-like
		the data to get binned
	robustness : int
		chop this many percentiles off the top and bottom of the range

	Returns
	-------
	ndarray
		the bin edges (length nbins+1)

	"""
	bottom = robustness
	top = 100-robustness
	return numpy.nanpercentile(arr, numpy.linspace(bottom, top, nbins+1))

def n_uniques(arr, stop_at=10):
	u = set()
	for i in arr:
		u.add(i)
		if len(u)>=stop_at:
			return stop_at, u
	return len(u), sorted(u)

def punique(arr, uniq):
	digitizer = list(uniq)
	digitizer.append(numpy.inf)
	bins = numpy.arange(len(uniq) + 1)
	ticks = bins[:-1] + 0.5, uniq
	a = numpy.digitize(arr, digitizer, right=False)
	return a, bins, ticks

def psize(arr, nbins, robustness=0):
	n_uniq, uniq = n_uniques(arr, nbins+1)
	if n_uniq <= nbins:
		return punique(arr, uniq)
	else:
		bins = homogeneous_size_bins(nbins, arr, robustness=robustness)
		a = numpy.digitize(arr, bins, right=True)
		ticks = None
	return a, bins, ticks

def pmass(arr, nbins, robustness=0):
	n_uniq, uniq = n_uniques(arr, nbins+1)
	if n_uniq <= nbins:
		return punique(arr, uniq)
	else:
		bins = homogeneous_mass_bins(nbins, arr, robustness=robustness)
		a = numpy.digitize(arr, bins, right=True)
		ticks = None
	return a, bins, ticks

def pmass_even(arr, nbins, robustness=0):
	a, _, ticks = pmass(arr, nbins, robustness)
	bins = numpy.linspace(robustness, 100-robustness, nbins+1)
	return a, bins, ticks

def _generate_heatmap(
		x_digitized,
		x_bins,
		x_ticks,
		y_digitized,
		y_bins,
		y_ticks,
		normalize_dim='',
		cmap='jet',
		z_robustness=2,
		z_min=None,
		z_max=None,
		clf=True,
		subplot=(1,1,1),
		x_label=None,
		y_label=None,
		title=None,
		**kwargs
):
	bins = (numpy.arange(1,len(x_bins)+1)-0.5, numpy.arange(1,len(y_bins)+1)-0.5)

	# print("bins", bins)
	# print("x_bins", x_bins)
	# print("y_bins", y_bins)
	# print("x_", numpy.unique(x_digitized, return_counts=True))
	# print("y_", numpy.unique(y_digitized, return_counts=True))

	h,h1,h2 = numpy.histogram2d(
		x_digitized, y_digitized,
		bins=bins,
	)

	if normalize_dim.lower()=='y':
		h /= h.sum(0)[None,:]
	elif normalize_dim.lower()=='x':
		h /= h.sum(1)[:,None]

	if z_min is None:
		z_min = numpy.percentile(h,z_robustness)
	if z_max is None:
		z_max = numpy.percentile(h,100-z_robustness)

	if clf:
		plt.clf()
	ax = plt.subplot(*subplot)

	heatmap_ = numpy.zeros([h.shape[0]+1, h.shape[1]+1], dtype=h.dtype)
	heatmap_[:-1,:-1] = h

	quads = ax.pcolormesh(x_bins, y_bins, heatmap_.T, cmap=cmap, vmin=z_min, vmax=z_max, **kwargs)

	cbar = plt.colorbar(quads, ax=ax)
	if x_label:
		plt.xlabel(f'{x_label}')
	if y_label:
		plt.ylabel(f'{y_label}')
	if title:
		plt.title(title)
	if x_ticks:
		plt.xticks(*x_ticks, rotation='vertical')
	if y_ticks:
		plt.yticks(*y_ticks)

def heatmap_dataframe(
		x_digitized,
		x_bins,
		x_ticks,
		y_digitized,
		y_bins,
		y_ticks,
		normalize_dim='',
		tick_fmt='.2f',
		**kwargs
):
	bins = (numpy.arange(1,len(x_bins)+1)-0.5, numpy.arange(1,len(y_bins)+1)-0.5)

	# print("bins", bins)
	# print("x_bins", x_bins)
	# print("y_bins", y_bins)
	# print("x_", numpy.unique(x_digitized, return_counts=True))
	# print("y_", numpy.unique(y_digitized, return_counts=True))

	h,h1,h2 = numpy.histogram2d(
		x_digitized, y_digitized,
		bins=bins,
	)

	if normalize_dim.lower()=='y':
		h /= h.sum(0)[None,:]
	elif normalize_dim.lower()=='x':
		h /= h.sum(1)[:,None]

	if x_ticks is not None:
		cols = x_ticks[1]
	else:
		cols = [f"{i:{tick_fmt}} to {j:{tick_fmt}}" for i,j in zip(x_bins[:-1],x_bins[1:])]
	if y_ticks is not None:
		rows = y_ticks[1]
	else:
		rows = [f"{i:{tick_fmt}} to {j:{tick_fmt}}" for i,j in zip(y_bins[:-1],y_bins[1:])]

	import pandas
	return pandas.DataFrame(
		data=h,
		columns=cols,
		index=rows,
	)

def heatmapper( x, y, x_robustness=0, y_robustness=0, **kwargs ):
	"""
	Create a heatmap

	Parameters
	----------
	x, y : array or tuple
		Either an array or a tuple generated from psize, pmass, or pmass_even
	x_robustness, y_robustness : numeric
		if x or y is an array, use this robustness value to trim the extremes
	kwargs
		passed to _generate_heatmap

	"""
	if isinstance(x, numpy.ndarray):
		x = psize(x,10,x_robustness)
	if isinstance(y, numpy.ndarray):
		y = psize(y,10,y_robustness)
	return _generate_heatmap( *x, *y, **kwargs)

def heatmap_sns(x, y, x_robustness=0, y_robustness=0, max_dim=20, **kwargs):
	"""
	Create a heatmap using seaborn

	Parameters
	----------
	x, y : array or tuple
		Either an array or a tuple generated from psize, pmass, or pmass_even
	x_robustness, y_robustness : numeric
		if x or y is an array, use this robustness value to trim the extremes
	kwargs
		passed to _generate_heatmap

	"""
	if isinstance(x, numpy.ndarray):
		x = psize(x,max_dim,x_robustness)
	if isinstance(y, numpy.ndarray):
		y = psize(y,max_dim,y_robustness)
	frame = heatmap_dataframe( *x, *y )
	import seaborn
	return seaborn.heatmap(frame, **kwargs)

def heatmap(x,y, xlabel=None, ylabel=None, title=None, bins=(100,100),
			pctile=(True, False), rpctile=(False,False), cmap='jet', # 'viridis',
			robustness=2, trim_y=1, docx_writer=None,
			zmin=None, zmax=None,
			y_normalize=True, **kwargs):
	"""Plot a heatmap figure

	Parameters
	----------
	x
	y
	xlabel, ylabel : str, optional
		Axis labels
	title : str, optional
		Figure title
	bins
	pctile
	rpctile : 2-tuple
		For (x,y), should the values be rescaled into percentiles instead of the original values.
		This will cause the output to be plotted on a 0-100 scale instead of the original scale
		of the given values.
	cmap : str
		Name of a colormap to pass to `pcolormesh`
	robustness : numeric
		Amount to trim from the z-scale range, in percentile amounts
	trim_y : numeric
		Amount to trim from the y axis range, in percentile amounts
	docx_writer
	zmin
	zmax
	y_normalize
	kwargs

	Returns
	-------

	"""

	plt.clf()
	# ax = plt.subplot(2,1,1)
	ax = plt.subplot(1,1,1)
	if rpctile[0] or pctile[0]:
		binsX = numpy.percentile(x, numpy.linspace(0,100,bins[0]))
		for i in range(1,len(binsX)):
			if binsX[i] <= binsX[i-1]:
				binsX[i] = binsX[i - 1] + numpy.abs(binsX[i - 1])*1e-4 + 1e-7
	else:
		binsX = bins[0]
	if rpctile[0]:
		x = numpy.argsort(numpy.argsort(x)) / len(x) * 100.0
		binsX_ = numpy.linspace(0,100,bins[0])
	else:
		binsX_ = binsX

	if isinstance(binsX_, int):
		binsX_ = numpy.linspace(numpy.nanmin(x), numpy.nanmax(x), binsX_)

	if pctile[1] or pctile[1]:
		binsY = numpy.percentile(y, numpy.linspace(0,100,bins[1]))
		for i in range(1,len(binsY)):
			if binsY[i] <= binsY[i-1]:
				binsY[i] = binsY[i - 1] + numpy.abs(binsY[i - 1])*1e-4 + 1e-7
	else:
		binsY = bins[1]
	if rpctile[1]:
		y = numpy.argsort(numpy.argsort(y)) / len(y) * 100.0
		binsY_ = numpy.linspace(0,100,bins[1])
		trim_y = 0
	else:
		binsY_ = binsY

	if isinstance(binsY_, int):
		binsY_ = numpy.linspace(numpy.nanmin(y), numpy.nanmax(y), binsY_)

	try:
		heatmap, yedges, xedges = numpy.histogram2d(y, x, bins=(binsY_,binsX_))
	except ValueError:
		print('binsY')
		print(binsY)
		print('binsX')
		print(binsX)
		raise

	if y_normalize:
		heatmap /= heatmap.sum(0)[None,:]

	if zmin is None:
		zmin = numpy.percentile(heatmap,robustness)
	if zmax is None:
		zmax = numpy.percentile(heatmap,100-robustness)

	heatmap_ = numpy.zeros([heatmap.shape[0]+1, heatmap.shape[1]+1], dtype=heatmap.dtype)
	heatmap_[:-1,:-1] = heatmap
	try:
		quads = ax.pcolormesh(binsX_, binsY_, heatmap_, cmap=cmap, vmin=zmin, vmax=zmax, **kwargs)
	except:
		print(binsX_)
		print(binsY_)
		print(heatmap_)
		raise

	ymin, ymax = numpy.percentile(y, [trim_y, 100-trim_y])

	ax.set_ylim(ymin, ymax)
	cbar = plt.colorbar(quads, ax=ax)
	if xlabel:
		if rpctile[0]:
			plt.xlabel(f'Percentile {xlabel}')
		else:
			plt.xlabel(f'{xlabel}')
	if ylabel:
		if rpctile[1]:
			plt.ylabel(f'Percentile {ylabel}')
		else:
			plt.xlabel(f'{ylabel}')
	if title:
		plt.title(title)

	if docx_writer is not None:
		docx_writer.write_plt()
	plt.show()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from __future__ import absolute_import

import time
import six
from flask import current_app
from hashlib import sha256
try:
    from urlparse import urlparse  # Python 2
except ImportError:
    from urllib.parse import urlparse  # Python 3

import nacl.secret
import nacl.utils
import nacl.exceptions

__author__ = 'lundberg'

def verify_auth_token(eppn, token, nonce, timestamp, generator=sha256):
    """
    Authenticate a user who just signed up, for user convenience.

    Authentication is done using a shared secret in the configuration of the
    authn and signup applications. The signup application can effectively
    log a new user in.

    :param eppn: the identifier of the user as string
    :param token: authentication token as string
    :param nonce: a public nonce for this authentication request as string
    :param timestamp: unixtime of signup application as hex string
    :param generator: hash function to use (default: SHA-256)
    :return: bool, True on valid authentication
    """
    current_app.logger.debug('Trying to authenticate user {} with auth token {}'.format(eppn, token))
    shared_key = current_app.config.get('TOKEN_LOGIN_SHARED_KEY')
    secret_key = shared_key
    if not isinstance(shared_key, six.binary_type):
        secret_key = shared_key.encode('ascii')

    # check timestamp to make sure it is within -300..900 seconds from now
    now = int(time.time())
    ts = int(timestamp, 16)
    if (ts < now - 300) or (ts > now + 900):
        current_app.logger.debug('Auth token timestamp {} out of bounds ({} seconds from {})'.format(
            timestamp, ts - now, now))
        return False

    # try to open secret box
    if isinstance(token, six.text_type):
        token = token.encode('ascii')
    if six.PY2:
        encrypted = token.decode('hex')
    else:
        encrypted = token.fromhex(token)
    try:
        box = nacl.secret.SecretBox(secret_key)
        plaintext = box.decrypt(encrypted)
        return plaintext == '{}|{}'.format(timestamp, eppn).encode('ascii')
    except (LookupError, nacl.exceptions.CryptoError) as e:
        current_app.logger.debug('Secretbox decryption failed, error: ' + str(e))

    # verify there is a long enough nonce
    if len(nonce) < 16:
        current_app.logger.warning('Auth token nonce {} too short'.format(nonce))
        return False

    # verify token format

    data = '{0}|{1}|{2}|{3}'.format(shared_key, eppn, nonce, timestamp)
    hashed = generator(data.encode('ascii'))
    expected = hashed.hexdigest()
    if len(expected) != len(token):
        current_app.logger.warning('Auth token bad length')
        return False

    # constant time comparision of the hash, courtesy of
    # http://rdist.root.org/2009/05/28/timing-attack-in-google-keyczar-library/
    result = 0
    for x, y in zip(expected, token):
        result |= ord(x) ^ ord(y)
    current_app.logger.debug('Auth token match result: {}'.format(result == 0))
    return result == 0
<commit_msg>fixing actions tests<commit_after># -*- coding: utf-8 -*-
from __future__ import absolute_import

import time
import six
from flask import current_app
from hashlib import sha256
try:
    from urlparse import urlparse  # Python 2
except ImportError:
    from urllib.parse import urlparse  # Python 3

import nacl.secret
import nacl.utils
import nacl.exceptions

__author__ = 'lundberg'

def verify_auth_token(eppn, token, nonce, timestamp, generator=sha256):
    """
    Authenticate a user who just signed up, for user convenience.

    Authentication is done using a shared secret in the configuration of the
    authn and signup applications. The signup application can effectively
    log a new user in.

    :param eppn: the identifier of the user as string
    :param token: authentication token as string
    :param nonce: a public nonce for this authentication request as string
    :param timestamp: unixtime of signup application as hex string
    :param generator: hash function to use (default: SHA-256)
    :return: bool, True on valid authentication
    """
    current_app.logger.debug('Trying to authenticate user {} with auth token {}'.format(eppn, token))
    shared_key = current_app.config.get('TOKEN_LOGIN_SHARED_KEY')
    secret_key = shared_key
    if not isinstance(shared_key, six.binary_type):
        secret_key = shared_key.encode('ascii')

    # check timestamp to make sure it is within -300..900 seconds from now
    now = int(time.time())
    ts = int(timestamp, 16)
    if (ts < now - 300) or (ts > now + 900):
        current_app.logger.debug('Auth token timestamp {} out of bounds ({} seconds from {})'.format(
            timestamp, ts - now, now))
        return False

    # try to open secret box
    tokensb = token
    if isinstance(tokensb, six.text_type):
        tokensb = tokensb.encode('ascii')
    if six.PY2:
        encrypted = tokensb.decode('hex')
    else:
        encrypted = tokensb.fromhex(token)
    try:
        box = nacl.secret.SecretBox(secret_key)
        plaintext = box.decrypt(encrypted)
        return plaintext == '{}|{}'.format(timestamp, eppn).encode('ascii')
    except (LookupError, nacl.exceptions.CryptoError) as e:
        current_app.logger.debug('Secretbox decryption failed, error: ' + str(e))

    if isinstance(token, six.text_type):
        token = token.encode('ascii')

    # verify there is a long enough nonce
    if len(nonce) < 16:
        current_app.logger.warning('Auth token nonce {} too short'.format(nonce))
        return False

    # verify token format

    data = '{0}|{1}|{2}|{3}'.format(shared_key, eppn, nonce, timestamp)
    hashed = generator(data.encode('ascii'))
    expected = hashed.hexdigest()
    if len(expected) != len(token):
        current_app.logger.warning('Auth token bad length')
        return False

    # constant time comparision of the hash, courtesy of
    # http://rdist.root.org/2009/05/28/timing-attack-in-google-keyczar-library/
    result = 0
    if isinstance(expected, six.binary_type):
        expected = expected.decode('ascii')
    if isinstance(token, six.binary_type):
        token = token.decode('ascii')
    for x, y in zip(expected, token):
        result |= ord(x) ^ ord(str(y))
    current_app.logger.debug('Auth token match result: {}'.format(result == 0))
    return result == 0
<|endoftext|>


<commit_before>from soaplib.wsgi_soap import SimpleWSGISoapApp
from soaplib.service import soapmethod

from soaplib.serializers.primitive import *
from soaplib.serializers.clazz import *

import socket
import struct
import sys

SOAP_INTERFACE_PORT = 7889
AGGREGATE_MANAGER_PORT = 2603
AGGREGATE_MANAGER_IP = 'localhost'
#AGGREGATE_MANAGER_IP = 'openflowvisor.stanford.edu'

# Message IDs for all the GENI light calls
# This will be used by the aggrMgr controller
SFA_GET_RESOURCES = 101
SFA_CREATE_SLICE = 102
SFA_START_SLICE = 103
SFA_STOP_SLICE = 104
SFA_DELETE_SLICE = 105
SFA_GET_SLICES = 106
SFA_RESET_SLICES = 107

def print_buffer(buf):
    for i in range(0,len(buf)):
        print('%x' % buf[i])

def extract(sock):
    # Shud we first obtain the message length?
    # msg_len = socket.ntohs(sock.recv(2))
    msg = ""

    while (1):
        try:
            chunk = sock.recv(1)
        except socket.error, message:
            if 'timed out' in message:
                break
            else:
                sys.exit("Socket error: " + message)

        if len(chunk) == 0:
            break
        msg += chunk

    print 'done extracting response from aggrMgr'
    return msg

def connect(server, port):
    '''Connect to the Aggregate Manager module'''
    sock = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
    sock.connect ( ( server, port) )
    sock.settimeout(1)
    print 'connected to aggregate manager module'
    return sock

def connect_aggrMgr():
    return connect(AGGREGATE_MANAGER_IP, AGGREGATE_MANAGER_PORT)

def generate_slide_id(cred, hrn):
    if cred == None:
        cred = ""
    if hrn == None:
        hrn = ""
    return cred + '_' + hrn

##
# The GeniServer class provides stubs for executing Geni operations at
# the Aggregate Manager.

class GeniLightServer(SimpleWSGISoapApp):
    def __init__(self):
        self.__tns__ = "http://yuba.stanford.edu/geniLight/"

    def msg_aggrMgr(self, cred, hrn, msg_id):
        slice_id = generate_slide_id(cred, hrn)

        msg = struct.pack('> B%ds' % len(slice_id), msg_id, slice_id)
        buf = struct.pack('> H', len(msg)+2) + msg

        try:
            aggrMgr_sock = connect_aggrMgr()
            aggrMgr_sock.send(buf)
            aggrMgr_sock.close()
            return 1
        except socketerror, message:
            print "Socket error"
        except IOerror, message:
            print "IO error"
        return 0

    # implicitly no __init__()
    @soapmethod(String,String,_returns=Integer)
    def start_slice(self, cred, hrn):
        return msg_aggrMgr(SFA_START_SLICE)

    @soapmethod(String,String,_returns=Integer)
    def stop_slice(self, cred, hrn):
        return msg_aggrMgr(SFA_STOP_SLICE)

    @soapmethod(String,String,_returns=Integer)
    def delete_slice(self, cred, hrn):
        return msg_aggrMgr(SFA_DELETE_SLICE)

    @soapmethod(String,String,_returns=Integer)
    def reset_slices(self, cred, hrn):
        return msg_aggrMgr(SFA_RESET_SLICES)

    @soapmethod(String,String,String,_returns=String)
    def create_slice(self, cred, hrn, rspec):
        slice_id = generate_slide_id(cred, hrn)

        msg = struct.pack('> B%ds%ds' % len(slice_id), SFA_CREATE_SLICE, slice_id, rspec)
        buf = struct.pack('> H', len(msg)+2) + msg

        try:
            aggrMgr_sock = connect_aggrMgr()
            aggrMgr_sock.send(buf)
            aggrMgr_sock.close()
            return 1
        except socketerror, message:
            print "Socket error"
        except IOerror, message:
            print "IO error"
        return 0

    @soapmethod(String,_returns=String)
    def get_slices(self, cred):
        msg = struct.pack('> B%ds%ds' % len(cred), SFA_GET_SLICES, cred)
        buf = struct.pack('> H', len(msg)+2) + msg

        try:
            aggrMgr_sock = connect_aggrMgr()
            aggrMgr_sock.send(buf)
            slice_list = extract(aggrMgr_sock);
            aggrMgr_sock.close()

            return slice_list
        except socketerror, message:
            print "Socket error"
        except IOerror, message:
            print "IO error"
        return None

    @soapmethod(String,String,_returns=Array(String))
    def get_resources(self, cred, hrn=None):
        slice_id = generate_slide_id(cred, hrn)

        msg = struct.pack('> B%ds' % len(slice_id), SFA_GET_RESOURCES, slice_id)
        buf = struct.pack('> H', len(msg)+2) + msg

        try:
            aggrMgr_sock = connect_aggrMgr()
            aggrMgr_sock.send(buf)
            resource_list = extract(aggrMgr_sock);
            aggrMgr_sock.close()

            return resource_list
        except socketerror, message:
            print "Socket error"
        except IOerror, message:
            print "IO error"
        return None

if __name__=='__main__':
    try:from cherrypy.wsgiserver import CherryPyWSGIServer
    except:from cherrypy._cpwsgiserver import CherryPyWSGIServer

    if len(sys.argv) > 2:
        AGGREGATE_MANAGER_IP = sys.argv[1]
        AGGREGATE_MANAGER_PORT = int(sys.argv[2])

    gls = GeniLightServer()
    server = CherryPyWSGIServer(('localhost',SOAP_INTERFACE_PORT),gls)

    try:
        server.start()
    except (KeyboardInterrupt):
        sys.exit(0)
<commit_msg>Added debug messages to the SFA server py script<commit_after>from soaplib.wsgi_soap import SimpleWSGISoapApp
from soaplib.service import soapmethod

from soaplib.serializers.primitive import *
from soaplib.serializers.clazz import *

import socket
import struct
import sys

SOAP_INTERFACE_PORT = 7889
AGGREGATE_MANAGER_PORT = 2603
AGGREGATE_MANAGER_IP = 'localhost'
#AGGREGATE_MANAGER_IP = 'openflowvisor.stanford.edu'

# Message IDs for all the GENI light calls
# This will be used by the aggrMgr controller
SFA_GET_RESOURCES = 101
SFA_CREATE_SLICE = 102
SFA_START_SLICE = 103
SFA_STOP_SLICE = 104
SFA_DELETE_SLICE = 105
SFA_GET_SLICES = 106
SFA_RESET_SLICES = 107

DEBUG = 1

def print_buffer(buf):
    for i in range(0,len(buf)):
        print('%x' % buf[i])

def extract(sock):
    # Shud we first obtain the message length?
    # msg_len = socket.ntohs(sock.recv(2))
    msg = ""

    while (1):
        try:
            chunk = sock.recv(1)
        except socket.error, message:
            if 'timed out' in message:
                break
            else:
                sys.exit("Socket error: " + message)

        if len(chunk) == 0:
            break
        msg += chunk

    print 'done extracting response from aggrMgr'
    return msg

def connect(server, port):
    '''Connect to the Aggregate Manager module'''
    sock = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
    sock.connect ( ( server, port) )
    sock.settimeout(1)
    print 'connected to aggregate manager module'
    return sock

def connect_aggrMgr():
    return connect(AGGREGATE_MANAGER_IP, AGGREGATE_MANAGER_PORT)

def generate_slide_id(cred, hrn):
    if cred == None:
        cred = ""
    if hrn == None:
        hrn = ""
    return cred + '_' + hrn

##
# The GeniServer class provides stubs for executing Geni operations at
# the Aggregate Manager.

class GeniLightServer(SimpleWSGISoapApp):
    def __init__(self):
        self.__tns__ = "http://yuba.stanford.edu/geniLight/"

    def msg_aggrMgr(self, cred, hrn, msg_id):
        slice_id = generate_slide_id(cred, hrn)

        msg = struct.pack('> B%ds' % len(slice_id), msg_id, slice_id)
        buf = struct.pack('> H', len(msg)+2) + msg

        try:
            aggrMgr_sock = connect_aggrMgr()
            aggrMgr_sock.send(buf)
            aggrMgr_sock.close()
            return 1
        except socketerror, message:
            print "Socket error"
        except IOerror, message:
            print "IO error"
        return 0

    # implicitly no __init__()
    @soapmethod(String,String,_returns=Integer)
    def start_slice(self, cred, hrn):
        if DEBUG: print "Received start_slice call"
        return msg_aggrMgr(SFA_START_SLICE)

    @soapmethod(String,String,_returns=Integer)
    def stop_slice(self, cred, hrn):
        if DEBUG: print "Received stop_slice call"
        return msg_aggrMgr(SFA_STOP_SLICE)

    @soapmethod(String,String,_returns=Integer)
    def delete_slice(self, cred, hrn):
        if DEBUG: print "Received delete_slice call"
        return msg_aggrMgr(SFA_DELETE_SLICE)

    @soapmethod(String,String,_returns=Integer)
    def reset_slices(self, cred, hrn):
        if DEBUG: print "Received reset_slices call"
        return msg_aggrMgr(SFA_RESET_SLICES)

    @soapmethod(String,String,String,_returns=String)
    def create_slice(self, cred, hrn, rspec):
        if DEBUG: print "Received create_slice call"
        slice_id = generate_slide_id(cred, hrn)

        msg = struct.pack('> B%ds%ds' % len(slice_id), SFA_CREATE_SLICE, slice_id, rspec)
        buf = struct.pack('> H', len(msg)+2) + msg

        try:
            aggrMgr_sock = connect_aggrMgr()
            aggrMgr_sock.send(buf)
            aggrMgr_sock.close()
            return 1
        except socketerror, message:
            print "Socket error"
        except IOerror, message:
            print "IO error"
        return 0

    @soapmethod(String,_returns=String)
    def get_slices(self, cred):
        if DEBUG: print "Received get_slices call"
        msg = struct.pack('> B%ds%ds' % len(cred), SFA_GET_SLICES, cred)
        buf = struct.pack('> H', len(msg)+2) + msg

        try:
            aggrMgr_sock = connect_aggrMgr()
            aggrMgr_sock.send(buf)
            slice_list = extract(aggrMgr_sock);
            aggrMgr_sock.close()

            return slice_list
        except socketerror, message:
            print "Socket error"
        except IOerror, message:
            print "IO error"
        return None

    @soapmethod(String,String,_returns=Array(String))
    def get_resources(self, cred, hrn=None):
        if DEBUG: print "Received get_resources call"
        slice_id = generate_slide_id(cred, hrn)

        msg = struct.pack('> B%ds' % len(slice_id), SFA_GET_RESOURCES, slice_id)
        buf = struct.pack('> H', len(msg)+2) + msg

        try:
            aggrMgr_sock = connect_aggrMgr()
            aggrMgr_sock.send(buf)
            resource_list = extract(aggrMgr_sock);
            aggrMgr_sock.close()

            return resource_list
        except socketerror, message:
            print "Socket error"
        except IOerror, message:
            print "IO error"
        return None

if __name__=='__main__':
    try:from cherrypy.wsgiserver import CherryPyWSGIServer
    except:from cherrypy._cpwsgiserver import CherryPyWSGIServer

    if len(sys.argv) > 2:
        AGGREGATE_MANAGER_IP = sys.argv[1]
        AGGREGATE_MANAGER_PORT = int(sys.argv[2])

    gls = GeniLightServer()
    server = CherryPyWSGIServer(('localhost',SOAP_INTERFACE_PORT),gls)

    try:
        server.start()
    except (KeyboardInterrupt):
        sys.exit(0)
<|endoftext|>


<commit_before>from __future__ import print_function
import sys
from itertools import chain, tee
from collections import defaultdict
import argparse
import json

import pip

__version__ = '0.5.0'

flatten = chain.from_iterable

def build_dist_index(pkgs):
    """Build an index pkgs by their key as a dict.

    :param list pkgs: list of pkg_resources.Distribution instances
    :returns: index of the pkgs by the pkg key
    :rtype: dict

    """
    return dict((p.key, DistPackage(p)) for p in pkgs)

def construct_tree(index):
    """Construct tree representation of the pkgs from the index.

    The keys of the dict representing the tree will be objects of type
    DistPackage and the values will be list of ReqPackage objects.

    :param dict index: dist index ie. index of pkgs by their keys
    :returns: tree of pkgs and their dependencies
    :rtype: dict

    """
    return dict((p, [ReqPackage(r, index.get(r.key))
                     for r in p.requires()])
                for p in index.values())

def reverse_tree(tree):
    """Reverse the dependency tree.

    ie. the keys of the resulting dict are objects of type
    ReqPackage and the values are lists of DistPackage objects.

    :param dict tree: the pkg dependency tree obtained by calling
                      `construct_tree` function
    :returns: reversed tree
    :rtype: dict

    """
    rtree = {}
    visited = set()
    child_keys = set(c.key for c in flatten(tree.values()))
    for k, vs in tree.items():
        for v in vs:
            if v not in rtree:
                rtree[v] = []
            rtree[v].append(k)
            visited.add(v.key)
        if k.key not in child_keys:
            rtree[k.as_requirement()] = []
    return rtree

class Package(object):
    """Abstract class for wrappers around objects that pip returns.

    This class needs to be subclassed with implementations for
    `render_as_root` and `render_as_branch` methods.

    """

    def __init__(self, obj):
        self._obj = obj
        self.project_name = obj.project_name
        self.key = obj.key
        # an instance of every subclass of Package will have a
        # DistPackage object associated with it. In case of
        # DistPackage class, it will be the object itself.
        self.dist = None

    def render_as_root(self, frozen):
        return NotImplementedError

    def render_as_branch(self, parent, frozen):
        return NotImplementedError

    def render(self, parent=None, frozen=False):
        if not parent:
            return self.render_as_root(frozen)
        else:
            return self.render_as_branch(parent, frozen)

    def frozen_repr(self):
        if self.dist:
            fr = pip.FrozenRequirement.from_dist(self.dist._obj, [])
            return str(fr).strip()
        else:
            return self.project_name

    def __getattr__(self, key):
        return getattr(self._obj, key)

    def __repr__(self):
        return '<{0}("{1}")>'.format(self.__class__.__name__, self.key)

class DistPackage(Package):
    """Wrapper class for pkg_resources.Distribution instances"""

    def __init__(self, obj):
        super(DistPackage, self).__init__(obj)
        # this itself is the associated dist package obj
        self.dist = self
        self.version_spec = None

    def render_as_root(self, frozen):
        if not frozen:
            return '{0}=={1}'.format(self.project_name, self.version)
        else:
            return self.frozen_repr()

    def render_as_branch(self, parent, frozen):
        if not frozen:
            parent_ver_spec = parent.version_spec
            parent_str = parent.project_name
            if parent_ver_spec:
                parent_str += parent_ver_spec
            return (
                '{0}=={1} [requires: {2}]'
            ).format(self.project_name, self.version, parent_str)
        else:
            return self.render_as_root(frozen)

    def as_requirement(self):
        return ReqPackage(self._obj.as_requirement(), dist=self)

    def as_dict(self):
        return {'key': self.key,
                'package_name': self.project_name,
                'installed_version': self.version}

class ReqPackage(Package):
    """Wrapper class for Requirements instance"""

    def __init__(self, obj, dist=None):
        super(ReqPackage, self).__init__(obj)
        self.dist = dist

    @property
    def version_spec(self):
        specs = self._obj.specs
        return ','.join([''.join(sp) for sp in specs]) if specs else None

    @property
    def installed_version(self):
        # if the dist is None as in some cases, we don't know the
        # installed version
        return self.dist.version if self.dist else '?'

    def render_as_root(self, frozen):
        if not frozen:
            return '{0}=={1}'.format(self.project_name, self.installed_version)
        else:
            return self.frozen_repr()

    def render_as_branch(self, _parent, frozen):
        if not frozen:
            vers = []
            if self.version_spec:
                vers.append(('required', self.version_spec))
            if self.dist:
                vers.append(('installed', self.installed_version))
            if not vers:
                return self.key
            ver_str = ', '.join(['{0}: {1}'.format(k, v) for k, v in vers])
            return '{0} [{1}]'.format(self.project_name, ver_str)
        else:
            return self.render_as_root(frozen)

    def as_dict(self):
        return {'key': self.key,
                'package_name': self.project_name,
                'installed_version': self.installed_version,
                'required_version': self.version_spec}

def render_tree(tree, list_all=True, show_only=None, frozen=False):
    """Convert to tree to string representation

    :param dict tree: the package tree
    :param bool list_all: whether to list all the pgks at the root
                          level or only those that are the
                          sub-dependencies
    :param set show_only: set of select packages to be shown in the
                          output. This is optional arg, default: None.
    :param bool frozen: whether or not show the names of the pkgs in
                        the output that's favourable to pip --freeze
    :returns: string representation of the tree
    :rtype: str

    """
    branch_keys = set(r.key for r in flatten(tree.values()))
    nodes = tree.keys()
    use_bullets = not frozen

    key_tree = dict((k.key, v) for k, v in tree.items())
    get_children = lambda n: key_tree[n.key]

    if show_only:
        nodes = [p for p in nodes
                 if p.key in show_only
                 or p.project_name in show_only]
    elif not list_all:
        nodes = [p for p in nodes if p.key not in branch_keys]

    def aux(node, parent=None, indent=0, chain=None):
        if chain is None:
            chain = [node.project_name]
        node_str = node.render(parent, frozen)
        if parent:
            prefix = ' '*indent + ('-' if use_bullets else ' ') + ' '
            node_str = prefix + node_str
        result = [node_str]

        # the dist attr for some ReqPackage could be None
        # eg. testresources, setuptools which is a dependencies of
        # some pkg but doesn't get listed in the result of
        # pip.get_installed_distributions.
        if node.dist:
            children = [aux(c, node, indent=indent+2,
                            chain=chain+[c.project_name])
                        for c in get_children(node)
                        if c.project_name not in chain]
            result += list(flatten(children))
        return result

    lines = flatten([aux(p) for p in nodes])
    return '\n'.join(lines)

def jsonify_tree(tree, indent):
    """Converts the tree into json representation.

    The json repr will be a list of hashes, each hash having 2 fields:
      - package
      - dependencies: list of dependencies

    :param dict tree: dependency tree
    :param int indent: no. of spaces to indent json
    :returns: json representation of the tree
    :rtype: str

    """
    return json.dumps([{'package': k.as_dict(),
                        'dependencies': [v.as_dict() for v in vs]}
                       for k, vs in tree.items()],
                      indent=indent)

def confusing_deps(tree):
    """Returns group of dependencies that are possibly confusing

    eg. if pkg1 requires pkg3>=1.0 and pkg2 requires pkg3>=1.0,<=2.0

    :param dict tree: the requirements tree
    :returns: groups of dependencies paired with their top level pkgs
    :rtype: list of list of pairs

    """
    def has_multi_versions(req_pkgs):
        return len(set(r.version_spec for r in req_pkgs)) > 1

    deps = defaultdict(list)
    for p, rs in tree.items():
        for r in rs:
            deps[r.key].append((p, r))
    return [ps for r, ps in deps.items()
            if len(ps) > 1
            and has_multi_versions(d for p, d in ps)]

def cyclic_deps(tree):
    """Generator that produces cyclic dependencies

    :param list pkgs: pkg_resources.Distribution instances
    :param dict pkg_index: mapping of pkgs with their respective keys
    :returns: generator that yields str representation of cyclic
              dependencies
    :rtype: generator

    """
    nodes = tree.keys()
    key_tree = dict((k.key, v) for k, v in tree.items())
    get_children = lambda n: key_tree[n.key]

    def aux(node, chain):
        if node.dist:
            for c in get_children(node):
                if c.project_name in chain:
                    yield ' => '.join([str(p) for p in chain] + [str(c)])
                else:
                    for cycle in aux(c, chain=chain+[c.project_name]):
                        yield cycle

    for cycle in flatten([aux(n, chain=[]) for n in nodes]):
        yield cycle

def peek_into(iterator):
    """Peeks into an iterator to check if it's empty

    :param iterator: an iterator
    :returns: tuple of boolean representing whether the iterator is
              empty or not and the iterator itself.
    :rtype: tuple

    """
    a, b = tee(iterator)
    is_empty = False
    try:
        next(a)
    except StopIteration:
        is_empty = True
    return is_empty, b

def main():
    parser = argparse.ArgumentParser(description=(
        'Dependency tree of the installed python packages'
    ))
    parser.add_argument('-f', '--freeze', action='store_true',
                        help='Print names so as to write freeze files')
    parser.add_argument('-a', '--all', action='store_true',
                        help='list all deps at top level')
    parser.add_argument('-l', '--local-only',
                        action='store_true', help=(
                            'If in a virtualenv that has global access '
                            'donot show globally installed packages'
                        ))
    parser.add_argument('-w', '--nowarn', action='store_true',
                        help=(
                            'Inhibit warnings about possibly '
                            'confusing packages'
                        ))
    parser.add_argument('-r', '--reverse', action='store_true',
                        default=False, help=(
                            'Shows the dependency tree in the reverse fasion '
                            'ie. the sub-dependencies are listed with the '
                            'list of packages that need them under them.'
                        ))
    parser.add_argument('-p', '--packages',
                        help=(
                            'Comma separated list of select packages to show '
                            'in the output. If set, --all will be ignored.'
                        ))
    parser.add_argument('-j', '--json', action='store_true', default=False,
                        help=(
                            'Display dependency tree as json. This will yield '
                            '"raw" output that may be used by external tools. '
                            'This option overrides all other options.'
                        ))
    args = parser.parse_args()

    default_skip = ['setuptools', 'pip', 'python', 'distribute']
    skip = default_skip + ['pipdeptree']
    pkgs = pip.get_installed_distributions(local_only=args.local_only,
                                           skip=skip)

    dist_index = build_dist_index(pkgs)
    tree = construct_tree(dist_index)

    if args.json:
        print(jsonify_tree(tree, indent=4))
        return 0

    # show warnings about possibly confusing deps if found and
    # warnings are enabled
    if not args.nowarn:
        confusing = confusing_deps(tree)
        if confusing:
            print('Warning!!! Possible confusing dependencies found:', file=sys.stderr)
            for xs in confusing:
                for i, (p, d) in enumerate(xs):
                    if d.key in skip:
                        continue
                    pkg = p.render_as_root(False)
                    req = d.render_as_branch(p, False)
                    tmpl = '  {0} -> {1}' if i > 0 else '* {0} -> {1}'
                    print(tmpl.format(pkg, req), file=sys.stderr)
            print('-'*72, file=sys.stderr)

        is_empty, cyclic = peek_into(cyclic_deps(tree))
        if not is_empty:
            print('Warning!!! Cyclic dependencies found:', file=sys.stderr)
            for xs in cyclic:
                print('- {0}'.format(xs), file=sys.stderr)
            print('-'*72, file=sys.stderr)

    show_only = set(args.packages.split(',')) if args.packages else None

    tree = render_tree(tree if not args.reverse else reverse_tree(tree),
                       list_all=args.all, show_only=show_only,
                       frozen=args.freeze)
    print(tree)
    return 0

if __name__ == '__main__':
    sys.exit(main())
<commit_msg>Minor pep8 violations fix.<commit_after>from __future__ import print_function
import sys
from itertools import chain, tee
from collections import defaultdict
import argparse
import json

import pip

__version__ = '0.5.0'

flatten = chain.from_iterable

def build_dist_index(pkgs):
    """Build an index pkgs by their key as a dict.

    :param list pkgs: list of pkg_resources.Distribution instances
    :returns: index of the pkgs by the pkg key
    :rtype: dict

    """
    return dict((p.key, DistPackage(p)) for p in pkgs)

def construct_tree(index):
    """Construct tree representation of the pkgs from the index.

    The keys of the dict representing the tree will be objects of type
    DistPackage and the values will be list of ReqPackage objects.

    :param dict index: dist index ie. index of pkgs by their keys
    :returns: tree of pkgs and their dependencies
    :rtype: dict

    """
    return dict((p, [ReqPackage(r, index.get(r.key))
                     for r in p.requires()])
                for p in index.values())

def reverse_tree(tree):
    """Reverse the dependency tree.

    ie. the keys of the resulting dict are objects of type
    ReqPackage and the values are lists of DistPackage objects.

    :param dict tree: the pkg dependency tree obtained by calling
                      `construct_tree` function
    :returns: reversed tree
    :rtype: dict

    """
    rtree = {}
    visited = set()
    child_keys = set(c.key for c in flatten(tree.values()))
    for k, vs in tree.items():
        for v in vs:
            if v not in rtree:
                rtree[v] = []
            rtree[v].append(k)
            visited.add(v.key)
        if k.key not in child_keys:
            rtree[k.as_requirement()] = []
    return rtree

class Package(object):
    """Abstract class for wrappers around objects that pip returns.

    This class needs to be subclassed with implementations for
    `render_as_root` and `render_as_branch` methods.

    """

    def __init__(self, obj):
        self._obj = obj
        self.project_name = obj.project_name
        self.key = obj.key
        # an instance of every subclass of Package will have a
        # DistPackage object associated with it. In case of
        # DistPackage class, it will be the object itself.
        self.dist = None

    def render_as_root(self, frozen):
        return NotImplementedError

    def render_as_branch(self, parent, frozen):
        return NotImplementedError

    def render(self, parent=None, frozen=False):
        if not parent:
            return self.render_as_root(frozen)
        else:
            return self.render_as_branch(parent, frozen)

    def frozen_repr(self):
        if self.dist:
            fr = pip.FrozenRequirement.from_dist(self.dist._obj, [])
            return str(fr).strip()
        else:
            return self.project_name

    def __getattr__(self, key):
        return getattr(self._obj, key)

    def __repr__(self):
        return '<{0}("{1}")>'.format(self.__class__.__name__, self.key)

class DistPackage(Package):
    """Wrapper class for pkg_resources.Distribution instances"""

    def __init__(self, obj):
        super(DistPackage, self).__init__(obj)
        # this itself is the associated dist package obj
        self.dist = self
        self.version_spec = None

    def render_as_root(self, frozen):
        if not frozen:
            return '{0}=={1}'.format(self.project_name, self.version)
        else:
            return self.frozen_repr()

    def render_as_branch(self, parent, frozen):
        if not frozen:
            parent_ver_spec = parent.version_spec
            parent_str = parent.project_name
            if parent_ver_spec:
                parent_str += parent_ver_spec
            return (
                '{0}=={1} [requires: {2}]'
            ).format(self.project_name, self.version, parent_str)
        else:
            return self.render_as_root(frozen)

    def as_requirement(self):
        return ReqPackage(self._obj.as_requirement(), dist=self)

    def as_dict(self):
        return {'key': self.key,
                'package_name': self.project_name,
                'installed_version': self.version}

class ReqPackage(Package):
    """Wrapper class for Requirements instance"""

    def __init__(self, obj, dist=None):
        super(ReqPackage, self).__init__(obj)
        self.dist = dist

    @property
    def version_spec(self):
        specs = self._obj.specs
        return ','.join([''.join(sp) for sp in specs]) if specs else None

    @property
    def installed_version(self):
        # if the dist is None as in some cases, we don't know the
        # installed version
        return self.dist.version if self.dist else '?'

    def render_as_root(self, frozen):
        if not frozen:
            return '{0}=={1}'.format(self.project_name, self.installed_version)
        else:
            return self.frozen_repr()

    def render_as_branch(self, _parent, frozen):
        if not frozen:
            vers = []
            if self.version_spec:
                vers.append(('required', self.version_spec))
            if self.dist:
                vers.append(('installed', self.installed_version))
            if not vers:
                return self.key
            ver_str = ', '.join(['{0}: {1}'.format(k, v) for k, v in vers])
            return '{0} [{1}]'.format(self.project_name, ver_str)
        else:
            return self.render_as_root(frozen)

    def as_dict(self):
        return {'key': self.key,
                'package_name': self.project_name,
                'installed_version': self.installed_version,
                'required_version': self.version_spec}

def render_tree(tree, list_all=True, show_only=None, frozen=False):
    """Convert to tree to string representation

    :param dict tree: the package tree
    :param bool list_all: whether to list all the pgks at the root
                          level or only those that are the
                          sub-dependencies
    :param set show_only: set of select packages to be shown in the
                          output. This is optional arg, default: None.
    :param bool frozen: whether or not show the names of the pkgs in
                        the output that's favourable to pip --freeze
    :returns: string representation of the tree
    :rtype: str

    """
    branch_keys = set(r.key for r in flatten(tree.values()))
    nodes = tree.keys()
    use_bullets = not frozen

    key_tree = dict((k.key, v) for k, v in tree.items())

    def get_children(n):
        return key_tree[n.key]

    if show_only:
        nodes = [p for p in nodes
                 if p.key in show_only or p.project_name in show_only]
    elif not list_all:
        nodes = [p for p in nodes if p.key not in branch_keys]

    def aux(node, parent=None, indent=0, chain=None):
        if chain is None:
            chain = [node.project_name]
        node_str = node.render(parent, frozen)
        if parent:
            prefix = ' '*indent + ('-' if use_bullets else ' ') + ' '
            node_str = prefix + node_str
        result = [node_str]

        # the dist attr for some ReqPackage could be None
        # eg. testresources, setuptools which is a dependencies of
        # some pkg but doesn't get listed in the result of
        # pip.get_installed_distributions.
        if node.dist:
            children = [aux(c, node, indent=indent+2,
                            chain=chain+[c.project_name])
                        for c in get_children(node)
                        if c.project_name not in chain]
            result += list(flatten(children))
        return result

    lines = flatten([aux(p) for p in nodes])
    return '\n'.join(lines)

def jsonify_tree(tree, indent):
    """Converts the tree into json representation.

    The json repr will be a list of hashes, each hash having 2 fields:
      - package
      - dependencies: list of dependencies

    :param dict tree: dependency tree
    :param int indent: no. of spaces to indent json
    :returns: json representation of the tree
    :rtype: str

    """
    return json.dumps([{'package': k.as_dict(),
                        'dependencies': [v.as_dict() for v in vs]}
                       for k, vs in tree.items()],
                      indent=indent)

def confusing_deps(tree):
    """Returns group of dependencies that are possibly confusing

    eg. if pkg1 requires pkg3>=1.0 and pkg2 requires pkg3>=1.0,<=2.0

    :param dict tree: the requirements tree
    :returns: groups of dependencies paired with their top level pkgs
    :rtype: list of list of pairs

    """
    def has_multi_versions(req_pkgs):
        return len(set(r.version_spec for r in req_pkgs)) > 1

    deps = defaultdict(list)
    for p, rs in tree.items():
        for r in rs:
            deps[r.key].append((p, r))
    return [ps for r, ps in deps.items()
            if len(ps) > 1 and has_multi_versions(d for p, d in ps)]

def cyclic_deps(tree):
    """Generator that produces cyclic dependencies

    :param list pkgs: pkg_resources.Distribution instances
    :param dict pkg_index: mapping of pkgs with their respective keys
    :returns: generator that yields str representation of cyclic
              dependencies
    :rtype: generator

    """
    nodes = tree.keys()
    key_tree = dict((k.key, v) for k, v in tree.items())

    def get_children(n):
        return key_tree[n.key]

    def aux(node, chain):
        if node.dist:
            for c in get_children(node):
                if c.project_name in chain:
                    yield ' => '.join([str(p) for p in chain] + [str(c)])
                else:
                    for cycle in aux(c, chain=chain+[c.project_name]):
                        yield cycle

    for cycle in flatten([aux(n, chain=[]) for n in nodes]):
        yield cycle

def peek_into(iterator):
    """Peeks into an iterator to check if it's empty

    :param iterator: an iterator
    :returns: tuple of boolean representing whether the iterator is
              empty or not and the iterator itself.
    :rtype: tuple

    """
    a, b = tee(iterator)
    is_empty = False
    try:
        next(a)
    except StopIteration:
        is_empty = True
    return is_empty, b

def main():
    parser = argparse.ArgumentParser(description=(
        'Dependency tree of the installed python packages'
    ))
    parser.add_argument('-f', '--freeze', action='store_true',
                        help='Print names so as to write freeze files')
    parser.add_argument('-a', '--all', action='store_true',
                        help='list all deps at top level')
    parser.add_argument('-l', '--local-only',
                        action='store_true', help=(
                            'If in a virtualenv that has global access '
                            'donot show globally installed packages'
                        ))
    parser.add_argument('-w', '--nowarn', action='store_true',
                        help=(
                            'Inhibit warnings about possibly '
                            'confusing packages'
                        ))
    parser.add_argument('-r', '--reverse', action='store_true',
                        default=False, help=(
                            'Shows the dependency tree in the reverse fasion '
                            'ie. the sub-dependencies are listed with the '
                            'list of packages that need them under them.'
                        ))
    parser.add_argument('-p', '--packages',
                        help=(
                            'Comma separated list of select packages to show '
                            'in the output. If set, --all will be ignored.'
                        ))
    parser.add_argument('-j', '--json', action='store_true', default=False,
                        help=(
                            'Display dependency tree as json. This will yield '
                            '"raw" output that may be used by external tools. '
                            'This option overrides all other options.'
                        ))
    args = parser.parse_args()

    default_skip = ['setuptools', 'pip', 'python', 'distribute']
    skip = default_skip + ['pipdeptree']
    pkgs = pip.get_installed_distributions(local_only=args.local_only,
                                           skip=skip)

    dist_index = build_dist_index(pkgs)
    tree = construct_tree(dist_index)

    if args.json:
        print(jsonify_tree(tree, indent=4))
        return 0

    # show warnings about possibly confusing deps if found and
    # warnings are enabled
    if not args.nowarn:
        confusing = confusing_deps(tree)
        if confusing:
            print('Warning!!! Possible confusing dependencies found:',
                  file=sys.stderr)
            for xs in confusing:
                for i, (p, d) in enumerate(xs):
                    if d.key in skip:
                        continue
                    pkg = p.render_as_root(False)
                    req = d.render_as_branch(p, False)
                    tmpl = '  {0} -> {1}' if i > 0 else '* {0} -> {1}'
                    print(tmpl.format(pkg, req), file=sys.stderr)
            print('-'*72, file=sys.stderr)

        is_empty, cyclic = peek_into(cyclic_deps(tree))
        if not is_empty:
            print('Warning!!! Cyclic dependencies found:', file=sys.stderr)
            for xs in cyclic:
                print('- {0}'.format(xs), file=sys.stderr)
            print('-'*72, file=sys.stderr)

    show_only = set(args.packages.split(',')) if args.packages else None

    tree = render_tree(tree if not args.reverse else reverse_tree(tree),
                       list_all=args.all, show_only=show_only,
                       frozen=args.freeze)
    print(tree)
    return 0

if __name__ == '__main__':
    sys.exit(main())
<|endoftext|>


<commit_before>import sys
from itertools import chain
import argparse

import pip

flatten = chain.from_iterable

def req_version(req):
    """Builds the version string for the requirement instance

    :param req : representing requirement
    :rtype     : string or NoneType

    """
    return ''.join(req.specs[0]) if req.specs else None

def top_pkg_name(pkg):
    """Builds the package name for top level package

    The format is the same that's used by `pip freeze`

    :param pkg : pkg_resources.Distribution
    :rtype     : string

    """
    return '{}=={}'.format(pkg.project_name, pkg.version)

def non_top_pkg_name(req, pkg):
    """Builds the package name for a non-top level package

    For the dependencies of the top level packages, the installed
    version as well as the version required by it's parent package
    will be specified with it's name

    :param req : requirements instance
    :param pkg : pkg_resources.Distribution
    :rtype     : string

    """
    vers = []
    req_ver = req_version(req)
    if req_ver:
        vers.append(('required', req_ver))
    if pkg:
        vers.append(('installed', pkg.version))
    if not vers:
        return req.key
    ver_str = ', '.join(['{}: {}'.format(k, v) for k, v in vers])
    return '{} [{}]'.format(pkg.project_name, ver_str)

def top_pkg_src(pkg):
    return str(pip.FrozenRequirement.from_dist(pkg, [])).strip()

def non_top_pkg_src(_, pkg):
    return top_pkg_src(pkg)

def render_tree(pkgs, freeze, list_all):
    """Renders a package dependency tree

    :param pkgs     : list of pkg_resources.Distribution
    :param list_all : boolean
    :rtype          : string

    """
    pkg_index = {p.key: p for p in pkgs}
    non_top = set(flatten((x.key for x in p.requires())
                          for p in pkgs))
    top = [p for p in pkgs if p.key not in non_top]

    if freeze:
        top_pkg_str, non_top_pkg_str = top_pkg_src, non_top_pkg_src
    else:
        top_pkg_str, non_top_pkg_str = top_pkg_name, non_top_pkg_name

    def aux(pkg, indent=0):
        if indent > 0:
            result = [' '*indent +
                      '- ' +
                      non_top_pkg_str(pkg, pkg_index.get(pkg.key))]
        else:
            result = [top_pkg_str(pkg)]
        if pkg.key in pkg_index:
            pkg_deps = pkg_index[pkg.key].requires()
            result += list(flatten([aux(d, indent=indent+2)
                                    for d in pkg_deps]))
        return result

    lines = flatten([aux(p) for p in (pkgs if list_all else top)])
    return '\n'.join(lines)

def main():
    parser = argparse.ArgumentParser(description=(
        'Dependency tree of the installed python packages'
    ))
    parser.add_argument('-f', '--freeze', action='store_true',
                        help='Print names so as to write freeze files')
    parser.add_argument('-a', '--all', action='store_true',
                        help='list all deps at top level')
    parser.add_argument('-l', '--local-only',
                        action='store_true', help=(
                            'If in a virtualenv that has global access '
                            'donot show globally installed packages'
                        ))
    args = parser.parse_args()
    default_skip = ['setuptools', 'pip', 'python', 'distribute']
    skip = default_skip + ['pipdeptree']
    packages = pip.get_installed_distributions(local_only=args.local_only,
                                               skip=skip)
    print(render_tree(packages, freeze=args.freeze, list_all=args.all))
    return 0

if __name__ == '__main__':
    sys.exit(main())
<commit_msg>Update and fix the docstrings<commit_after>import sys
from itertools import chain
import argparse

import pip

flatten = chain.from_iterable

def req_version(req):
    """Builds the version string for the requirement instance

    :param req: requirement object
    :returns: the version in desired format
    :rtype: string or NoneType

    """
    return ''.join(req.specs[0]) if req.specs else None

def top_pkg_name(pkg):
    """Builds the package name for top level package

    This just prints the name and the version of the package which may
    not necessarily match with the output of `pip freeze` which also
    includes info such as VCS source for editable packages

    :param pkg: pkg_resources.Distribution
    :returns: the package name and version in the desired format
    :rtype: string

    """
    return '{}=={}'.format(pkg.project_name, pkg.version)

def non_top_pkg_name(req, pkg):
    """Builds the package name for a non-top level package

    For the dependencies of the top level packages, the installed
    version as well as the version required by it's parent package
    will be specified with it's name

    :param req: requirements instance
    :param pkg: pkg_resources.Distribution
    :returns: the package name and version in the desired format
    :rtype: string

    """
    vers = []
    req_ver = req_version(req)
    if req_ver:
        vers.append(('required', req_ver))
    if pkg:
        vers.append(('installed', pkg.version))
    if not vers:
        return req.key
    ver_str = ', '.join(['{}: {}'.format(k, v) for k, v in vers])
    return '{} [{}]'.format(pkg.project_name, ver_str)

def top_pkg_src(pkg):
    """Returns the frozen package name

    The may or may not be the same as the package name.

    :param pkg: pkg_resources.Distribution
    :returns: frozen name of the package
    :rtype: string

    """
    return str(pip.FrozenRequirement.from_dist(pkg, [])).strip()

def non_top_pkg_src(_req, pkg):
    """FIXME! briefly describe function

    :param _req: the requirements instance
    :param pkg: pkg_resources.Distribution
    :returns: frozen name of the package
    :rtype: string

    """
    return top_pkg_src(pkg)

def render_tree(pkgs, freeze, list_all):
    """Renders a package dependency tree

    :param pkgs: list of pkg_resources.Distribution
    :param list_all: boolean
    :rtype: string

    """
    pkg_index = {p.key: p for p in pkgs}
    non_top = set(flatten((x.key for x in p.requires())
                          for p in pkgs))
    top = [p for p in pkgs if p.key not in non_top]

    if freeze:
        top_pkg_str, non_top_pkg_str = top_pkg_src, non_top_pkg_src
    else:
        top_pkg_str, non_top_pkg_str = top_pkg_name, non_top_pkg_name

    def aux(pkg, indent=0):
        if indent > 0:
            result = [' '*indent +
                      '- ' +
                      non_top_pkg_str(pkg, pkg_index.get(pkg.key))]
        else:
            result = [top_pkg_str(pkg)]
        if pkg.key in pkg_index:
            pkg_deps = pkg_index[pkg.key].requires()
            result += list(flatten([aux(d, indent=indent+2)
                                    for d in pkg_deps]))
        return result

    lines = flatten([aux(p) for p in (pkgs if list_all else top)])
    return '\n'.join(lines)

def main():
    parser = argparse.ArgumentParser(description=(
        'Dependency tree of the installed python packages'
    ))
    parser.add_argument('-f', '--freeze', action='store_true',
                        help='Print names so as to write freeze files')
    parser.add_argument('-a', '--all', action='store_true',
                        help='list all deps at top level')
    parser.add_argument('-l', '--local-only',
                        action='store_true', help=(
                            'If in a virtualenv that has global access '
                            'donot show globally installed packages'
                        ))
    args = parser.parse_args()
    default_skip = ['setuptools', 'pip', 'python', 'distribute']
    skip = default_skip + ['pipdeptree']
    packages = pip.get_installed_distributions(local_only=args.local_only,
                                               skip=skip)
    print(render_tree(packages, freeze=args.freeze, list_all=args.all))
    return 0

if __name__ == '__main__':
    sys.exit(main())
<|endoftext|>


<commit_before># This file is part of Indico.
# Copyright (C) 2002 - 2018 European Organization for Nuclear Research (CERN).
#
# Indico is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3 of the
# License, or (at your option) any later version.
#
# Indico is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Indico; if not, see <http://www.gnu.org/licenses/>.

import os

from flask import Response, current_app, json, redirect, render_template, send_from_directory, session
from werkzeug.exceptions import NotFound

from indico.core.config import config
from indico.core.plugins import plugin_engine
from indico.modules.events.layout import theme_settings
from indico.modules.users.util import serialize_user
from indico.util.i18n import po_to_json
from indico.util.string import crc32
from indico.web.assets.util import get_asset_path
from indico.web.assets.vars_js import generate_global_file
from indico.web.flask.util import send_file, url_for
from indico.web.flask.wrappers import IndicoBlueprint

assets_blueprint = IndicoBlueprint('assets', __name__, url_prefix='/assets')
assets_blueprint.add_url_rule('!/css/<path:filename>', 'css', build_only=True)
assets_blueprint.add_url_rule('!/images/<path:filename>', 'image', build_only=True)
assets_blueprint.add_url_rule('!/js/<path:filename>', 'js', build_only=True)

@assets_blueprint.route('/js-vars/global.js')
def js_vars_global():
    """
    Provides a JS file with global definitions (all users)
    Useful for server-wide config options, URLs, etc...
    """
    cache_file = os.path.join(config.CACHE_DIR, 'assets_global_{}.js'.format(config.hash))

    if not os.path.exists(cache_file):
        data = generate_global_file()
        with open(cache_file, 'wb') as f:
            f.write(data)

    return send_file('global.js', cache_file, mimetype='application/javascript', no_cache=False, conditional=True)

@assets_blueprint.route('/js-vars/user.js')
def js_vars_user():
    """
    Provides a JS file with user-specific definitions
    Useful for favorites, settings etc.
    """
    user = session.user
    if user is None:
        user_vars = {}
    else:
        user_vars = {
            'id': user.id,
            'first_name': user.first_name,
            'last_name': user.last_name,
            'favorite_users': {u.id: serialize_user(u) for u in user.favorite_users}
        }
    data = render_template('assets/vars_user.js', user_vars=user_vars, user=user)
    return Response(data, mimetype='application/javascript')

def locale_data(path, name, domain):
    po_file = os.path.join(path, name, 'LC_MESSAGES', 'messages-js.po')
    return po_to_json(po_file, domain=domain, locale=name) if os.access(po_file, os.R_OK) else {}

@assets_blueprint.route('/i18n/<locale_name>.js')
def i18n_locale(locale_name):
    """
    Retrieve a locale in a Jed-compatible format
    """
    root_path = os.path.join(current_app.root_path, 'translations')
    plugin_key = ','.join(sorted(plugin_engine.get_active_plugins()))
    cache_file = os.path.join(config.CACHE_DIR, 'assets_i18n_{}_{}.js'.format(locale_name, crc32(plugin_key)))

    if not os.path.exists(cache_file):
        i18n_data = locale_data(root_path, locale_name, 'indico')
        if not i18n_data:
            # Dummy data, not having the indico domain would cause lots of failures
            i18n_data = {'indico': {'': {'domain': 'indico',
                                         'lang': locale_name}}}

        for pid, plugin in plugin_engine.get_active_plugins().iteritems():
            data = {}
            if plugin.translation_path:
                data = locale_data(plugin.translation_path, locale_name, pid)
            if not data:
                # Dummy entry so we can still load the domain
                data = {pid: {'': {'domain': pid,
                                   'lang': locale_name}}}
            i18n_data.update(data)

        with open(cache_file, 'wb') as f:
            f.write("window.TRANSLATIONS = {};".format(json.dumps(i18n_data)))

    return send_file('{}.js'.format(locale_name), cache_file, mimetype='application/javascript',
                     no_cache=False, conditional=True)

@assets_blueprint.route('!/static/assets/core/<path:path>')
@assets_blueprint.route('!/static/assets/plugin-<plugin>/<path:path>')
@assets_blueprint.route('!/static/assets/theme-<theme>/<path:path>')
def static_asset(path, plugin=None, theme=None):
    # Ensure there's no weird stuff in the plugin/theme name
    if plugin and not plugin_engine.get_plugin(plugin):
        raise NotFound
    elif theme and theme not in theme_settings.themes:
        raise NotFound
    return send_from_directory(config.ASSETS_DIR, get_asset_path(path, plugin=plugin, theme=theme))

@assets_blueprint.route('!/static/custom/<path:filename>', endpoint='custom')
def static_custom(filename):
    customization_dir = config.CUSTOMIZATION_DIR
    if not customization_dir:
        raise NotFound
    customization_dir = os.path.join(customization_dir, 'static')
    return send_from_directory(customization_dir, filename)

@assets_blueprint.route('!/favicon.ico')
def favicon():
    return redirect(url_for('.image', filename='indico.ico'))
<commit_msg>Include version in js cache file names<commit_after># This file is part of Indico.
# Copyright (C) 2002 - 2018 European Organization for Nuclear Research (CERN).
#
# Indico is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3 of the
# License, or (at your option) any later version.
#
# Indico is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Indico; if not, see <http://www.gnu.org/licenses/>.

import os

from flask import Response, current_app, json, redirect, render_template, send_from_directory, session
from werkzeug.exceptions import NotFound

import indico
from indico.core.config import config
from indico.core.plugins import plugin_engine
from indico.modules.events.layout import theme_settings
from indico.modules.users.util import serialize_user
from indico.util.i18n import po_to_json
from indico.web.assets.util import get_asset_path
from indico.web.assets.vars_js import generate_global_file
from indico.web.flask.util import send_file, url_for
from indico.web.flask.wrappers import IndicoBlueprint

assets_blueprint = IndicoBlueprint('assets', __name__, url_prefix='/assets')
assets_blueprint.add_url_rule('!/css/<path:filename>', 'css', build_only=True)
assets_blueprint.add_url_rule('!/images/<path:filename>', 'image', build_only=True)
assets_blueprint.add_url_rule('!/js/<path:filename>', 'js', build_only=True)

@assets_blueprint.route('/js-vars/global.js')
def js_vars_global():
    """
    Provides a JS file with global definitions (all users)
    Useful for server-wide config options, URLs, etc...
    """
    cache_file = os.path.join(config.CACHE_DIR, 'assets_global_{}_{}.js'.format(indico.__version__, config.hash))

    if not os.path.exists(cache_file):
        data = generate_global_file()
        with open(cache_file, 'wb') as f:
            f.write(data)

    return send_file('global.js', cache_file, mimetype='application/javascript', no_cache=False, conditional=True)

@assets_blueprint.route('/js-vars/user.js')
def js_vars_user():
    """
    Provides a JS file with user-specific definitions
    Useful for favorites, settings etc.
    """
    user = session.user
    if user is None:
        user_vars = {}
    else:
        user_vars = {
            'id': user.id,
            'first_name': user.first_name,
            'last_name': user.last_name,
            'favorite_users': {u.id: serialize_user(u) for u in user.favorite_users}
        }
    data = render_template('assets/vars_user.js', user_vars=user_vars, user=user)
    return Response(data, mimetype='application/javascript')

def locale_data(path, name, domain):
    po_file = os.path.join(path, name, 'LC_MESSAGES', 'messages-js.po')
    return po_to_json(po_file, domain=domain, locale=name) if os.access(po_file, os.R_OK) else {}

@assets_blueprint.route('/i18n/<locale_name>.js')
def i18n_locale(locale_name):
    """
    Retrieve a locale in a Jed-compatible format
    """
    root_path = os.path.join(current_app.root_path, 'translations')
    cache_file = os.path.join(config.CACHE_DIR, 'assets_i18n_{}_{}_{}.js'.format(
        locale_name, indico.__version__, config.hash))

    if not os.path.exists(cache_file):
        i18n_data = locale_data(root_path, locale_name, 'indico')
        if not i18n_data:
            # Dummy data, not having the indico domain would cause lots of failures
            i18n_data = {'indico': {'': {'domain': 'indico',
                                         'lang': locale_name}}}

        for pid, plugin in plugin_engine.get_active_plugins().iteritems():
            data = {}
            if plugin.translation_path:
                data = locale_data(plugin.translation_path, locale_name, pid)
            if not data:
                # Dummy entry so we can still load the domain
                data = {pid: {'': {'domain': pid,
                                   'lang': locale_name}}}
            i18n_data.update(data)

        with open(cache_file, 'wb') as f:
            f.write("window.TRANSLATIONS = {};".format(json.dumps(i18n_data)))

    return send_file('{}.js'.format(locale_name), cache_file, mimetype='application/javascript',
                     no_cache=False, conditional=True)

@assets_blueprint.route('!/static/assets/core/<path:path>')
@assets_blueprint.route('!/static/assets/plugin-<plugin>/<path:path>')
@assets_blueprint.route('!/static/assets/theme-<theme>/<path:path>')
def static_asset(path, plugin=None, theme=None):
    # Ensure there's no weird stuff in the plugin/theme name
    if plugin and not plugin_engine.get_plugin(plugin):
        raise NotFound
    elif theme and theme not in theme_settings.themes:
        raise NotFound
    return send_from_directory(config.ASSETS_DIR, get_asset_path(path, plugin=plugin, theme=theme))

@assets_blueprint.route('!/static/custom/<path:filename>', endpoint='custom')
def static_custom(filename):
    customization_dir = config.CUSTOMIZATION_DIR
    if not customization_dir:
        raise NotFound
    customization_dir = os.path.join(customization_dir, 'static')
    return send_from_directory(customization_dir, filename)

@assets_blueprint.route('!/favicon.ico')
def favicon():
    return redirect(url_for('.image', filename='indico.ico'))
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##
##
## This file is part of CDS Indico.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
##
## CDS Indico is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Indico is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

# python stdlib imports
import datetime
import icalendar as ical

# indico imports
from indico.util.metadata.serializer import Serializer

# legacy indico imports
from MaKaC.rb_reservation import RepeatabilityEnum
from MaKaC.rb_tools import weekNumber

WEEK_DAYS = 'MO TU WE TH FR SA SU'.split()

class vRecur(ical.vRecur):
    """Fix vRecur so the frequency comes first"""
    def ical(self):
        # SequenceTypes
        result = ['FREQ=%s' % self.types['FREQ'](self['FREQ']).ical()]
        for key, vals in self.items():
            if key == 'FREQ':
                continue
            typ = self.types[key]
            if not type(vals) in ical.prop.SequenceTypes:
                vals = [vals]
            vals = ','.join([typ(val).ical() for val in vals])
            result.append('%s=%s' % (key, vals))
        return ';'.join(result)

ical.cal.types_factory['recur'] = vRecur

def serialize_event(cal, fossil, now, id_prefix="indico-event"):
    event = ical.Event()
    event.set('uid', '%s-%s@cern.ch' % (id_prefix, fossil['id']))
    event.set('dtstamp', now)
    event.set('dtstart', fossil['startDate'])
    event.set('dtend', fossil['endDate'])
    event.set('url', fossil['url'])
    event.set('summary', fossil['title'].decode('utf-8'))
    loc = fossil['location'] or ''
    if loc:
        loc = loc.decode('utf-8')
    if fossil['room']:
        loc += ' ' + fossil['room'].decode('utf-8')
    event.set('location', loc)
    if fossil['description']:
        event.set('description', fossil['description'].decode('utf-8') + '\n' + fossil['url'])
    else:
        event.set('description', fossil['url'])
    cal.add_component(event)

def serialize_repeatability(startDT, endDT, repType):
    intervals = { RepeatabilityEnum.onceAWeek: 1, RepeatabilityEnum.onceEvery2Weeks: 2, RepeatabilityEnum.onceEvery3Weeks: 3 }
    recur = ical.vRecur()
    recur['until'] = endDT
    if repType == RepeatabilityEnum.daily:
        recur['freq'] = 'daily'
    elif repType in intervals.keys():
        recur['freq'] = 'weekly'
        recur['interval'] = intervals[repType]
    elif repType == RepeatabilityEnum.onceAMonth:
        recur['freq'] = 'monthly'
        recur['byday'] = str(weekNumber(startDT)) + WEEK_DAYS[startDT.weekday()]
    return recur

def serialize_reservation(cal, fossil, now):
    event = ical.Event()
    event.set('uid', 'indico-resv-%s@cern.ch' % fossil['id'])
    event.set('dtstamp', now)
    event.set('dtstart', fossil['startDT'])
    event.set('dtend', datetime.datetime.combine(fossil['startDT'].date(), fossil['endDT'].time()))
    event.set('url', fossil['bookingUrl'])
    event.set('summary', fossil['reason'])
    event.set('location', fossil['location'].decode('utf-8') + ': ' + fossil['room']['fullName'].decode('utf-8'))
    event.set('description', fossil['reason'].decode('utf-8') + '\n' + fossil['bookingUrl'])
    rrule = None
    if fossil['repeatability'] is not None:
        rrule = serialize_repeatability(fossil['startDT'], fossil['endDT'], RepeatabilityEnum.shortname2rep[fossil['repeatability']])
    if rrule:
        event.set('rrule', rrule)
    cal.add_component(event)

def serialize_contribs(cal, fossil, now):
    for sfossil in fossil['contributions']:
        if sfossil['startDate']:
            sfossil['id'] = "%s-%s" % (fossil['id'], sfossil['id'])
            serialize_event(cal, sfossil, now, id_prefix="indico-contribution")

def serialize_contrib(cal, fossil, now):
    serialize_event(cal, fossil, now, id_prefix="indico-contribution")

class ICalSerializer(Serializer):

    schemaless = False
    _mime = 'text/calendar'

    _mappers = {
        'conferenceMetadata': serialize_event,
        'reservationMetadata': serialize_reservation,
        'conferenceMetadataWithContribs': serialize_contribs,
        'sessionMetadata': serialize_contribs,
        'contributionMetadata': serialize_contrib
    }

    @classmethod
    def register_mapper(cls, fossil, func):
        cls._mappers[fossil] = func

    def __call__(self, fossils):
        results = fossils['results']
        if type(results) != list:
            results = [results]

        cal = ical.Calendar()
        cal.set('version', '2.0')
        cal.set('prodid', '-//CERN//INDICO//EN')
        now = datetime.datetime.utcnow()
        for fossil in results:
            mapper = ICalSerializer._mappers.get(fossil['_fossil'])
            if mapper:
                mapper(cal, fossil, now)

        return cal.to_ical()
<commit_msg>[FIX] ICAL meeting if no entries in TT<commit_after># -*- coding: utf-8 -*-
##
##
## This file is part of CDS Indico.
## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 CERN.
##
## CDS Indico is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License as
## published by the Free Software Foundation; either version 2 of the
## License, or (at your option) any later version.
##
## CDS Indico is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with CDS Indico; if not, write to the Free Software Foundation, Inc.,
## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.

# python stdlib imports
import datetime
import icalendar as ical

# indico imports
from indico.util.metadata.serializer import Serializer

# legacy indico imports
from MaKaC.rb_reservation import RepeatabilityEnum
from MaKaC.rb_tools import weekNumber

WEEK_DAYS = 'MO TU WE TH FR SA SU'.split()

class vRecur(ical.vRecur):
    """Fix vRecur so the frequency comes first"""
    def ical(self):
        # SequenceTypes
        result = ['FREQ=%s' % self.types['FREQ'](self['FREQ']).ical()]
        for key, vals in self.items():
            if key == 'FREQ':
                continue
            typ = self.types[key]
            if not type(vals) in ical.prop.SequenceTypes:
                vals = [vals]
            vals = ','.join([typ(val).ical() for val in vals])
            result.append('%s=%s' % (key, vals))
        return ';'.join(result)

ical.cal.types_factory['recur'] = vRecur

def serialize_event(cal, fossil, now, id_prefix="indico-event"):
    event = ical.Event()
    event.set('uid', '%s-%s@cern.ch' % (id_prefix, fossil['id']))
    event.set('dtstamp', now)
    event.set('dtstart', fossil['startDate'])
    event.set('dtend', fossil['endDate'])
    event.set('url', fossil['url'])
    event.set('summary', fossil['title'].decode('utf-8'))
    loc = fossil['location'] or ''
    if loc:
        loc = loc.decode('utf-8')
    if fossil['room']:
        loc += ' ' + fossil['room'].decode('utf-8')
    event.set('location', loc)
    if fossil['description']:
        event.set('description', fossil['description'].decode('utf-8') + '\n' + fossil['url'])
    else:
        event.set('description', fossil['url'])
    cal.add_component(event)

def serialize_repeatability(startDT, endDT, repType):
    intervals = { RepeatabilityEnum.onceAWeek: 1, RepeatabilityEnum.onceEvery2Weeks: 2, RepeatabilityEnum.onceEvery3Weeks: 3 }
    recur = ical.vRecur()
    recur['until'] = endDT
    if repType == RepeatabilityEnum.daily:
        recur['freq'] = 'daily'
    elif repType in intervals.keys():
        recur['freq'] = 'weekly'
        recur['interval'] = intervals[repType]
    elif repType == RepeatabilityEnum.onceAMonth:
        recur['freq'] = 'monthly'
        recur['byday'] = str(weekNumber(startDT)) + WEEK_DAYS[startDT.weekday()]
    return recur

def serialize_reservation(cal, fossil, now):
    event = ical.Event()
    event.set('uid', 'indico-resv-%s@cern.ch' % fossil['id'])
    event.set('dtstamp', now)
    event.set('dtstart', fossil['startDT'])
    event.set('dtend', datetime.datetime.combine(fossil['startDT'].date(), fossil['endDT'].time()))
    event.set('url', fossil['bookingUrl'])
    event.set('summary', fossil['reason'])
    event.set('location', fossil['location'].decode('utf-8') + ': ' + fossil['room']['fullName'].decode('utf-8'))
    event.set('description', fossil['reason'].decode('utf-8') + '\n' + fossil['bookingUrl'])
    rrule = None
    if fossil['repeatability'] is not None:
        rrule = serialize_repeatability(fossil['startDT'], fossil['endDT'], RepeatabilityEnum.shortname2rep[fossil['repeatability']])
    if rrule:
        event.set('rrule', rrule)
    cal.add_component(event)

def serialize_contribs(cal, fossil, now):
    if len(fossil['contributions']) == 0:
        serialize_event(cal, fossil, now)
    else:
        for sfossil in fossil['contributions']:
            if sfossil['startDate']:
                sfossil['id'] = "%s-%s" % (fossil['id'], sfossil['id'])
                serialize_event(cal, sfossil, now, id_prefix="indico-contribution")

def serialize_contrib(cal, fossil, now):
    serialize_event(cal, fossil, now, id_prefix="indico-contribution")

class ICalSerializer(Serializer):

    schemaless = False
    _mime = 'text/calendar'

    _mappers = {
        'conferenceMetadata': serialize_event,
        'reservationMetadata': serialize_reservation,
        'conferenceMetadataWithContribs': serialize_contribs,
        'sessionMetadata': serialize_contribs,
        'contributionMetadata': serialize_contrib
    }

    @classmethod
    def register_mapper(cls, fossil, func):
        cls._mappers[fossil] = func

    def __call__(self, fossils):
        results = fossils['results']
        if type(results) != list:
            results = [results]

        cal = ical.Calendar()
        cal.set('version', '2.0')
        cal.set('prodid', '-//CERN//INDICO//EN')
        now = datetime.datetime.utcnow()
        for fossil in results:
            mapper = ICalSerializer._mappers.get(fossil['_fossil'])
            if mapper:
                mapper(cal, fossil, now)

        return cal.to_ical()
<|endoftext|>