<commit_before>import numpy as np

def kalman_prediction_and_variance(ts, ys, dys, mu, sigma, ar_roots, ma_roots):
    """Outputs the prediction of a Kalman filter implementing a CARMA
    model and the associated prediction variance for data ``ys`` taken
    at times ``ts`` with measurement uncertanties ``dys``.

    :param ts: The sample times.

    :param ys: The sample data.

    :param dys: The (1-sigma) measurement uncertainties.

    :param mu: The (constant) mean of the filter process.

    :param sigma: The (constant) standard deviation of the filter
      process.

    :param ar_roots: The (possibly complex) roots describing the
      autoregressive part of the CARMA process.

    :param ma_roots: The (possibly complex) roots describing the
      moving average part of the CARMA process.

    :returns: ``(ys_pred, var_ys_pred)``, a tuple of arrays.
      ``ys_pred[i]`` gives the predicted value of time series element
      ``i`` given all the elements, ``j``, with ``j < i`` from the
      filter; ``var_ys_pred[i]`` gives the variance of this
      prediction.

    """

    ts = np.atleast_1d(ts)
    ys = np.atleast_1d(ys)
    dys = np.atleast_1d(dys)

    ar_roots = np.atleast_1d(ar_roots)
    ma_roots = np.atleast_1d(ma_roots)

    p = ar_roots.shape[0]
    q = ma_roots.shape[0]

    ma_poly = np.polynomial.polynomial.polyfromroots(ma_roots)
    ma_poly = ma_poly / ma_poly[-1] # Has a 1 in the constant term
    ma_poly = ma_poly[::-1] # 1.0 + c[1]*x + c[2]*x^2 + ...
    ma_poly = np.concatenate((ma_poly,np.zeros(p-q-1)))

    # Recentre
    ys = ys - mu

    U = np.zeros((p,p), dtype=np.complex)
    for l in range(p):
        for k in range(p):
            U[l,k] = ar_roots[k]**l

    btilde = np.dot(ma_poly, U)

    e = np.zeros(p)
    e[-1] = sigma # This will be adjusted later....

    J = np.linalg.solve(U, e)

    Vtilde = np.zeros((p,p), dtype=np.complex)
    for l in range(p):
        for k in range(p):
            Vtilde[l,k] = -J[l]*np.conj(J[k])/(ar_roots[l] + np.conj(ar_roots[k]))

    xtilde = np.zeros(p)
    Ptilde = Vtilde.copy()

    # Here we adjust the variance matrix so that the variance of the
    # process is sigma*sigma
    R0 = np.dot(btilde, np.dot(Ptilde, np.conj(btilde)))
    sigma_factor2 = sigma*sigma/R0
    Vtilde *= sigma_factor2
    Ptilde *= sigma_factor2

    eys = [0.0]
    vys = [np.dot(btilde, np.dot(Ptilde, np.conj(btilde))) + dys[0]*dys[0]]

    gain = np.dot(Ptilde, np.conj(btilde)) / vys[0]

    xtilde = xtilde + ys[0]*gain
    Ptilde = Ptilde - vys[0]*np.outer(gain, np.conj(gain))

    for i in range(1, ys.shape[0]):
        dt = ts[i] - ts[i-1]
        Lambda = np.diag(np.exp(ar_roots*dt))

        xtilde = np.dot(Lambda, xtilde)
        Ptilde = np.dot(Lambda, np.dot(Ptilde - Vtilde, np.conj(Lambda.T))) + Vtilde

        eys.append(np.dot(btilde, xtilde))
        vys.append(np.dot(btilde, np.dot(Ptilde, np.conj(btilde))) + dys[i]*dys[i])

        gain = np.dot(Ptilde, np.conj(btilde))/vys[i]

        xtilde = xtilde + (ys[i] - eys[i])*gain
        Ptilde = Ptilde - vys[i]*np.outer(gain, np.conj(gain))

    eys = np.real(np.array(eys))
    vys = np.real(np.array(vys))

    return eys + mu, vys
<commit_msg>Better docstrings in kalman.py<commit_after>import numpy as np

def kalman_prediction_and_variance(ts, ys, dys, mu, sigma, ar_roots, ma_roots):
    """Outputs the prediction of a Kalman filter implementing a CARMA
    model and the associated prediction variance for data ``ys`` taken
    at times ``ts`` with measurement uncertanties ``dys``.

    :param ts: The sample times.

    :param ys: The sample data.

    :param dys: The (1-sigma) measurement uncertainties.

    :param mu: The (constant) mean of the filter process.

    :param sigma: The (constant) standard deviation of the filter
      process.

    :param ar_roots: The (possibly complex) roots describing the
      autoregressive part of the CARMA process.

    :param ma_roots: The (possibly complex) roots describing the
      moving average part of the CARMA process.

    :returns: ``(ys_pred, var_ys_pred)``, a tuple of arrays.
      ``ys_pred[i]`` gives the predicted value of time series element
      ``i`` given all the elements, ``j``, with ``j < i`` from the
      filter; ``var_ys_pred[i]`` gives the variance of this
      prediction, incorporating the quoted observational uncertainty.

    """

    ts = np.atleast_1d(ts)
    ys = np.atleast_1d(ys)
    dys = np.atleast_1d(dys)

    ar_roots = np.atleast_1d(ar_roots)
    ma_roots = np.atleast_1d(ma_roots)

    p = ar_roots.shape[0]
    q = ma_roots.shape[0]

    ma_poly = np.polynomial.polynomial.polyfromroots(ma_roots)
    ma_poly = ma_poly / ma_poly[-1] # Has a 1 in the constant term
    ma_poly = ma_poly[::-1] # 1.0 + c[1]*x + c[2]*x^2 + ...
    ma_poly = np.concatenate((ma_poly,np.zeros(p-q-1)))

    # Recentre
    ys = ys - mu

    U = np.zeros((p,p), dtype=np.complex)
    for l in range(p):
        for k in range(p):
            U[l,k] = ar_roots[k]**l

    btilde = np.dot(ma_poly, U)

    e = np.zeros(p)
    e[-1] = sigma # This will be adjusted later....

    J = np.linalg.solve(U, e)

    Vtilde = np.zeros((p,p), dtype=np.complex)
    for l in range(p):
        for k in range(p):
            Vtilde[l,k] = -J[l]*np.conj(J[k])/(ar_roots[l] + np.conj(ar_roots[k]))

    xtilde = np.zeros(p)
    Ptilde = Vtilde.copy()

    # Here we adjust the variance matrix so that the variance of the
    # process is sigma*sigma
    R0 = np.dot(btilde, np.dot(Ptilde, np.conj(btilde)))
    sigma_factor2 = sigma*sigma/R0
    Vtilde *= sigma_factor2
    Ptilde *= sigma_factor2

    eys = [0.0]
    vys = [np.dot(btilde, np.dot(Ptilde, np.conj(btilde))) + dys[0]*dys[0]]

    gain = np.dot(Ptilde, np.conj(btilde)) / vys[0]

    xtilde = xtilde + ys[0]*gain
    Ptilde = Ptilde - vys[0]*np.outer(gain, np.conj(gain))

    for i in range(1, ys.shape[0]):
        dt = ts[i] - ts[i-1]
        Lambda = np.diag(np.exp(ar_roots*dt))

        xtilde = np.dot(Lambda, xtilde)
        Ptilde = np.dot(Lambda, np.dot(Ptilde - Vtilde, np.conj(Lambda.T))) + Vtilde

        eys.append(np.dot(btilde, xtilde))
        vys.append(np.dot(btilde, np.dot(Ptilde, np.conj(btilde))) + dys[i]*dys[i])

        gain = np.dot(Ptilde, np.conj(btilde))/vys[i]

        xtilde = xtilde + (ys[i] - eys[i])*gain
        Ptilde = Ptilde - vys[i]*np.outer(gain, np.conj(gain))

    eys = np.real(np.array(eys))
    vys = np.real(np.array(vys))

    return eys + mu, vys
<|endoftext|>


<commit_before>"""!
The main file with the class definitions

Core
==============

This file contains all of the classes for the module.
"""

from contextlib import contextmanager
import os.path as p
import re

import numpy as np
from scipy.io import FortranFile

class Grid(object):
    """Make a grid object containing all of the axes.

        :param int nx: Number of grid points in the x direction
        :param int ny: Number of grid points in the y direction
        :param int layers: Number of active layers
        :param float dx: Grid size in x direction in metres
        :param float dy: Grid size in y direction in metres
        :param float x0: x value at lower left corner of domain
        :param float y0: y value at lower left corner of domain

        The initialisation call returns an object containing each of the input parameters as well as the following arrays:

        - x: x locations of the tracer points
        - y: y locations of the tracer points
        - xp1: x locations of the u velocity points and vorticity points
        - yp1: y locations of the v velocity points and vorticity points
        """

    def __init__(self,nx,ny,layers,dx,dy,x0=0,y0=0):
        """Instantiate a grid object for Aronnax."""

        # axes for vorticity points
        self.xp1 = np.linspace(x0,nx*dx+x0,nx+1)
        self.yp1 = np.linspace(y0,ny*dy+y0,ny+1)

        # Axes for tracer points.
        self.x = (self.xp1[1:] + self.xp1[:-1])/2.
        self.y = (self.yp1[1:] + self.yp1[:-1])/2.

        # Size
        self.nx = nx
        self.ny = ny
        self.layers = layers

        # Grid spacing
        self.dx = dx
        self.dy = dy

@contextmanager
def fortran_file(*args, **kwargs):
    f = FortranFile(*args, **kwargs)
    try:
        yield f
    finally:
        f.close()

def interpret_raw_file(name, nx, ny, layers):
    """Read an output file dumped by the Aronnax core.

    Each such file contains one array, whose size depends on what,
    exactly, is in it, and on the resolution of the simulation.
    Hence, the parameters nx, ny, and layers, as well as the file
    naming convetion, suffice to interpret the content (assuming it
    was generated on the same system)."""
    # Note: This depends on inspection of the output writing code in
    # the Aronnax core, to align array sizes and dimensions.  In
    # particular, Fortran arrays are indexed in decreasing order of
    # rate of change as one traverses the elements sequentially,
    # whereas Python (and all other programming languages I am aware
    # of) indexes in increasing order.
    file_part = p.basename(name)
    dx = 0; dy = 0;
    if file_part.startswith("snap.BP"):
        pass
    if file_part.startswith("snap.eta"):
        layers = 1
    if file_part.startswith("snap.eta_new"):
        layers = 1
    if file_part.startswith("snap.eta_star"):
        layers = 1
    if file_part.startswith("snap.h"):
        pass
    if file_part.startswith("snap.u"):
        dx = 1
    if file_part.startswith("snap.ub"):
        dx = 1
        layers = 1
    if file_part.startswith("snap.v"):
        dy = 1
    if file_part.startswith("snap.vb"):
        dy = 1
        layers = 1
    if file_part.startswith("snap.zeta"):
        dx = 1
        dy = 1
    if file_part.startswith("wind_x"):
        dx = 1
        layers = 1
    if file_part.startswith("wind_y"):
        dy = 1
        layers = 1
    if file_part.startswith("av.h"):
        pass
    if file_part.startswith("av.u"):
        dx = 1
    if file_part.startswith("av.v"):
        dy = 1
    if file_part.startswith("av.eta"):
        layers = 1
    if file_part.startswith("debug.dhdt"):
        pass
    if file_part.startswith("debug.dudt"):
        dx = 1
    if file_part.startswith("debug.dvdt"):
        dy = 1
    with fortran_file(name, 'r') as f:
        return f.read_reals(dtype=np.float64) \
                    .reshape(layers, ny+dy, nx+dx).transpose()

### General input construction helpers

def tracer_point_variable(grid, field_layers, *funcs):
    """Input generator for a variable at the tracer location of the grid. If passed a function, then that function can depend only on `X` and `Y`."""
    X,Y = np.meshgrid(grid.x, grid.y)
    T_variable = np.ones((field_layers, grid.ny, grid.nx))

    assert field_layers == len(funcs)

    for i, f in enumerate(funcs):
        if isinstance(f, (int, long, float)):
            T_variable[i,:,:] = f
        else:
            T_variable[i,:,:] = f(X, Y)
    return T_variable

def u_point_variable(grid, field_layers, *funcs):
    """Input generator for a variable at the u location of the grid. If passed a function, then that function can depend only on `X` and `Y`."""
    X,Y = np.meshgrid(grid.xp1, grid.y)
    u_variable = np.ones((field_layers, grid.ny, grid.nx+1))

    assert field_layers == len(funcs)

    for i, f in enumerate(funcs):
        if isinstance(f, (int, long, float)):
            u_variable[i,:,:] = f
        else:
            u_variable[i,:,:] = f(X, Y)
    return u_variable

def v_point_variable(grid, field_layers, *funcs):
    """Input generator for a variable at the v location of the grid. If passed a function, then that function can depend only on `X` and `Y`."""
    X,Y = np.meshgrid(grid.x, grid.yp1)
    v_variable = np.ones((field_layers, grid.ny+1, grid.nx))

    assert field_layers == len(funcs)

    for i, f in enumerate(funcs):
        if isinstance(f, (int, long, float)):
            v_variable[i,:,:] = f
        else:
            v_variable[i,:,:] = f(X, Y)
    return v_variable

def time_series_variable(nTimeSteps, dt, func):
    '''Input generator for a time series variable. If passed a function, then that function can depend on the number of timesteps, `nTimeSteps`, and the timestep, `dt`.'''

    ts_variable = np.zeros((nTimeSteps))

    # number of elements in `func` list should always be one
    assert len(func) == 1

    for i, f in enumerate(func):
        if isinstance(f, (int, long, float)):
            ts_variable[:] = np.ones(nTimeSteps) * f
        else:
            ts_variable[:] = f(nTimeSteps, dt)
    return ts_variable

### Specific construction helpers

def f_plane_f_u(grid, field_layers, coeff):
    """Define an f-plane approximation to the Coriolis force (u location)."""
    assert field_layers == 1
    return np.ones((grid.nx+1, grid.ny), dtype=np.float64) * coeff

def f_plane_f_v(grid, field_layers, coeff):
    """Define an f-plane approximation to the Coriolis force (v location)."""
    assert field_layers == 1
    return np.ones((grid.nx, grid.ny+1), dtype=np.float64) * coeff

def beta_plane_f_u(grid, field_layers, f0, beta):
    """Define a beta-plane approximation to the Coriolis force (u location)."""
    assert field_layers == 1
    _, Y = np.meshgrid(grid.xp1, grid.y)
    fu = f0 + Y*beta
    return fu

def beta_plane_f_v(grid, field_layers, f0, beta):
    """Define a beta-plane approximation to the Coriolis force (v location)."""
    assert field_layers == 1
    _, Y = np.meshgrid(grid.x, grid.yp1)
    fv = f0 + Y*beta
    return fv

def rectangular_pool(grid, field_layers):
    """The wet mask file for a maximal rectangular pool."""
    assert field_layers == 1
    nx = grid.nx; ny = grid.ny
    wetmask = np.ones((nx, ny), dtype=np.float64)
    wetmask[ 0, :] = 0
    wetmask[-1, :] = 0
    wetmask[ :, 0] = 0
    wetmask[ :,-1] = 0
    return wetmask

specifier_rx = re.compile(r':(.*):(.*)')

ok_generators = {
    'tracer_point_variable': tracer_point_variable,
    'u_point_variable': u_point_variable,
    'v_point_variable': v_point_variable,
    'time_series_variable': time_series_variable,
    'beta_plane_f_u': beta_plane_f_u,
    'beta_plane_f_v': beta_plane_f_v,
    'f_plane_f_u': f_plane_f_u,
    'f_plane_f_v': f_plane_f_v,
    'rectangular_pool': rectangular_pool,

}

def interpret_data_specifier(string):
    m = re.match(specifier_rx, string)
    if m:
        name = m.group(1)
        arg_str = m.group(2)
        if len(arg_str) > 0:
            args = [float(a) for a in arg_str.split(',')]
        else:
            args = []
        return (ok_generators[name], args)
    else:
        return None

def interpret_requested_data(requested_data, shape, config):
    """Interpret a flexible input data specification.

    The requested_data can be one of

    - TODO A string giving the path to a NetCDF file, whose content
      will be interpolated to match the desired grid specification;

    - A string giving the path to a raw Fortran array file, whose
      content will be used as-is;

    - TODO A numpy array in memory, whose content will be used as-is,
      or TODO interpolated; or

    - A string specifying auto-generation of the required data, in this format:
      :<generator_func_name>:arg1,arg2,...argn

    - Python objects specifying auto-generation of the required data.
      In this case, `interpret_requested_data` will construct the
      appropriate `Grid` instance and pass it, together with the
      `requested_data`, to an appropriate meta-generator for the array
      shape of the needful datum (determined by the `shape` argument).
      The exact API varies with the meta-generator, but they typically
      interpret numbers as that constant and functions as an analytic
      definition of the field, which is evaluated on appropriate numpy
      arrays to produce the needed numerical values.
    """
    grid = Grid(config.getint("grid", "nx"), config.getint("grid", "ny"),
                config.getint("grid", "layers"),
                config.getfloat("grid", "dx"), config.getfloat("grid", "dy"))
    field_layers = find_field_layers(shape, grid)

    if isinstance(requested_data, basestring):
        candidate = interpret_data_specifier(requested_data)
        if candidate is not None:
            (func, args) = candidate
            return func(grid, field_layers, *args)
        else:
            # Assume Fortran file name
            with fortran_file(requested_data, 'r') as f:
                return f.read_reals(dtype=np.float64)
    else:
        if shape == "2dT" or shape == "3dT":
            return tracer_point_variable(grid, field_layers, *requested_data)
        if shape == "2dU" or shape == "3dU":
            return u_point_variable(grid, field_layers, *requested_data)
        if shape == "2dV" or shape == "3dV":
            return v_point_variable(grid, field_layers, *requested_data)
        if shape == "time":
            nTimeSteps = config.getint("numerics", "nTimeSteps")
            dt = config.getfloat("numerics", "dt")
            return time_series_variable(nTimeSteps, dt, requested_data)
        else:
            raise Exception("TODO implement custom generation for other input shapes")

def find_field_layers(shape, grid):
    """Given a particular field shape, return how many layers it should have."""

    if shape == "2dT":
        return 1
    if shape == "3dT":
        return grid.layers
    if shape == "2dU":
        return 1
    if shape == "3dU":
        return grid.layers
    if shape == "2dV":
        return 1
    if shape == "3dV":
        return grid.layers<commit_msg>new line at end of file<commit_after>"""!
The main file with the class definitions

Core
==============

This file contains all of the classes for the module.
"""

from contextlib import contextmanager
import os.path as p
import re

import numpy as np
from scipy.io import FortranFile

class Grid(object):
    """Make a grid object containing all of the axes.

        :param int nx: Number of grid points in the x direction
        :param int ny: Number of grid points in the y direction
        :param int layers: Number of active layers
        :param float dx: Grid size in x direction in metres
        :param float dy: Grid size in y direction in metres
        :param float x0: x value at lower left corner of domain
        :param float y0: y value at lower left corner of domain

        The initialisation call returns an object containing each of the input parameters as well as the following arrays:

        - x: x locations of the tracer points
        - y: y locations of the tracer points
        - xp1: x locations of the u velocity points and vorticity points
        - yp1: y locations of the v velocity points and vorticity points
        """

    def __init__(self,nx,ny,layers,dx,dy,x0=0,y0=0):
        """Instantiate a grid object for Aronnax."""

        # axes for vorticity points
        self.xp1 = np.linspace(x0,nx*dx+x0,nx+1)
        self.yp1 = np.linspace(y0,ny*dy+y0,ny+1)

        # Axes for tracer points.
        self.x = (self.xp1[1:] + self.xp1[:-1])/2.
        self.y = (self.yp1[1:] + self.yp1[:-1])/2.

        # Size
        self.nx = nx
        self.ny = ny
        self.layers = layers

        # Grid spacing
        self.dx = dx
        self.dy = dy

@contextmanager
def fortran_file(*args, **kwargs):
    f = FortranFile(*args, **kwargs)
    try:
        yield f
    finally:
        f.close()

def interpret_raw_file(name, nx, ny, layers):
    """Read an output file dumped by the Aronnax core.

    Each such file contains one array, whose size depends on what,
    exactly, is in it, and on the resolution of the simulation.
    Hence, the parameters nx, ny, and layers, as well as the file
    naming convetion, suffice to interpret the content (assuming it
    was generated on the same system)."""
    # Note: This depends on inspection of the output writing code in
    # the Aronnax core, to align array sizes and dimensions.  In
    # particular, Fortran arrays are indexed in decreasing order of
    # rate of change as one traverses the elements sequentially,
    # whereas Python (and all other programming languages I am aware
    # of) indexes in increasing order.
    file_part = p.basename(name)
    dx = 0; dy = 0;
    if file_part.startswith("snap.BP"):
        pass
    if file_part.startswith("snap.eta"):
        layers = 1
    if file_part.startswith("snap.eta_new"):
        layers = 1
    if file_part.startswith("snap.eta_star"):
        layers = 1
    if file_part.startswith("snap.h"):
        pass
    if file_part.startswith("snap.u"):
        dx = 1
    if file_part.startswith("snap.ub"):
        dx = 1
        layers = 1
    if file_part.startswith("snap.v"):
        dy = 1
    if file_part.startswith("snap.vb"):
        dy = 1
        layers = 1
    if file_part.startswith("snap.zeta"):
        dx = 1
        dy = 1
    if file_part.startswith("wind_x"):
        dx = 1
        layers = 1
    if file_part.startswith("wind_y"):
        dy = 1
        layers = 1
    if file_part.startswith("av.h"):
        pass
    if file_part.startswith("av.u"):
        dx = 1
    if file_part.startswith("av.v"):
        dy = 1
    if file_part.startswith("av.eta"):
        layers = 1
    if file_part.startswith("debug.dhdt"):
        pass
    if file_part.startswith("debug.dudt"):
        dx = 1
    if file_part.startswith("debug.dvdt"):
        dy = 1
    with fortran_file(name, 'r') as f:
        return f.read_reals(dtype=np.float64) \
                    .reshape(layers, ny+dy, nx+dx).transpose()

### General input construction helpers

def tracer_point_variable(grid, field_layers, *funcs):
    """Input generator for a variable at the tracer location of the grid. If passed a function, then that function can depend only on `X` and `Y`."""
    X,Y = np.meshgrid(grid.x, grid.y)
    T_variable = np.ones((field_layers, grid.ny, grid.nx))

    assert field_layers == len(funcs)

    for i, f in enumerate(funcs):
        if isinstance(f, (int, long, float)):
            T_variable[i,:,:] = f
        else:
            T_variable[i,:,:] = f(X, Y)
    return T_variable

def u_point_variable(grid, field_layers, *funcs):
    """Input generator for a variable at the u location of the grid. If passed a function, then that function can depend only on `X` and `Y`."""
    X,Y = np.meshgrid(grid.xp1, grid.y)
    u_variable = np.ones((field_layers, grid.ny, grid.nx+1))

    assert field_layers == len(funcs)

    for i, f in enumerate(funcs):
        if isinstance(f, (int, long, float)):
            u_variable[i,:,:] = f
        else:
            u_variable[i,:,:] = f(X, Y)
    return u_variable

def v_point_variable(grid, field_layers, *funcs):
    """Input generator for a variable at the v location of the grid. If passed a function, then that function can depend only on `X` and `Y`."""
    X,Y = np.meshgrid(grid.x, grid.yp1)
    v_variable = np.ones((field_layers, grid.ny+1, grid.nx))

    assert field_layers == len(funcs)

    for i, f in enumerate(funcs):
        if isinstance(f, (int, long, float)):
            v_variable[i,:,:] = f
        else:
            v_variable[i,:,:] = f(X, Y)
    return v_variable

def time_series_variable(nTimeSteps, dt, func):
    '''Input generator for a time series variable. If passed a function, then that function can depend on the number of timesteps, `nTimeSteps`, and the timestep, `dt`.'''

    ts_variable = np.zeros((nTimeSteps))

    # number of elements in `func` list should always be one
    assert len(func) == 1

    for i, f in enumerate(func):
        if isinstance(f, (int, long, float)):
            ts_variable[:] = np.ones(nTimeSteps) * f
        else:
            ts_variable[:] = f(nTimeSteps, dt)
    return ts_variable

### Specific construction helpers

def f_plane_f_u(grid, field_layers, coeff):
    """Define an f-plane approximation to the Coriolis force (u location)."""
    assert field_layers == 1
    return np.ones((grid.nx+1, grid.ny), dtype=np.float64) * coeff

def f_plane_f_v(grid, field_layers, coeff):
    """Define an f-plane approximation to the Coriolis force (v location)."""
    assert field_layers == 1
    return np.ones((grid.nx, grid.ny+1), dtype=np.float64) * coeff

def beta_plane_f_u(grid, field_layers, f0, beta):
    """Define a beta-plane approximation to the Coriolis force (u location)."""
    assert field_layers == 1
    _, Y = np.meshgrid(grid.xp1, grid.y)
    fu = f0 + Y*beta
    return fu

def beta_plane_f_v(grid, field_layers, f0, beta):
    """Define a beta-plane approximation to the Coriolis force (v location)."""
    assert field_layers == 1
    _, Y = np.meshgrid(grid.x, grid.yp1)
    fv = f0 + Y*beta
    return fv

def rectangular_pool(grid, field_layers):
    """The wet mask file for a maximal rectangular pool."""
    assert field_layers == 1
    nx = grid.nx; ny = grid.ny
    wetmask = np.ones((nx, ny), dtype=np.float64)
    wetmask[ 0, :] = 0
    wetmask[-1, :] = 0
    wetmask[ :, 0] = 0
    wetmask[ :,-1] = 0
    return wetmask

specifier_rx = re.compile(r':(.*):(.*)')

ok_generators = {
    'tracer_point_variable': tracer_point_variable,
    'u_point_variable': u_point_variable,
    'v_point_variable': v_point_variable,
    'time_series_variable': time_series_variable,
    'beta_plane_f_u': beta_plane_f_u,
    'beta_plane_f_v': beta_plane_f_v,
    'f_plane_f_u': f_plane_f_u,
    'f_plane_f_v': f_plane_f_v,
    'rectangular_pool': rectangular_pool,

}

def interpret_data_specifier(string):
    m = re.match(specifier_rx, string)
    if m:
        name = m.group(1)
        arg_str = m.group(2)
        if len(arg_str) > 0:
            args = [float(a) for a in arg_str.split(',')]
        else:
            args = []
        return (ok_generators[name], args)
    else:
        return None

def interpret_requested_data(requested_data, shape, config):
    """Interpret a flexible input data specification.

    The requested_data can be one of

    - TODO A string giving the path to a NetCDF file, whose content
      will be interpolated to match the desired grid specification;

    - A string giving the path to a raw Fortran array file, whose
      content will be used as-is;

    - TODO A numpy array in memory, whose content will be used as-is,
      or TODO interpolated; or

    - A string specifying auto-generation of the required data, in this format:
      :<generator_func_name>:arg1,arg2,...argn

    - Python objects specifying auto-generation of the required data.
      In this case, `interpret_requested_data` will construct the
      appropriate `Grid` instance and pass it, together with the
      `requested_data`, to an appropriate meta-generator for the array
      shape of the needful datum (determined by the `shape` argument).
      The exact API varies with the meta-generator, but they typically
      interpret numbers as that constant and functions as an analytic
      definition of the field, which is evaluated on appropriate numpy
      arrays to produce the needed numerical values.
    """
    grid = Grid(config.getint("grid", "nx"), config.getint("grid", "ny"),
                config.getint("grid", "layers"),
                config.getfloat("grid", "dx"), config.getfloat("grid", "dy"))
    field_layers = find_field_layers(shape, grid)

    if isinstance(requested_data, basestring):
        candidate = interpret_data_specifier(requested_data)
        if candidate is not None:
            (func, args) = candidate
            return func(grid, field_layers, *args)
        else:
            # Assume Fortran file name
            with fortran_file(requested_data, 'r') as f:
                return f.read_reals(dtype=np.float64)
    else:
        if shape == "2dT" or shape == "3dT":
            return tracer_point_variable(grid, field_layers, *requested_data)
        if shape == "2dU" or shape == "3dU":
            return u_point_variable(grid, field_layers, *requested_data)
        if shape == "2dV" or shape == "3dV":
            return v_point_variable(grid, field_layers, *requested_data)
        if shape == "time":
            nTimeSteps = config.getint("numerics", "nTimeSteps")
            dt = config.getfloat("numerics", "dt")
            return time_series_variable(nTimeSteps, dt, requested_data)
        else:
            raise Exception("TODO implement custom generation for other input shapes")

def find_field_layers(shape, grid):
    """Given a particular field shape, return how many layers it should have."""

    if shape == "2dT":
        return 1
    if shape == "3dT":
        return grid.layers
    if shape == "2dU":
        return 1
    if shape == "3dU":
        return grid.layers
    if shape == "2dV":
        return 1
    if shape == "3dV":
        return grid.layers
<|endoftext|>


<commit_before>"""
picture.py
Author: Mary Feyrer
Credit: colorpicker.com

Assignment:

Use the ggame library to "paint" a graphical picture of something (e.g. a house, a face or landscape).

Use at least:
1. Three different Color objects.
2. Ten different Sprite objects.
3. One (or more) RectangleAsset objects.
4. One (or more) CircleAsset objects.
5. One (or more) EllipseAsset objects.
6. One (or more) PolygonAsset objects.

See:
https://github.com/HHS-IntroProgramming/Standards-and-Syllabus/wiki/Displaying-Graphics
for general information on how to use ggame.

See:
http://brythonserver.github.io/ggame/
for detailed information on ggame.

"""
from ggame import App, Color, LineStyle, Sprite, RectangleAsset, CircleAsset, EllipseAsset, PolygonAsset

# add your code here \/  \/  \/
red = Color(0xff0000, 1.0)
green = Color(0x00ff00, 1.0)
blue = Color(0x0000ff, 1.0)
black = Color(0x000000, 1.0)
yellow = Color(0xF2EC41, 1.0)
darkgreen = Color(0x278F28, 1.0)
brown = Color(0x693C0E, 1.0)
pink = Color(0xF573DD, 1.0)
white = Color(0xffffff, 0.9)
lightblue = Color(0x7EE7F2, 1.0)
thinline = LineStyle(1, black)

sky = RectangleAsset(300, 250, thinline, lightblue)
ground = RectangleAsset(300, 50, thinline, green)
sun = CircleAsset(20, thinline, yellow)
trunk = RectangleAsset(20, 40, thinline, brown)
tree = PolygonAsset([(180,10),(140,90),(220,90)], thinline, darkgreen)
tree2 = PolygonAsset([(180,10),(135,90),(225,90)], thinline, darkgreen)
stem = RectangleAsset(7,20, thinline, green)
flower = CircleAsset(6, thinline, pink)
cloud = EllipseAsset(10, 15, thinline, white)

Sprite(sky)
Sprite(ground, (0, 200))
Sprite(sun, (30,30))
Sprite(trunk, (170, 170))
Sprite(tree2, (0, 90))
Sprite(tree, (0, 45))
Sprite(stem, (62, 186))
Sprite(flower, (60, 182))
Sprite(flower, (57, 172))
Sprite(flower, (70, 182))
Sprite(flower, (74, 172))
Sprite(flower, (65, 165))
Sprite(cloud, (200, 35))

# add your code here /\  /\  /\

myapp = App()
myapp.run()
<commit_msg>Updated from Brython Server: 1/26/2016 2:25:13 PM<commit_after>"""
picture.py
Author: Mary Feyrer
Credit: colorpicker.com

Assignment:

Use the ggame library to "paint" a graphical picture of something (e.g. a house, a face or landscape).

Use at least:
1. Three different Color objects.
2. Ten different Sprite objects.
3. One (or more) RectangleAsset objects.
4. One (or more) CircleAsset objects.
5. One (or more) EllipseAsset objects.
6. One (or more) PolygonAsset objects.

See:
https://github.com/HHS-IntroProgramming/Standards-and-Syllabus/wiki/Displaying-Graphics
for general information on how to use ggame.

See:
http://brythonserver.github.io/ggame/
for detailed information on ggame.

"""
from ggame import App, Color, LineStyle, Sprite, RectangleAsset, CircleAsset, EllipseAsset, PolygonAsset

# add your code here \/  \/  \/
red = Color(0xff0000, 1.0)
green = Color(0x00ff00, 1.0)
blue = Color(0x0000ff, 1.0)
black = Color(0x000000, 1.0)
yellow = Color(0xF2EC41, 1.0)
darkgreen = Color(0x278F28, 1.0)
brown = Color(0x693C0E, 1.0)
pink = Color(0xF573DD, 1.0)
white = Color(0xffffff, 0.9)
lightblue = Color(0x7EE7F2, 1.0)
thinline = LineStyle(1, black)

sky = RectangleAsset(300, 250, thinline, lightblue)
ground = RectangleAsset(300, 50, thinline, green)
sun = CircleAsset(20, thinline, yellow)
trunk = RectangleAsset(20, 40, thinline, brown)
tree = PolygonAsset([(180,10),(140,90),(220,90)], thinline, darkgreen)
tree2 = PolygonAsset([(180,10),(135,90),(225,90)], thinline, darkgreen)
stem = RectangleAsset(7,20, thinline, green)
flower = CircleAsset(6, thinline, pink)
cloud = EllipseAsset(40, 10, thinline, white)

Sprite(sky)
Sprite(ground, (0, 200))
Sprite(sun, (30,30))
Sprite(trunk, (170, 170))
Sprite(tree2, (0, 90))
Sprite(tree, (0, 45))
Sprite(stem, (62, 186))
Sprite(flower, (60, 182))
Sprite(flower, (57, 172))
Sprite(flower, (70, 182))
Sprite(flower, (74, 172))
Sprite(flower, (65, 165))
Sprite(cloud, (200, 35))

# add your code here /\  /\  /\

myapp = App()
myapp.run()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#######################################################################
# Name: peg.py
# Purpose: Implementing PEG language
# Author: Igor R. Dejanovic <igor DOT dejanovic AT gmail DOT com>
# Copyright: (c) 2009 Igor R. Dejanovic <igor DOT dejanovic AT gmail DOT com>
# License: MIT License
#######################################################################

from __future__ import print_function
from arpeggio import *
from arpeggio import RegExMatch as _

__all__ = ['ParserPEG']

# PEG Lexical rules
def LEFT_ARROW():       return "<-"
def SLASH():            return "/"
def STAR():             return "*"
def QUESTION():         return "?"
def PLUS():             return "+"
def AND():              return "&"
def NOT():              return "!"
def OPEN():             return "("
def CLOSE():            return ")"
def regex():            return "r'", _(r"(\\\'|[^\'])*"),"'"
def rule_name():        return _(r"[a-zA-Z_]([a-zA-Z_]|[0-9])*")
def rule_crossref():    return rule_name
#def literal():          return [_(r"\'(\\\'|[^\'])*\'"),_(r'"[^"]*"')]
def str_match():        return _(r'(\'(\\\'|[^\'])*\')|("[^"]*")')
def comment():          return "//", _(".*\n")

# PEG syntax rules
def grammar():          return OneOrMore(rule), EOF
def rule():             return rule_name, LEFT_ARROW, ordered_choice, ";"
def ordered_choice():   return sequence, ZeroOrMore(SLASH, sequence)
def sequence():         return OneOrMore(prefix)
def prefix():           return Optional([AND,NOT]), sufix
def sufix():            return expression, Optional([QUESTION, STAR, PLUS])
def expression():       return [regex, rule_crossref,
                                (OPEN, ordered_choice, CLOSE),
                                str_match]

# ------------------------------------------------------------------
# PEG Semantic Actions

class PEGSemanticAction(SemanticAction):
    def _resolve(self, parser, rule_name):
        if rule_name in parser.peg_rules:
            if parser.debug:
                print("Resolving reference {}".format(rule_name))
            return parser.peg_rules[rule_name]
        else:
            raise SemanticError("Rule \"{}\" does not exists."
                                .format(rule_name))

    def second_pass(self, parser, node):
        '''
        Resolving cross-references in second pass.
        '''
        if isinstance(node, CrossRef):
            return self._resolve(parser, node.rule_name)
        elif isinstance(node, ParsingExpression):
            for i, n in enumerate(node.nodes):
                if isinstance(n, CrossRef):
                    node.nodes[i] = self._resolve(parser, n.rule_name)
            return node
        else:
            raise SemanticError("Invalid type '{}'({}) after first pass."
                                .format(type(node), str(node)))

class SemGrammar(SemanticAction):
    def first_pass(self, parser, node, children):
        print(parser.peg_rules)
        return parser.peg_rules[parser.root_rule_name]

class SemRule(PEGSemanticAction):
    def first_pass(self, parser, node, children):
        rule_name = children[0]
        if len(children) > 2:
            retval = Sequence(nodes=children[1:])
        else:
            retval = children[1]
        retval.rule = rule_name
        retval.root = True

        if not hasattr(parser, "peg_rules"):
            parser.peg_rules = {}   # Used for linking phase
            parser.peg_rules["EndOfFile"] = EndOfFile()

        # Keep a map of parser rules for cross reference
        # resolving.
        parser.peg_rules[rule_name] = retval

        return retval

class SemSequence(PEGSemanticAction):
    def first_pass(self, parser, node, children):
        if len(children) > 1:
            return Sequence(nodes=children)
        else:
            # If only one child rule exists reduce.
            return children[0]

class SemOrderedChoice(PEGSemanticAction):
    def first_pass(self, parser, node, children):
        if len(children) > 1:
            retval = OrderedChoice(nodes=children)
        else:
            # If only one child rule exists reduce.
            retval = children[0]
        return retval

class SemPrefix(PEGSemanticAction):
    def first_pass(self, parser, node, children):
        if len(children) == 2:
            if children[0] == NOT():
                retval = Not()
            else:
                retval = And()
            if type(children[1]) is list:
                retval.nodes = children[1]
            else:
                retval.nodes = [children[1]]
        else:
            # If there is no optional prefix reduce.
            retval = children[0]

        return retval

class SemSufix(PEGSemanticAction):
    def first_pass(self, parser, node, children):
        if len(children) == 2:
            if children[1] == STAR():
                retval = ZeroOrMore(children[0])
            elif children[1] == QUESTION():
                retval = Optional(children[0])
            else:
                retval = OneOrMore(children[0])
            if type(children[0]) is list:
                retval.nodes = children[0]
            else:
                retval.nodes = [children[0]]
        else:
            retval = children[0]

        return retval

class SemExpression(PEGSemanticAction):
    def first_pass(self, parser, node, children):
        return children[0]

class SemRuleCrossRef(SemanticAction):
    def first_pass(self, parser, node, children):
        return CrossRef(node.value)

class SemRegEx(SemanticAction):
    def first_pass(self, parser, node, children):
        return RegExMatch(children[0])

class SemStrMatch(SemanticAction):
    def first_pass(self, parser, node, children):
        match_str = node.value[1:-1]
        match_str = match_str.replace("\\'", "'")
        match_str = match_str.replace("\\\\", "\\")
        return StrMatch(match_str)

grammar.sem = SemGrammar()
rule.sem = SemRule()
ordered_choice.sem = SemOrderedChoice()
sequence.sem = SemSequence()
prefix.sem = SemPrefix()
sufix.sem = SemSufix()
expression.sem = SemExpression()
rule_crossref.sem = SemRuleCrossRef()
regex.sem = SemRegEx()
str_match.sem = SemStrMatch()

class ParserPEG(Parser):
    def __init__(self, language_def, root_rule_name, comment_rule_name=None,
                 *args, **kwargs):
        super(ParserPEG, self).__init__(*args, **kwargs)
        self.root_rule_name = root_rule_name

        # PEG Abstract Syntax Graph
        self.parser_model = self._from_peg(language_def)

        # Comments should be optional and there can be more of them
        if self.comments_model: # and not isinstance(self.comments_model, ZeroOrMore):
            self.comments_model.root = True
            self.comments_model.rule = comment_rule_name

    def _parse(self):
        return self.parser_model.parse(self)

    def _from_peg(self, language_def):
        parser = ParserPython(grammar, comment, reduce_tree=False, debug=True)
        parser.root_rule_name = self.root_rule_name
        parser.parse(language_def)

        return parser.getASG()
<commit_msg>Removing print and disabling debuging in PEG parser construction<commit_after># -*- coding: utf-8 -*-
#######################################################################
# Name: peg.py
# Purpose: Implementing PEG language
# Author: Igor R. Dejanovic <igor DOT dejanovic AT gmail DOT com>
# Copyright: (c) 2009 Igor R. Dejanovic <igor DOT dejanovic AT gmail DOT com>
# License: MIT License
#######################################################################

from __future__ import print_function
from arpeggio import *
from arpeggio import RegExMatch as _

__all__ = ['ParserPEG']

# PEG Lexical rules
def LEFT_ARROW():       return "<-"
def SLASH():            return "/"
def STAR():             return "*"
def QUESTION():         return "?"
def PLUS():             return "+"
def AND():              return "&"
def NOT():              return "!"
def OPEN():             return "("
def CLOSE():            return ")"
def regex():            return "r'", _(r"(\\\'|[^\'])*"),"'"
def rule_name():        return _(r"[a-zA-Z_]([a-zA-Z_]|[0-9])*")
def rule_crossref():    return rule_name
#def literal():          return [_(r"\'(\\\'|[^\'])*\'"),_(r'"[^"]*"')]
def str_match():        return _(r'(\'(\\\'|[^\'])*\')|("[^"]*")')
def comment():          return "//", _(".*\n")

# PEG syntax rules
def grammar():          return OneOrMore(rule), EOF
def rule():             return rule_name, LEFT_ARROW, ordered_choice, ";"
def ordered_choice():   return sequence, ZeroOrMore(SLASH, sequence)
def sequence():         return OneOrMore(prefix)
def prefix():           return Optional([AND,NOT]), sufix
def sufix():            return expression, Optional([QUESTION, STAR, PLUS])
def expression():       return [regex, rule_crossref,
                                (OPEN, ordered_choice, CLOSE),
                                str_match]

# ------------------------------------------------------------------
# PEG Semantic Actions

class PEGSemanticAction(SemanticAction):
    def _resolve(self, parser, rule_name):
        if rule_name in parser.peg_rules:
            if parser.debug:
                print("Resolving reference {}".format(rule_name))
            return parser.peg_rules[rule_name]
        else:
            raise SemanticError("Rule \"{}\" does not exists."
                                .format(rule_name))

    def second_pass(self, parser, node):
        '''
        Resolving cross-references in second pass.
        '''
        if isinstance(node, CrossRef):
            return self._resolve(parser, node.rule_name)
        elif isinstance(node, ParsingExpression):
            for i, n in enumerate(node.nodes):
                if isinstance(n, CrossRef):
                    node.nodes[i] = self._resolve(parser, n.rule_name)
            return node
        else:
            raise SemanticError("Invalid type '{}'({}) after first pass."
                                .format(type(node), str(node)))

class SemGrammar(SemanticAction):
    def first_pass(self, parser, node, children):
        return parser.peg_rules[parser.root_rule_name]

class SemRule(PEGSemanticAction):
    def first_pass(self, parser, node, children):
        rule_name = children[0]
        if len(children) > 2:
            retval = Sequence(nodes=children[1:])
        else:
            retval = children[1]
        retval.rule = rule_name
        retval.root = True

        if not hasattr(parser, "peg_rules"):
            parser.peg_rules = {}   # Used for linking phase
            parser.peg_rules["EndOfFile"] = EndOfFile()

        # Keep a map of parser rules for cross reference
        # resolving.
        parser.peg_rules[rule_name] = retval

        return retval

class SemSequence(PEGSemanticAction):
    def first_pass(self, parser, node, children):
        if len(children) > 1:
            return Sequence(nodes=children)
        else:
            # If only one child rule exists reduce.
            return children[0]

class SemOrderedChoice(PEGSemanticAction):
    def first_pass(self, parser, node, children):
        if len(children) > 1:
            retval = OrderedChoice(nodes=children)
        else:
            # If only one child rule exists reduce.
            retval = children[0]
        return retval

class SemPrefix(PEGSemanticAction):
    def first_pass(self, parser, node, children):
        if len(children) == 2:
            if children[0] == NOT():
                retval = Not()
            else:
                retval = And()
            if type(children[1]) is list:
                retval.nodes = children[1]
            else:
                retval.nodes = [children[1]]
        else:
            # If there is no optional prefix reduce.
            retval = children[0]

        return retval

class SemSufix(PEGSemanticAction):
    def first_pass(self, parser, node, children):
        if len(children) == 2:
            if children[1] == STAR():
                retval = ZeroOrMore(children[0])
            elif children[1] == QUESTION():
                retval = Optional(children[0])
            else:
                retval = OneOrMore(children[0])
            if type(children[0]) is list:
                retval.nodes = children[0]
            else:
                retval.nodes = [children[0]]
        else:
            retval = children[0]

        return retval

class SemExpression(PEGSemanticAction):
    def first_pass(self, parser, node, children):
        return children[0]

class SemRuleCrossRef(SemanticAction):
    def first_pass(self, parser, node, children):
        return CrossRef(node.value)

class SemRegEx(SemanticAction):
    def first_pass(self, parser, node, children):
        return RegExMatch(children[0])

class SemStrMatch(SemanticAction):
    def first_pass(self, parser, node, children):
        match_str = node.value[1:-1]
        match_str = match_str.replace("\\'", "'")
        match_str = match_str.replace("\\\\", "\\")
        return StrMatch(match_str)

grammar.sem = SemGrammar()
rule.sem = SemRule()
ordered_choice.sem = SemOrderedChoice()
sequence.sem = SemSequence()
prefix.sem = SemPrefix()
sufix.sem = SemSufix()
expression.sem = SemExpression()
rule_crossref.sem = SemRuleCrossRef()
regex.sem = SemRegEx()
str_match.sem = SemStrMatch()

class ParserPEG(Parser):
    def __init__(self, language_def, root_rule_name, comment_rule_name=None,
                 *args, **kwargs):
        super(ParserPEG, self).__init__(*args, **kwargs)
        self.root_rule_name = root_rule_name

        # PEG Abstract Syntax Graph
        self.parser_model = self._from_peg(language_def)

        # Comments should be optional and there can be more of them
        if self.comments_model: # and not isinstance(self.comments_model, ZeroOrMore):
            self.comments_model.root = True
            self.comments_model.rule = comment_rule_name

    def _parse(self):
        return self.parser_model.parse(self)

    def _from_peg(self, language_def):
        parser = ParserPython(grammar, comment, reduce_tree=False)
        parser.root_rule_name = self.root_rule_name
        parser.parse(language_def)

        return parser.getASG()
<|endoftext|>


<commit_before>import re

from livestreamer.plugin import Plugin
from livestreamer.plugin.api import http, validate
from livestreamer.stream import RTMPStream

CHANNELS_API_URL = "http://api.gaminglive.tv/channels/{0}"
QUALITY_WEIGHTS = {
    "live": 3,
    "medium": 2,
    "low": 1,
}

_url_re = re.compile("""
    http(s)?://(staging|alpha)\.gaminglive\.tv
    /\#/channels/(?P<channel>[^/]+)
""", re.VERBOSE)
_quality_re = re.compile("[^/]+-(?P<quality>[^/]+)")

_channel_schema = validate.Schema(
    {
        validate.optional("state"): {
            "stream": {
                "qualities": [validate.text],
                "rootUrl": validate.url(scheme="rtmp")
            }
        }
    },
    validate.get("state")
)

class GamingLive(Plugin):
    @classmethod
    def can_handle_url(self, url):
        return _url_re.match(url)

    @classmethod
    def stream_weight(cls, key):
        weight = QUALITY_WEIGHTS.get(key)
        if weight:
            return weight, "gaminglive"

        return Plugin.stream_weight(key)

    def _get_quality(self, label):
        match = _quality_re.match(label)
        if match:
            return match.group("quality")

        return "live"

    def _get_streams(self):
        match = _url_re.match(self.url)
        channel = match.group("channel")

        res = http.get(CHANNELS_API_URL.format(channel))
        json = http.json(res, schema=_channel_schema)
        if not json:
            return

        streams = {}
        for quality in json["stream"]["qualities"]:
            stream_name = self._get_quality(quality)
            stream = RTMPStream(self.session, {
                "rtmp": json["stream"]["rootUrl"],
                "playpath": quality,
                "pageUrl": self.url
            })
            streams[stream_name] = stream

        return streams

__plugin__ = GamingLive
<commit_msg>plugins.gaminglive: fix "No data returned from stream" issue<commit_after>import re

from livestreamer.plugin import Plugin
from livestreamer.plugin.api import http, validate
from livestreamer.stream import RTMPStream

SWF_URL = "http://alpha.gaminglive.tv/lib/flowplayer/flash/flowplayer.commercial-3.2.18.swf"
CHANNELS_API_URL = "http://api.gaminglive.tv/channels/{0}"
QUALITY_WEIGHTS = {
    "live": 3,
    "medium": 2,
    "low": 1,
}

_url_re = re.compile("""
    http(s)?://(staging|alpha)\.gaminglive\.tv
    /\#/channels/(?P<channel>[^/]+)
""", re.VERBOSE)
_quality_re = re.compile("[^/]+-(?P<quality>[^/]+)")

_channel_schema = validate.Schema(
    {
        validate.optional("state"): {
            "stream": {
                "qualities": [validate.text],
                "rootUrl": validate.url(scheme="rtmp")
            }
        }
    },
    validate.get("state")
)

class GamingLive(Plugin):
    @classmethod
    def can_handle_url(self, url):
        return _url_re.match(url)

    @classmethod
    def stream_weight(cls, key):
        weight = QUALITY_WEIGHTS.get(key)
        if weight:
            return weight, "gaminglive"

        return Plugin.stream_weight(key)

    def _get_quality(self, label):
        match = _quality_re.match(label)
        if match:
            return match.group("quality")

        return "live"

    def _get_streams(self):
        match = _url_re.match(self.url)
        channel = match.group("channel")

        res = http.get(CHANNELS_API_URL.format(channel))
        json = http.json(res, schema=_channel_schema)
        if not json:
            return

        streams = {}
        for quality in json["stream"]["qualities"]:
            stream_name = self._get_quality(quality)
            stream = RTMPStream(self.session, {
                "rtmp": json["stream"]["rootUrl"],
                "playpath": quality,
                "pageUrl": self.url,
                "swfVfy": SWF_URL,
                "live": True
            })
            streams[stream_name] = stream

        return streams

__plugin__ = GamingLive
<|endoftext|>


<commit_before>"""
picture.py
Author: <your name here>
Credit: <list sources used, if any>

Assignment:

Use the ggame library to "paint" a graphical picture of something (e.g. a house, a face or landscape).

Use at least:
1. Three different Color objects.
2. Ten different Sprite objects.
3. One (or more) RectangleAsset objects.
4. One (or more) CircleAsset objects.
5. One (or more) EllipseAsset objects.
6. One (or more) PolygonAsset objects.

See:
https://github.com/HHS-IntroProgramming/Standards-and-Syllabus/wiki/Displaying-Graphics
for general information on how to use ggame.

See:
http://brythonserver.github.io/ggame/
for detailed information on ggame.

"""
from ggame import App, Color, LineStyle, Sprite, RectangleAsset, CircleAsset, EllipseAsset, PolygonAsset

# add your code here \/  \/  \/
from ggame import App, Color, LineStyle, Sprite
from ggame import RectangleAsset, CircleAsset, EllipseAsset, PolygonAsset

red = Color(0xff0000, 1.0)
green = Color(0x00ff00, 1.0)
blue = Color(0x0000ff, 1.0)
black = Color(0x000000, 1.0)
white = Color(0xf8f8ff, 1.0)
pwhite = Color(0xfffafa,1.0)
thinline = LineStyle(1, black)
thinline1 = LineStyle(1, pwhite)

circle = CircleAsset(50, thinline, red)
Sprite(circle, (50, 50))

base = RectangleAsset(200, 200, thinline, blue)
Sprite(base, (900, 400))

roof = PolygonAsset([(0,0), (200,0), (100, -120)], thinline, black)
Sprite(roof, (900, 400))

window1 = RectangleAsset(50, 80, thinline, white)
Sprite(window1, (920, 430))

window2 = RectangleAsset(50, 80, thinline, white)
Sprite(window2, (1030, 430))

door = CircleAsset(50, thinline, green)
Sprite(door, (1000, 600))

door1 = RectangleAsset(200, 200, thinline1, white)
Sprite(door1, (899, 600))

floor = PolygonAsset([(0,0), (900,0), (900, 1), (0,1)], thinline, green)
Sprite(floor, (0, 599))
# add your code here /\  /\  /\

roof1 = PolygonAsset([(0,0), (66,0), (33, -56)], thinline1, pwhite)
Sprite(roof1, (965, 350))

myapp = App()
myapp.run()
<commit_msg>Updated from Brython Server: 1/27/2017 6:07:47 PM<commit_after>"""
picture.py
Author: <Brendan>
Credit: <Ethan Adner>

Assignment:

Use the ggame library to "paint" a graphical picture of something (e.g. a house, a face or landscape).

Use at least:
1. Three different Color objects.
2. Ten different Sprite objects.
3. One (or more) RectangleAsset objects.
4. One (or more) CircleAsset objects.
5. One (or more) EllipseAsset objects.
6. One (or more) PolygonAsset objects.

See:
https://github.com/HHS-IntroProgramming/Standards-and-Syllabus/wiki/Displaying-Graphics
for general information on how to use ggame.

See:
http://brythonserver.github.io/ggame/
for detailed information on ggame.

"""
from ggame import App, Color, LineStyle, Sprite, RectangleAsset, CircleAsset, EllipseAsset, PolygonAsset

# add your code here \/  \/  \/
from ggame import App, Color, LineStyle, Sprite
from ggame import RectangleAsset, CircleAsset, EllipseAsset, PolygonAsset

red = Color(0xff0000, 1.0)
green = Color(0x00ff00, 1.0)
blue = Color(0x0000ff, 1.0)
black = Color(0x000000, 1.0)
white = Color(0xf8f8ff, 1.0)
pwhite = Color(0xfffafa,1.0)
thinline = LineStyle(1, black)
thinline1 = LineStyle(1, pwhite)

circle = CircleAsset(50, thinline, red)
Sprite(circle, (50, 50))

base = RectangleAsset(200, 200, thinline, blue)
Sprite(base, (900, 400))

roof = PolygonAsset([(0,0), (200,0), (100, -120)], thinline, black)
Sprite(roof, (900, 400))

window1 = RectangleAsset(50, 80, thinline, white)
Sprite(window1, (920, 430))

window2 = RectangleAsset(50, 80, thinline, white)
Sprite(window2, (1030, 430))

door = CircleAsset(50, thinline, green)
Sprite(door, (1000, 600))

door1 = RectangleAsset(200, 200, thinline1, white)
Sprite(door1, (899, 600))

floor = PolygonAsset([(0,0), (900,0), (900, 1), (0,1)], thinline, green)
Sprite(floor, (0, 599))
# add your code here /\  /\  /\

roof1 = PolygonAsset([(0,0), (66,0), (33, -56)], thinline1, pwhite)
Sprite(roof1, (965, 350))

myapp = App()
myapp.run()
<|endoftext|>


<commit_before>"""
picture.py
Author: Mary Feyrer
Credit: colorpicker.com

Assignment:

Use the ggame library to "paint" a graphical picture of something (e.g. a house, a face or landscape).

Use at least:
1. Three different Color objects.
2. Ten different Sprite objects.
3. One (or more) RectangleAsset objects.
4. One (or more) CircleAsset objects.
5. One (or more) EllipseAsset objects.
6. One (or more) PolygonAsset objects.

See:
https://github.com/HHS-IntroProgramming/Standards-and-Syllabus/wiki/Displaying-Graphics
for general information on how to use ggame.

See:
http://brythonserver.github.io/ggame/
for detailed information on ggame.

"""
from ggame import App, Color, LineStyle, Sprite, RectangleAsset, CircleAsset, EllipseAsset, PolygonAsset

# add your code here \/  \/  \/
red = Color(0xff0000, 1.0)
green = Color(0x00ff00, 1.0)
blue = Color(0x0000ff, 1.0)
black = Color(0x000000, 1.0)
yellow = Color(0xF2EC41, 1.0)
darkgreen = Color(0x278F28, 1.0)
brown = Color(0x693C0E, 1.0)
lightblue = Color(0x7EE7F2, 1.0)
thinline = LineStyle(1, black)

sky = RectangleAsset(300, 250, thinline, lightblue)
ground = RectangleAsset(300, 50, thinline, green)
sun = CircleAsset(20, thinline, yellow)
trunk = RectangleAsset(20, 40, thinline, brown)
tree = PolygonAsset([(180,10),(140,90),(220,90)], thinline, darkgreen)

Sprite(sky)
Sprite(ground, (0, 200))
Sprite(sun, (30,30))
Sprite(trunk, (170, 170))
Sprite(tree, (0, 85))
Sprite(tree, (0, 40))

# add your code here /\  /\  /\

myapp = App()
myapp.run()
<commit_msg>Updated from Brython Server: 1/25/2016 2:56:55 PM<commit_after>"""
picture.py
Author: Mary Feyrer
Credit: colorpicker.com

Assignment:

Use the ggame library to "paint" a graphical picture of something (e.g. a house, a face or landscape).

Use at least:
1. Three different Color objects.
2. Ten different Sprite objects.
3. One (or more) RectangleAsset objects.
4. One (or more) CircleAsset objects.
5. One (or more) EllipseAsset objects.
6. One (or more) PolygonAsset objects.

See:
https://github.com/HHS-IntroProgramming/Standards-and-Syllabus/wiki/Displaying-Graphics
for general information on how to use ggame.

See:
http://brythonserver.github.io/ggame/
for detailed information on ggame.

"""
from ggame import App, Color, LineStyle, Sprite, RectangleAsset, CircleAsset, EllipseAsset, PolygonAsset

# add your code here \/  \/  \/
red = Color(0xff0000, 1.0)
green = Color(0x00ff00, 1.0)
blue = Color(0x0000ff, 1.0)
black = Color(0x000000, 1.0)
yellow = Color(0xF2EC41, 1.0)
darkgreen = Color(0x278F28, 1.0)
brown = Color(0x693C0E, 1.0)
lightblue = Color(0x7EE7F2, 1.0)
thinline = LineStyle(1, black)

sky = RectangleAsset(300, 250, thinline, lightblue)
ground = RectangleAsset(300, 50, thinline, green)
sun = CircleAsset(20, thinline, yellow)
trunk = RectangleAsset(20, 40, thinline, brown)
tree = PolygonAsset([(180,10),(140,90),(220,90)], thinline, darkgreen)

Sprite(sky)
Sprite(ground, (0, 200))
Sprite(sun, (30,30))
Sprite(trunk, (170, 170))
Sprite(tree, (0, 90))
Sprite(tree, (0, 45))

# add your code here /\  /\  /\

myapp = App()
myapp.run()
<|endoftext|>


<commit_before>"""
picture.py
Author: Mary Feyrer
Credit: colorpicker.com

Assignment:

Use the ggame library to "paint" a graphical picture of something (e.g. a house, a face or landscape).

Use at least:
1. Three different Color objects.
2. Ten different Sprite objects.
3. One (or more) RectangleAsset objects.
4. One (or more) CircleAsset objects.
5. One (or more) EllipseAsset objects.
6. One (or more) PolygonAsset objects.

See:
https://github.com/HHS-IntroProgramming/Standards-and-Syllabus/wiki/Displaying-Graphics
for general information on how to use ggame.

See:
http://brythonserver.github.io/ggame/
for detailed information on ggame.

"""
from ggame import App, Color, LineStyle, Sprite, RectangleAsset, CircleAsset, EllipseAsset, PolygonAsset

# add your code here \/  \/  \/
red = Color(0xff0000, 1.0)
green = Color(0x00ff00, 1.0)
blue = Color(0x0000ff, 1.0)
black = Color(0x000000, 1.0)
yellow = Color(0xF2EC41, 1.0)
darkgreen = Color(0x278F28, 1.0)
brown = Color(0x693C0E, 1.0)
pink = Color(0xF573DD, 1.0)
white = Color(0xffffff, 0.9)
lightblue = Color(0x7EE7F2, 1.0)
thinline = LineStyle(1, black)

sky = RectangleAsset(300, 250, thinline, lightblue)
ground = RectangleAsset(300, 50, thinline, green)
sun = CircleAsset(20, thinline, yellow)
trunk = RectangleAsset(20, 40, thinline, brown)
tree = PolygonAsset([(180,10),(140,90),(220,90)], thinline, darkgreen)
tree2 = PolygonAsset([(180,10),(135,90),(225,90)], thinline, darkgreen)
stem = RectangleAsset(7,20, thinline, green)
flower = CircleAsset(6, thinline, pink)
cloud = EllipseAsset(40, 10, thinline, white)

Sprite(sky)
Sprite(ground, (0, 200))
Sprite(sun, (30,30))
Sprite(trunk, (160, 170))
Sprite(tree2, (-10, 90))
Sprite(tree, (-10, 45))
Sprite(stem, (62, 186))
Sprite(flower, (60, 182))
Sprite(flower, (57, 172))
Sprite(flower, (70, 182))
Sprite(flower, (74, 172))
Sprite(flower, (65, 165))
Sprite(cloud, (230, 35))

# add your code here /\  /\  /\

myapp = App()
myapp.run()
<commit_msg>Updated from Brython Server: 1/26/2016 2:26:13 PM<commit_after>"""
picture.py
Author: Mary Feyrer
Credit: colorpicker.com

Assignment:

Use the ggame library to "paint" a graphical picture of something (e.g. a house, a face or landscape).

Use at least:
1. Three different Color objects.
2. Ten different Sprite objects.
3. One (or more) RectangleAsset objects.
4. One (or more) CircleAsset objects.
5. One (or more) EllipseAsset objects.
6. One (or more) PolygonAsset objects.

See:
https://github.com/HHS-IntroProgramming/Standards-and-Syllabus/wiki/Displaying-Graphics
for general information on how to use ggame.

See:
http://brythonserver.github.io/ggame/
for detailed information on ggame.

"""
from ggame import App, Color, LineStyle, Sprite, RectangleAsset, CircleAsset, EllipseAsset, PolygonAsset

# add your code here \/  \/  \/
red = Color(0xff0000, 1.0)
green = Color(0x00ff00, 1.0)
blue = Color(0x0000ff, 1.0)
black = Color(0x000000, 1.0)
yellow = Color(0xF2EC41, 1.0)
darkgreen = Color(0x278F28, 1.0)
brown = Color(0x693C0E, 1.0)
pink = Color(0xF573DD, 1.0)
white = Color(0xffffff, 0.9)
lightblue = Color(0x7EE7F2, 1.0)
thinline = LineStyle(1, black)

sky = RectangleAsset(300, 250, thinline, lightblue)
ground = RectangleAsset(300, 50, thinline, green)
sun = CircleAsset(20, thinline, yellow)
trunk = RectangleAsset(20, 40, thinline, brown)
tree = PolygonAsset([(180,10),(140,90),(220,90)], thinline, darkgreen)
tree2 = PolygonAsset([(180,10),(135,90),(225,90)], thinline, darkgreen)
stem = RectangleAsset(7,20, thinline, green)
flower = CircleAsset(6, thinline, pink)
cloud = EllipseAsset(40, 10, thinline, white)

Sprite(sky)
Sprite(ground, (0, 200))
Sprite(sun, (30,30))
Sprite(trunk, (160, 170))
Sprite(tree2, (-10, 90))
Sprite(tree, (-10, 45))
Sprite(stem, (62, 186))
Sprite(flower, (60, 182))
Sprite(flower, (57, 172))
Sprite(flower, (70, 182))
Sprite(flower, (74, 172))
Sprite(flower, (65, 165))
Sprite(cloud, (240, 40))

# add your code here /\  /\  /\

myapp = App()
myapp.run()
<|endoftext|>


<commit_before>"""
    weasyprint.utils
    ----------------

    Various utility functions and classes.

    :copyright: Copyright 2011-2019 Simon Sapin and contributors, see AUTHORS.
    :license: BSD, see LICENSE for details.

"""

import codecs
import contextlib
import email
import gzip
import io
import os.path
import re
import sys
import traceback
import zlib
from base64 import decodebytes
from gzip import GzipFile
from urllib.parse import quote, unquote, urljoin, urlsplit
from urllib.request import Request, pathname2url, urlopen

from . import VERSION_STRING
from .logger import LOGGER

# See http://stackoverflow.com/a/11687993/1162888
# Both are needed in Python 3 as the re module does not like to mix
# http://tools.ietf.org/html/rfc3986#section-3.1
UNICODE_SCHEME_RE = re.compile('^([a-zA-Z][a-zA-Z0-9.+-]+):')
BYTES_SCHEME_RE = re.compile(b'^([a-zA-Z][a-zA-Z0-9.+-]+):')

# getfilesystemencoding() on Linux is sometimes stupid...
FILESYSTEM_ENCODING = sys.getfilesystemencoding()
try:
    if codecs.lookup(FILESYSTEM_ENCODING).name == 'ascii':
        FILESYSTEM_ENCODING = 'utf-8'
except LookupError:
    FILESYSTEM_ENCODING = 'utf-8'

class StreamingGzipFile(GzipFile):
    def __init__(self, fileobj):
        GzipFile.__init__(self, fileobj=fileobj)
        self.fileobj_to_close = fileobj

    def close(self):
        GzipFile.close(self)
        self.fileobj_to_close.close()

    # Inform html5lib to not rely on these:
    seek = tell = None

def parse_email(data):
    if isinstance(data, bytes):
        data = data.decode('utf8')
    return email.message_from_string(data)

def iri_to_uri(url):
    """Turn an IRI that can contain any Unicode character into an ASCII-only
    URI that conforms to RFC 3986.
    """
    if url.startswith('data:'):
        # Data URIs can be huge, but don’t need this anyway.
        return url
    # Use UTF-8 as per RFC 3987 (IRI), except for file://
    url = url.encode(FILESYSTEM_ENCODING
                     if url.startswith('file:') else 'utf-8')
    # This is a full URI, not just a component. Only %-encode characters
    # that are not allowed at all in URIs. Everthing else is "safe":
    # * Reserved characters: /:?#[]@!$&'()*+,;=
    # * Unreserved characters: ASCII letters, digits and -._~
    #   Of these, only '~' is not in urllib’s "always safe" list.
    # * '%' to avoid double-encoding
    return quote(url, safe=b"/:?#[]@!$&'()*+,;=~%")

def path2url(path):
    """Return file URL of `path`.
    Accepts 'str' or 'bytes', returns 'str'
    """
    # Ensure 'str'
    if isinstance(path, bytes):
        path = path.decode(sys.getfilesystemencoding())
    # if a trailing path.sep is given -- keep it
    wants_trailing_slash = path.endswith(os.path.sep) or path.endswith('/')
    path = os.path.abspath(path)
    if wants_trailing_slash or os.path.isdir(path):
        # Make sure directory names have a trailing slash.
        # Otherwise relative URIs are resolved from the parent directory.
        path += os.path.sep
        wants_trailing_slash = True
    path = pathname2url(path)
    # on Windows pathname2url cuts off trailing slash
    if wants_trailing_slash and not path.endswith('/'):
        path += '/'
    if path.startswith('///'):
        # On Windows pathname2url(r'C:\foo') is apparently '///C:/foo'
        # That enough slashes already.
        return 'file:' + path
    else:
        return 'file://' + path

def url_is_absolute(url):
    return bool(
        (UNICODE_SCHEME_RE if isinstance(url, str) else BYTES_SCHEME_RE)
        .match(url))

def get_url_attribute(element, attr_name, base_url, allow_relative=False):
    """Get the URI corresponding to the ``attr_name`` attribute.

    Return ``None`` if:

    * the attribute is empty or missing or,
    * the value is a relative URI but the document has no base URI and
      ``allow_relative`` is ``False``.

    Otherwise return an URI, absolute if possible.

    """
    value = element.get(attr_name, '').strip()
    if value:
        return url_join(
            base_url or '', value, allow_relative, '<%s %s="%s">',
            (element.tag, attr_name, value))

def url_join(base_url, url, allow_relative, context, context_args):
    """Like urllib.urljoin, but warn if base_url is required but missing."""
    if url_is_absolute(url):
        return iri_to_uri(url)
    elif base_url:
        return iri_to_uri(urljoin(base_url, url))
    elif allow_relative:
        return iri_to_uri(url)
    else:
        LOGGER.error('Relative URI reference without a base URI: ' + context,
                     *context_args)
        return None

def get_link_attribute(element, attr_name, base_url):
    """Return ('external', absolute_uri) or
    ('internal', unquoted_fragment_id) or None.

    """
    attr_value = element.get(attr_name, '').strip()
    if attr_value.startswith('#') and len(attr_value) > 1:
        # Do not require a base_url when the value is just a fragment.
        return ('url', ('internal', unquote(attr_value[1:])))
    uri = get_url_attribute(element, attr_name, base_url, allow_relative=True)
    if uri:
        if base_url:
            parsed = urlsplit(uri)
            # Compare with fragments removed
            if parsed[:-1] == urlsplit(base_url)[:-1]:
                return ('url', ('internal', unquote(parsed.fragment)))
        return ('url', ('external', uri))

def ensure_url(string):
    """Get a ``scheme://path`` URL from ``string``.

    If ``string`` looks like an URL, return it unchanged. Otherwise assume a
    filename and convert it to a ``file://`` URL.

    """
    return string if url_is_absolute(string) else path2url(string)

def safe_decodebytes(data):
    """Decode base64, padding being optional.

    "From a theoretical point of view, the padding character is not needed,
     since the number of missing bytes can be calculated from the number
     of Base64 digits."

    https://en.wikipedia.org/wiki/Base64#Padding

    :param data: Base64 data as an ASCII byte string
    :returns: The decoded byte string.

    """
    missing_padding = 4 - len(data) % 4
    if missing_padding:
        data += b'=' * missing_padding
    return decodebytes(data)

HTTP_HEADERS = {
    'User-Agent': VERSION_STRING,
    'Accept': '*/*',
    'Accept-Encoding': 'gzip, deflate',
}

def default_url_fetcher(url, timeout=10):
    """Fetch an external resource such as an image or stylesheet.

    Another callable with the same signature can be given as the
    :obj:`url_fetcher` argument to :class:`HTML` or :class:`CSS`.
    (See :ref:`url-fetchers`.)

    :type url: str
    :param url: The URL of the resource to fetch.
    :raises: An exception indicating failure, e.g. :obj:`ValueError` on
        syntactically invalid URL.
    :returns: A :obj:`dict` with the following keys:

        * One of ``string`` (a :obj:`bytestring <bytes>`) or ``file_obj``
          (a :term:`file object`).
        * Optionally: ``mime_type``, a MIME type extracted e.g. from a
          *Content-Type* header. If not provided, the type is guessed from the
          file extension in the URL.
        * Optionally: ``encoding``, a character encoding extracted e.g. from a
          *charset* parameter in a *Content-Type* header
        * Optionally: ``redirected_url``, the actual URL of the resource
          if there were e.g. HTTP redirects.
        * Optionally: ``filename``, the filename of the resource. Usually
          derived from the *filename* parameter in a *Content-Disposition*
          header

        If a ``file_obj`` key is given, it is the caller’s responsibility
        to call ``file_obj.close()``. The default function used internally to
        fetch data in WeasyPrint tries to close the file object after
        retreiving; but if this URL fetcher is used elsewhere, the file object
        has to be closed manually.

    """
    if UNICODE_SCHEME_RE.match(url):
        # See https://bugs.python.org/issue34702
        if url.startswith('file://'):
            url = url.split('?')[0]

        url = iri_to_uri(url)
        response = urlopen(Request(url, headers=HTTP_HEADERS), timeout=timeout)
        response_info = response.info()
        result = dict(redirected_url=response.geturl(),
                      mime_type=response_info.get_content_type(),
                      encoding=response_info.get_param('charset'),
                      filename=response_info.get_filename())
        content_encoding = response_info.get('Content-Encoding')
        if content_encoding == 'gzip':
            if StreamingGzipFile is None:
                result['string'] = gzip.GzipFile(
                    fileobj=io.BytesIO(response.read())).read()
                response.close()
            else:
                result['file_obj'] = StreamingGzipFile(fileobj=response)
        elif content_encoding == 'deflate':
            data = response.read()
            try:
                result['string'] = zlib.decompress(data)
            except zlib.error:
                # Try without zlib header or checksum
                result['string'] = zlib.decompress(data, -15)
        else:
            result['file_obj'] = response
        return result
    else:
        raise ValueError('Not an absolute URI: %r' % url)

class URLFetchingError(IOError):
    """Some error happened when fetching an URL."""

@contextlib.contextmanager
def fetch(url_fetcher, url):
    """Call an url_fetcher, fill in optional data, and clean up."""
    try:
        result = url_fetcher(url)
    except Exception as exc:
        raise URLFetchingError('%s: %s' % (type(exc).__name__, str(exc)))
    result.setdefault('redirected_url', url)
    result.setdefault('mime_type', None)
    if 'file_obj' in result:
        try:
            yield result
        finally:
            try:
                result['file_obj'].close()
            except Exception:
                # May already be closed or something.
                # This is just cleanup anyway: log but make it non-fatal.
                LOGGER.warning('Error when closing stream for %s:\n%s',
                               url, traceback.format_exc())
    else:
        yield result
<commit_msg>allow ability to ignore ssl verification within default_url_fetcher<commit_after>"""
    weasyprint.utils
    ----------------

    Various utility functions and classes.

    :copyright: Copyright 2011-2019 Simon Sapin and contributors, see AUTHORS.
    :license: BSD, see LICENSE for details.

"""

import codecs
import contextlib
import email
import gzip
import io
import os.path
import re
import sys
import traceback
import zlib
import ssl
from base64 import decodebytes
from gzip import GzipFile
from urllib.parse import quote, unquote, urljoin, urlsplit
from urllib.request import Request, pathname2url, urlopen

from . import VERSION_STRING
from .logger import LOGGER

# See http://stackoverflow.com/a/11687993/1162888
# Both are needed in Python 3 as the re module does not like to mix
# http://tools.ietf.org/html/rfc3986#section-3.1
UNICODE_SCHEME_RE = re.compile('^([a-zA-Z][a-zA-Z0-9.+-]+):')
BYTES_SCHEME_RE = re.compile(b'^([a-zA-Z][a-zA-Z0-9.+-]+):')

# getfilesystemencoding() on Linux is sometimes stupid...
FILESYSTEM_ENCODING = sys.getfilesystemencoding()
try:
    if codecs.lookup(FILESYSTEM_ENCODING).name == 'ascii':
        FILESYSTEM_ENCODING = 'utf-8'
except LookupError:
    FILESYSTEM_ENCODING = 'utf-8'

class StreamingGzipFile(GzipFile):
    def __init__(self, fileobj):
        GzipFile.__init__(self, fileobj=fileobj)
        self.fileobj_to_close = fileobj

    def close(self):
        GzipFile.close(self)
        self.fileobj_to_close.close()

    # Inform html5lib to not rely on these:
    seek = tell = None

def parse_email(data):
    if isinstance(data, bytes):
        data = data.decode('utf8')
    return email.message_from_string(data)

def iri_to_uri(url):
    """Turn an IRI that can contain any Unicode character into an ASCII-only
    URI that conforms to RFC 3986.
    """
    if url.startswith('data:'):
        # Data URIs can be huge, but don’t need this anyway.
        return url
    # Use UTF-8 as per RFC 3987 (IRI), except for file://
    url = url.encode(FILESYSTEM_ENCODING
                     if url.startswith('file:') else 'utf-8')
    # This is a full URI, not just a component. Only %-encode characters
    # that are not allowed at all in URIs. Everthing else is "safe":
    # * Reserved characters: /:?#[]@!$&'()*+,;=
    # * Unreserved characters: ASCII letters, digits and -._~
    #   Of these, only '~' is not in urllib’s "always safe" list.
    # * '%' to avoid double-encoding
    return quote(url, safe=b"/:?#[]@!$&'()*+,;=~%")

def path2url(path):
    """Return file URL of `path`.
    Accepts 'str' or 'bytes', returns 'str'
    """
    # Ensure 'str'
    if isinstance(path, bytes):
        path = path.decode(sys.getfilesystemencoding())
    # if a trailing path.sep is given -- keep it
    wants_trailing_slash = path.endswith(os.path.sep) or path.endswith('/')
    path = os.path.abspath(path)
    if wants_trailing_slash or os.path.isdir(path):
        # Make sure directory names have a trailing slash.
        # Otherwise relative URIs are resolved from the parent directory.
        path += os.path.sep
        wants_trailing_slash = True
    path = pathname2url(path)
    # on Windows pathname2url cuts off trailing slash
    if wants_trailing_slash and not path.endswith('/'):
        path += '/'
    if path.startswith('///'):
        # On Windows pathname2url(r'C:\foo') is apparently '///C:/foo'
        # That enough slashes already.
        return 'file:' + path
    else:
        return 'file://' + path

def url_is_absolute(url):
    return bool(
        (UNICODE_SCHEME_RE if isinstance(url, str) else BYTES_SCHEME_RE)
        .match(url))

def get_url_attribute(element, attr_name, base_url, allow_relative=False):
    """Get the URI corresponding to the ``attr_name`` attribute.

    Return ``None`` if:

    * the attribute is empty or missing or,
    * the value is a relative URI but the document has no base URI and
      ``allow_relative`` is ``False``.

    Otherwise return an URI, absolute if possible.

    """
    value = element.get(attr_name, '').strip()
    if value:
        return url_join(
            base_url or '', value, allow_relative, '<%s %s="%s">',
            (element.tag, attr_name, value))

def url_join(base_url, url, allow_relative, context, context_args):
    """Like urllib.urljoin, but warn if base_url is required but missing."""
    if url_is_absolute(url):
        return iri_to_uri(url)
    elif base_url:
        return iri_to_uri(urljoin(base_url, url))
    elif allow_relative:
        return iri_to_uri(url)
    else:
        LOGGER.error('Relative URI reference without a base URI: ' + context,
                     *context_args)
        return None

def get_link_attribute(element, attr_name, base_url):
    """Return ('external', absolute_uri) or
    ('internal', unquoted_fragment_id) or None.

    """
    attr_value = element.get(attr_name, '').strip()
    if attr_value.startswith('#') and len(attr_value) > 1:
        # Do not require a base_url when the value is just a fragment.
        return ('url', ('internal', unquote(attr_value[1:])))
    uri = get_url_attribute(element, attr_name, base_url, allow_relative=True)
    if uri:
        if base_url:
            parsed = urlsplit(uri)
            # Compare with fragments removed
            if parsed[:-1] == urlsplit(base_url)[:-1]:
                return ('url', ('internal', unquote(parsed.fragment)))
        return ('url', ('external', uri))

def ensure_url(string):
    """Get a ``scheme://path`` URL from ``string``.

    If ``string`` looks like an URL, return it unchanged. Otherwise assume a
    filename and convert it to a ``file://`` URL.

    """
    return string if url_is_absolute(string) else path2url(string)

def safe_decodebytes(data):
    """Decode base64, padding being optional.

    "From a theoretical point of view, the padding character is not needed,
     since the number of missing bytes can be calculated from the number
     of Base64 digits."

    https://en.wikipedia.org/wiki/Base64#Padding

    :param data: Base64 data as an ASCII byte string
    :returns: The decoded byte string.

    """
    missing_padding = 4 - len(data) % 4
    if missing_padding:
        data += b'=' * missing_padding
    return decodebytes(data)

HTTP_HEADERS = {
    'User-Agent': VERSION_STRING,
    'Accept': '*/*',
    'Accept-Encoding': 'gzip, deflate',
}

def default_url_fetcher(url, timeout=10, verify=True):
    """Fetch an external resource such as an image or stylesheet.

    Another callable with the same signature can be given as the
    :obj:`url_fetcher` argument to :class:`HTML` or :class:`CSS`.
    (See :ref:`url-fetchers`.)

    :type url: str
    :param url: The URL of the resource to fetch.
    :raises: An exception indicating failure, e.g. :obj:`ValueError` on
        syntactically invalid URL.
    :returns: A :obj:`dict` with the following keys:

        * One of ``string`` (a :obj:`bytestring <bytes>`) or ``file_obj``
          (a :term:`file object`).
        * Optionally: ``mime_type``, a MIME type extracted e.g. from a
          *Content-Type* header. If not provided, the type is guessed from the
          file extension in the URL.
        * Optionally: ``encoding``, a character encoding extracted e.g. from a
          *charset* parameter in a *Content-Type* header
        * Optionally: ``redirected_url``, the actual URL of the resource
          if there were e.g. HTTP redirects.
        * Optionally: ``filename``, the filename of the resource. Usually
          derived from the *filename* parameter in a *Content-Disposition*
          header

        If a ``file_obj`` key is given, it is the caller’s responsibility
        to call ``file_obj.close()``. The default function used internally to
        fetch data in WeasyPrint tries to close the file object after
        retreiving; but if this URL fetcher is used elsewhere, the file object
        has to be closed manually.

    """
    if UNICODE_SCHEME_RE.match(url):
        # See https://bugs.python.org/issue34702
        if url.startswith('file://'):
            url = url.split('?')[0]

        url = iri_to_uri(url)
        if verify:
            ctx = ssl.create_default_context()
            ctx.check_hostname = False
            response = urlopen(Request(url, headers=HTTP_HEADERS), timeout=timeout, context=ctx)
        else:
            response = urlopen(Request(url, headers=HTTP_HEADERS), timeout=timeout)
        response_info = response.info()
        result = dict(redirected_url=response.geturl(),
                      mime_type=response_info.get_content_type(),
                      encoding=response_info.get_param('charset'),
                      filename=response_info.get_filename())
        content_encoding = response_info.get('Content-Encoding')
        if content_encoding == 'gzip':
            if StreamingGzipFile is None:
                result['string'] = gzip.GzipFile(
                    fileobj=io.BytesIO(response.read())).read()
                response.close()
            else:
                result['file_obj'] = StreamingGzipFile(fileobj=response)
        elif content_encoding == 'deflate':
            data = response.read()
            try:
                result['string'] = zlib.decompress(data)
            except zlib.error:
                # Try without zlib header or checksum
                result['string'] = zlib.decompress(data, -15)
        else:
            result['file_obj'] = response
        return result
    else:
        raise ValueError('Not an absolute URI: %r' % url)

class URLFetchingError(IOError):
    """Some error happened when fetching an URL."""

@contextlib.contextmanager
def fetch(url_fetcher, url):
    """Call an url_fetcher, fill in optional data, and clean up."""
    try:
        result = url_fetcher(url)
    except Exception as exc:
        raise URLFetchingError('%s: %s' % (type(exc).__name__, str(exc)))
    result.setdefault('redirected_url', url)
    result.setdefault('mime_type', None)
    if 'file_obj' in result:
        try:
            yield result
        finally:
            try:
                result['file_obj'].close()
            except Exception:
                # May already be closed or something.
                # This is just cleanup anyway: log but make it non-fatal.
                LOGGER.warning('Error when closing stream for %s:\n%s',
                               url, traceback.format_exc())
    else:
        yield result
<|endoftext|>