<commit_before>"""Call the NASA Mars Rover Photo API and return image data."""
from __future__ import unicode_literals, absolute_import

import re
import os
import sys
import json
import time
import requests
from operator import itemgetter
from itertools import count, combinations
import django
django.setup()

from photos.models import Photo, Rover, Camera

RIGHT_LENS = r'R.{3}\-BR\.JPG'
LOW_RES_SPI_OPP = r'ESF.{7}\-BR\.JPG'
BAD_CUR = r'.(M|D).{7}(NCAM|TRAV|SAPP).{7}\.JPG'
BAD_PATS = (RIGHT_LENS, LOW_RES_SPI_OPP, BAD_CUR)

BASE_URL = 'https://api.nasa.gov/mars-photos/api/v1/rovers/{}/photos'
INIT_DATA = os.path.join(os.dirname(__file__), 'initial_data.json')
NASA_API_KEY = os.environ['NASA_API_KEY']
NULL_IMG_SRC = 'notreal.jpg'
DEFAULT_LAST_EARTH_DATE = '2004-01-04'

def get_initial_data():
    """Get initial data as list of rovers from json file."""
    with open(INIT_DATA) as json_file:
        return json.load(json_file)

def iter_sol_rover(max_sol):
    """Generate sol/rover combinations."""
    sol_counter = count()
    rovers = Rover.objects.all()
    while True:
        sol = next(sol_counter)
        if max_sol is not None and sol > max_sol:
            break
        for rover in rovers:
            yield sol, rover

def make_rover_url(rover_name):
    """Make a url to query a rover's photos."""
    return BASE_URL.format(rover_name)

def populate_rovers_and_cameras(rover_data):
    """Populate Rover objects from pre-defined data."""
    for rover in rover_data:
        cameras = rover.pop('cameras')
        new_rover = Rover(**rover)
        new_rover.save()

        for camera in cameras:
            new_camera = Camera(**camera)
            new_camera.save()
            new_camera.rover = new_rover

def populate_photos(max_sol=None):
    """Fill database with photos from NASA API."""
    api_key = NASA_API_KEY
    last_earth_date = DEFAULT_LAST_EARTH_DATE
    null_id_counter = count(1000000000)

    rover_data = Rover.objects.all()
    prev_photos = {
        rover.name: {camera.name: None for camera in rover.cameras.all()}
        for rover in rover_data
    }

    for sol, rover in iter_sol_rover(max_sol):
        url = make_rover_url(rover.name)

        # Dict keeping track of just the photos from each cam at this sol.
        photos_this_sol = {}

        for camera in rover.cameras.all():
            photos = get_photos(url, sol, camera.name, api_key)
            photos = filter(is_good_photo, photos)
            photos = sorted(photos, key=itemgetter('img_src'))

            for photo in photos:
                print('Creating photo:\n{}\n'.format(photo))

                # Prepare params for init --overwrite dict with model
                photo['camera'] = camera
                photo['rover'] = rover
                new_photo = Photo(**photo)

                # Crucial association of prev_photo/next_photo relationship
                if prev_photos[rover.name][camera.name] is not None:
                    new_photo.prev_photo = prev_photos[rover.name][camera.name]
                new_photo.save()
                prev_photos[rover.name][camera.name] = new_photo

                photos_this_sol.setdefault(camera.name, []).append(new_photo)

                last_earth_date = max((last_earth_date, photo['earth_date']))

            if not photos:
                null_photo = make_null_photo(
                    id=next(null_id_counter),
                    sol=sol,
                    earth_date=last_earth_date,
                    camera=camera,
                    rover=rover
                )
                photos_this_sol[camera.name] = [null_photo]

        set_concurrent(photos_this_sol)

def set_concurrent(photos_by_cam):
    """Set relationships between photos from same sol on different cameras."""
    for pair in combinations(photos_by_cam.values(), 2):
        shortest, longest = sorted(pair, key=len)
        # round up instead?
        ratio = len(longest) // len(shortest)

        for idx, photo in enumerate(shortest):
            try:
                other = longest[idx * ratio]
            except IndexError:
                other = longest[-1]
            photo.concurrent.add(other)

        for idx, photo in enumerate(longest):
            try:
                other = shortest[idx // ratio]
            except IndexError:
                other = shortest[-1]
            photo.concurrent.add(other)

def get_photos(url, sol, camera, api_key):
    """Get all photos from one sol from one camera."""
    found_ids = set()
    page_counter = count(1)
    while True:
        page = next(page_counter)
        page_photos = make_page_request(url, sol, camera, api_key, page)
        print('{} photos: sol={}, camera={}, page={}'.format(
            len(page_photos), sol, camera, page))
        if not page_photos:
            break
        for photo in page_photos:
            if photo["id"] not in found_ids:
                found_ids.add(photo['id'])
                yield photo

def make_page_request(url, sol, camera, api_key, page):
    """Make one page request from NASA API."""
    time.sleep(0.4)
    params = {
        'sol': sol,
        'camera': camera,
        'api_key': api_key,
        'page': page,
    }
    response = requests.get(url, params=params)
    if response.status_code != 200:
        return []
    return response.json()['photos']

def is_good_photo(photo):
    """Return True if photo is usable; False if it is a bad photo."""
    return all([re.search(pat, photo['img_src']) is None for pat in BAD_PATS])

def make_null_photo(**kwargs):
    """Enter a Photo into the database which is an empty placeholder."""
    kwargs['img_src'] = NULL_IMG_SRC
    new_photo = Photo(**kwargs)
    new_photo.save()
    print('Created null photo for rover={} camera={} sol={}'.format(
        kwargs['rover'].name, kwargs['camera'].name, kwargs['sol']
    ))
    return new_photo

if __name__ == '__main__':

    rover_data = get_initial_data()
    populate_rovers_and_cameras(rover_data)
    try:
        populate_photos(int(sys.argv[1]))
    except IndexError:
        populate_photos()
<commit_msg>Fixed os.dirname -> os.path.dirname<commit_after>"""Call the NASA Mars Rover Photo API and return image data."""
from __future__ import unicode_literals, absolute_import

import re
import os
import sys
import json
import time
import requests
from operator import itemgetter
from itertools import count, combinations
import django
django.setup()

from photos.models import Photo, Rover, Camera

RIGHT_LENS = r'R.{3}\-BR\.JPG'
LOW_RES_SPI_OPP = r'ESF.{7}\-BR\.JPG'
BAD_CUR = r'.(M|D).{7}(NCAM|TRAV|SAPP).{7}\.JPG'
BAD_PATS = (RIGHT_LENS, LOW_RES_SPI_OPP, BAD_CUR)

BASE_URL = 'https://api.nasa.gov/mars-photos/api/v1/rovers/{}/photos'
INIT_DATA = os.path.join(os.path.dirname(__file__), 'initial_data.json')
NASA_API_KEY = os.environ['NASA_API_KEY']
NULL_IMG_SRC = 'notreal.jpg'
DEFAULT_LAST_EARTH_DATE = '2004-01-04'

def get_initial_data():
    """Get initial data as list of rovers from json file."""
    with open(INIT_DATA) as json_file:
        return json.load(json_file)

def iter_sol_rover(max_sol):
    """Generate sol/rover combinations."""
    sol_counter = count()
    rovers = Rover.objects.all()
    while True:
        sol = next(sol_counter)
        if max_sol is not None and sol > max_sol:
            break
        for rover in rovers:
            yield sol, rover

def make_rover_url(rover_name):
    """Make a url to query a rover's photos."""
    return BASE_URL.format(rover_name)

def populate_rovers_and_cameras(rover_data):
    """Populate Rover objects from pre-defined data."""
    for rover in rover_data:
        cameras = rover.pop('cameras')
        new_rover = Rover(**rover)
        new_rover.save()

        for camera in cameras:
            new_camera = Camera(**camera)
            new_camera.save()
            new_camera.rover = new_rover

def populate_photos(max_sol=None):
    """Fill database with photos from NASA API."""
    api_key = NASA_API_KEY
    last_earth_date = DEFAULT_LAST_EARTH_DATE
    null_id_counter = count(1000000000)

    rover_data = Rover.objects.all()
    prev_photos = {
        rover.name: {camera.name: None for camera in rover.cameras.all()}
        for rover in rover_data
    }

    for sol, rover in iter_sol_rover(max_sol):
        url = make_rover_url(rover.name)

        # Dict keeping track of just the photos from each cam at this sol.
        photos_this_sol = {}

        for camera in rover.cameras.all():
            photos = get_photos(url, sol, camera.name, api_key)
            photos = filter(is_good_photo, photos)
            photos = sorted(photos, key=itemgetter('img_src'))

            for photo in photos:
                print('Creating photo:\n{}\n'.format(photo))

                # Prepare params for init --overwrite dict with model
                photo['camera'] = camera
                photo['rover'] = rover
                new_photo = Photo(**photo)

                # Crucial association of prev_photo/next_photo relationship
                if prev_photos[rover.name][camera.name] is not None:
                    new_photo.prev_photo = prev_photos[rover.name][camera.name]
                new_photo.save()
                prev_photos[rover.name][camera.name] = new_photo

                photos_this_sol.setdefault(camera.name, []).append(new_photo)

                last_earth_date = max((last_earth_date, photo['earth_date']))

            if not photos:
                null_photo = make_null_photo(
                    id=next(null_id_counter),
                    sol=sol,
                    earth_date=last_earth_date,
                    camera=camera,
                    rover=rover
                )
                photos_this_sol[camera.name] = [null_photo]

        set_concurrent(photos_this_sol)

def set_concurrent(photos_by_cam):
    """Set relationships between photos from same sol on different cameras."""
    for pair in combinations(photos_by_cam.values(), 2):
        shortest, longest = sorted(pair, key=len)
        # round up instead?
        ratio = len(longest) // len(shortest)

        for idx, photo in enumerate(shortest):
            try:
                other = longest[idx * ratio]
            except IndexError:
                other = longest[-1]
            photo.concurrent.add(other)

        for idx, photo in enumerate(longest):
            try:
                other = shortest[idx // ratio]
            except IndexError:
                other = shortest[-1]
            photo.concurrent.add(other)

def get_photos(url, sol, camera, api_key):
    """Get all photos from one sol from one camera."""
    found_ids = set()
    page_counter = count(1)
    while True:
        page = next(page_counter)
        page_photos = make_page_request(url, sol, camera, api_key, page)
        print('{} photos: sol={}, camera={}, page={}'.format(
            len(page_photos), sol, camera, page))
        if not page_photos:
            break
        for photo in page_photos:
            if photo["id"] not in found_ids:
                found_ids.add(photo['id'])
                yield photo

def make_page_request(url, sol, camera, api_key, page):
    """Make one page request from NASA API."""
    time.sleep(0.4)
    params = {
        'sol': sol,
        'camera': camera,
        'api_key': api_key,
        'page': page,
    }
    response = requests.get(url, params=params)
    if response.status_code != 200:
        return []
    return response.json()['photos']

def is_good_photo(photo):
    """Return True if photo is usable; False if it is a bad photo."""
    return all([re.search(pat, photo['img_src']) is None for pat in BAD_PATS])

def make_null_photo(**kwargs):
    """Enter a Photo into the database which is an empty placeholder."""
    kwargs['img_src'] = NULL_IMG_SRC
    new_photo = Photo(**kwargs)
    new_photo.save()
    print('Created null photo for rover={} camera={} sol={}'.format(
        kwargs['rover'].name, kwargs['camera'].name, kwargs['sol']
    ))
    return new_photo

if __name__ == '__main__':

    rover_data = get_initial_data()
    populate_rovers_and_cameras(rover_data)
    try:
        populate_photos(int(sys.argv[1]))
    except IndexError:
        populate_photos()
<|endoftext|>


<commit_before>"""
Space game
Ryan Kynor
Checklist:
fixed star field
~~Sun sprite~~
at least one player
muliple players or multplie inanimate objects to avoid
animated rocket thrust
collisions destroy ship
moving ships
rotating ships
Source:
lines 23 - 27 based off of orininal space game code
"""

#key list starts a line 1067 in ggame.py file

from ggame import App, RectangleAsset, ImageAsset, Sprite, LineStyle, Color, Frame

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480

class Sun(Sprite):
    """
    The Sun on the Screen
    """

    asset =  ImageAsset("images/sun.png")
    height = 80
    width = 80

    def __init__(self, position):
        super().__init__(Sun.asset, position)
        self.weight = 1
        self.fxcenter = 0.5
        self.fycenter = 0.5
        self.circularCollisionModel()

class Starfield(Sprite):
    """
    The Starfield
    """

    asset = ImageAsset("images/starfield.jpg")
    #height = SCREEN_HEIGHT
    #width = SCREEN_WIDTH

    def __init__(self, position):
        super().__init__(Starfield.asset, position)
        self.weight = 1
        self.fxcenter = 0.5
        self.fycenter = 0.5

class SpaceShip(Sprite):
    """
    Animated space ship
    """
    asset = ImageAsset("images/four_spaceship_by_albertov_with_thrust.png",
        Frame(227,0,292-227,125), 4, 'vertical')

#spaceship spawn movement
    def __init__(self, position):
        super().__init__(SpaceShip.asset, position)
        self.vx = 0
        self.vy = 0
        self.vr = 1.00
        self.thrust = 0
        self.thrustframe = 1

        #Thrust detection
        SpaceGame.listenKeyEvent("keydown", "space", self.thrustOn)
        SpaceGame.listenKeyEvent("keyup", "space", self.thrustOff)

        #Movement detection
        SpaceGame.listenKeyEvent("keydown", "w", self.moveFowardOn)
        SpaceGame.listenKeyEvent("keyup", "w", self.moveFowardOff)

        SpaceGame.listenKeyEvent("keydown", "s", self.moveBackOn)
        SpaceGame.listenKeyEvent("keyup", "s", self.moveBackOff)

        SpaceGame.listenKeyEvent("keydown", "a", self.moveLeftOn)
        SpaceGame.listenKeyEvent("keyup", "a", self.moveLeftOff)

        SpaceGame.listenKeyEvent("keydown", "d", self.moveRightOn)
        SpaceGame.listenKeyEvent("keydown", "d", self.moveRightOff)
        #Rotation animation

        #SpaceGame.listenKeyEvent("keydown", "w",
        self.fxcenter = self.fycenter = 0.5

#display of thrust
    def step(self):
        self.x += self.vx
        self.y += self.vy
        self.rotation += self.vr
        if self.thrust == 1:
            self.setImage(self.thrustframe)
            self.thrustframe += 1
            if self.thrustframe == 4:
                self.thrustframe = 1
        else:
            self.setImage(0)
#thrust
    def thrustOn(self, event):
        self.thrust = 1
    def thrustOff(self, event):
        self.thrust = 0

#movement
    def moveFowardOn(self,event):
        self.foward = 1
    def moveFowardOff(self,event):
        self.foward = 0

    def moveRightOn(self,event):
        self.right = 1
    def moveRightOff(self,event):
        self.right = 0

    def moveLeftOn(self,event):
        self.left = 1
    def moveLeftOff(self,event):
        self.left = 0

    def moveBackOn(self,event):
        self.back = 1
    def moveBackOff(self,event):
        self.back = 0

#rotation

class SpaceGame(App):
    """
    Tutorial4 space game example.
    """
    def __init__(self, width, height):
        super().__init__(width, height)
        black = Color(0, 1)
        noline = LineStyle(0, black)
        bg_asset = RectangleAsset(width, height, noline, black)
        bg = Sprite(bg_asset, (0,0))
        Starfield((SCREEN_WIDTH/2,SCREEN_HEIGHT/2))
        Sun((SCREEN_WIDTH/2,SCREEN_HEIGHT/2))
        SpaceShip((100,100))
        #SpaceShip((150,150))
        #SpaceShip((200,50))

    def step(self):
        for ship in self.getSpritesbyClass(SpaceShip):
            ship.step()

#Sun((SCREEN_WIDTH/2,SCREEN_HEIGHT/2))

myapp = SpaceGame(SCREEN_WIDTH, SCREEN_HEIGHT)
myapp.run()

#self rotation will give you the current angle of rotation in radians
Status API Training Shop Blog About Pricing
<commit_msg>Updated from Brython Server: 12/7/2015 2:23:25 PM<commit_after>"""
Space game
Ryan Kynor
Checklist:
fixed star field
~~Sun sprite~~
at least one player
muliple players or multplie inanimate objects to avoid
animated rocket thrust
collisions destroy ship
moving ships
rotating ships
Source:
lines 23 - 27 based off of orininal space game code
"""

#key list starts a line 1067 in ggame.py file

from ggame import App, RectangleAsset, ImageAsset, Sprite, LineStyle, Color, Frame

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480

class Sun(Sprite):
    """
    The Sun on the Screen
    """

    asset =  ImageAsset("images/sun.png")
    height = 80
    width = 80

    def __init__(self, position):
        super().__init__(Sun.asset, position)
        self.weight = 1
        self.fxcenter = 0.5
        self.fycenter = 0.5
        self.circularCollisionModel()

class Starfield(Sprite):
    """
    The Starfield
    """

    asset = ImageAsset("images/starfield.jpg")
    #height = SCREEN_HEIGHT
    #width = SCREEN_WIDTH

    def __init__(self, position):
        super().__init__(Starfield.asset, position)
        self.weight = 1
        self.fxcenter = 0.5
        self.fycenter = 0.5

class SpaceShip(Sprite):
    """
    Animated space ship
    """
    asset = ImageAsset("images/four_spaceship_by_albertov_with_thrust.png",
        Frame(227,0,292-227,125), 4, 'vertical')

#spaceship spawn movement
    def __init__(self, position):
        super().__init__(SpaceShip.asset, position)
        self.vx = 0
        self.vy = 0
        self.vr = 0.00
        self.thrust = 0
        self.thrustframe = 1

        #Thrust detection
        SpaceGame.listenKeyEvent("keydown", "space", self.thrustOn)
        SpaceGame.listenKeyEvent("keyup", "space", self.thrustOff)

        #Movement detection
        SpaceGame.listenKeyEvent("keydown", "w", self.moveFowardOn)
        SpaceGame.listenKeyEvent("keyup", "w", self.moveFowardOff)

        SpaceGame.listenKeyEvent("keydown", "s", self.moveBackOn)
        SpaceGame.listenKeyEvent("keyup", "s", self.moveBackOff)

        SpaceGame.listenKeyEvent("keydown", "a", self.moveLeftOn)
        SpaceGame.listenKeyEvent("keyup", "a", self.moveLeftOff)

        SpaceGame.listenKeyEvent("keydown", "d", self.moveRightOn)
        SpaceGame.listenKeyEvent("keydown", "d", self.moveRightOff)
        #Rotation animation

        #SpaceGame.listenKeyEvent("keydown", "w",
        self.fxcenter = self.fycenter = 0.5

#display of thrust
    def step(self):
        self.x += self.vx
        self.y += self.vy
        self.rotation += self.vr
        if self.thrust == 1:
            self.setImage(self.thrustframe)
            self.thrustframe += 1
            if self.thrustframe == 4:
                self.thrustframe = 1
        else:
            self.setImage(0)
#thrust
    def thrustOn(self, event):
        self.thrust = 1
    def thrustOff(self, event):
        self.thrust = 0

#movement
    def moveFowardOn(self,event):
        self.foward = 1
    def moveFowardOff(self,event):
        self.foward = 0

    def moveRightOn(self,event):
        self.right = 1
    def moveRightOff(self,event):
        self.right = 0

    def moveLeftOn(self,event):
        self.left = 1
    def moveLeftOff(self,event):
        self.left = 0

    def moveBackOn(self,event):
        self.back = 1
    def moveBackOff(self,event):
        self.back = 0

#rotation

class SpaceGame(App):
    """
    Tutorial4 space game example.
    """
    def __init__(self, width, height):
        super().__init__(width, height)
        black = Color(0, 1)
        noline = LineStyle(0, black)
        bg_asset = RectangleAsset(width, height, noline, black)
        bg = Sprite(bg_asset, (0,0))
        Starfield((SCREEN_WIDTH/2,SCREEN_HEIGHT/2))
        Sun((SCREEN_WIDTH/2,SCREEN_HEIGHT/2))
        SpaceShip((190,240))
        #SpaceShip((150,150))
        #SpaceShip((200,50))

    def step(self):
        for ship in self.getSpritesbyClass(SpaceShip):
            ship.step()

#Sun((SCREEN_WIDTH/2,SCREEN_HEIGHT/2))

myapp = SpaceGame(SCREEN_WIDTH, SCREEN_HEIGHT)
myapp.run()

#self rotation will give you the current angle of rotation in radians<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

# Copyright 2015 Juca Crispim <juca@poraodojuca.net>

# This file is part of toxicbuild.

# toxicbuild 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.

# toxicbuild 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 toxicbuild. If not, see <http://www.gnu.org/licenses/>.

from abc import ABCMeta, abstractmethod
import asyncio
import os
from toxicbuild.core.exceptions import VCSError, ImpossibillityError
from toxicbuild.core.utils import(exec_cmd, inherit_docs, string2datetime,
                                  datetime2string)

class VCS(metaclass=ABCMeta):

    """ Generic inteface to a vcs (clone, fetch, get revisions etc...).
    """
    vcsbin = None

    def __init__(self, workdir):
        """:param workdir: Directory where repository will be cloned and
        all action will happen.
        """
        self.workdir = workdir

    @asyncio.coroutine
    def exec_cmd(self, cmd, cwd=None):
        """ Executes a shell command. If ``cwd`` is None ``self.workdir``
        will be used.

        :param cwd: Directory where the command will be executed.
        """
        if cwd is None:
            cwd = self.workdir

        ret = yield from exec_cmd(cmd, cwd)
        return ret

    def workdir_exists(self):
        """ Informs if the workdir for this vcs exists
        """
        return os.path.exists(self.workdir)

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def clone(self, url):
        """ Clones a repository into ``self.workdir``
        :param url: repository url
        """

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def fetch(self):
        """ Fetch changes from remote repository
        """

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def checkout(self, named_tree):
        """ Checkout to ``named_tree``
        :param named_tree: A commit, branch, tag...
        """

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def pull(self, branch_name):
        """ Pull changes from ``branch_name`` on remote repo.

        :param branch_name: A branch name, like 'master'.
        """

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def has_changes(self):
        """ Informs if there are new revisions in the repository
        """

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def get_revisions(self, since={}):
        """ Returns the revisions for all branches since ``since``.
        :param since: dictionary in the format: {branch_name: since_date}.
          ``since`` is a datetime object.
        """

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def get_revisions_for_branch(self, branch, since=None):
        """ Returns the revisions for ``branch`` since ``since``.
        If ``since`` is None, all revisions will be returned.
        :param branch: branch name
        :param since: datetime
        """

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def get_remote_branches(self):
        """ Returns a list of the remote branches available.
        """

@inherit_docs
class Git(VCS):

    """ An interface to git version control system
    """

    vcsbin = 'git'
    # this date_format is used to ask git about revisions since
    # some date
    date_format = '%a %b %d %H:%M:%S %Y %z'

    @asyncio.coroutine
    def clone(self, url):
        cmd = '%s clone %s %s' % (self.vcsbin, url, self.workdir)
        # we can't go to self.workdir while we do not clone the repo
        yield from self.exec_cmd(cmd, cwd='.')

    @asyncio.coroutine
    def fetch(self):
        # HACK!
        # fucking git fetch send its response to stderr even
        # if everything was ok
        cmd = '%s %s 2>&1' % (self.vcsbin, 'fetch')

        fetched = yield from self.exec_cmd(cmd)
        return fetched

    @asyncio.coroutine
    def checkout(self, named_tree):

        cmd = '{} checkout {}'.format(self.vcsbin, named_tree)
        yield from self.exec_cmd(cmd)

    @asyncio.coroutine
    def pull(self, branch_name):

        cmd = '{} pull --no-edit origin {}'.format(self.vcsbin, branch_name)

        ret = yield from self.exec_cmd(cmd)
        return ret

    @asyncio.coroutine
    def has_changes(self):
        ret = yield from self.fetch()
        return bool(ret)

    @asyncio.coroutine
    def get_revisions(self, since={}):

        remote_branches = yield from self.get_remote_branches()
        revisions = {}
        for branch in remote_branches:
            yield from self.checkout(branch)
            yield from self.pull(branch)
            since_date = since.get(branch)

            revs = yield from self.get_revisions_for_branch(branch, since_date)
            revisions[branch] = revs

        return revisions

    @asyncio.coroutine
    def get_revisions_for_branch(self, branch, since=None):

        cmd = '{} log --pretty=format:"%H | %ad" '.format(self.vcsbin)
        if since:
            date = datetime2string(since, self.date_format)
            cmd += '--since="%s"' % date

        last_revs = [r for r in (yield from self.exec_cmd(cmd)).split('\n')
                     if r]
        last_revs.reverse()
        revisions = []

        for rev in last_revs:
            rev_uuid, date = rev.split('|')
            date = string2datetime(date.strip(), dtformat=self.date_format)

            revisions.append({'commit': rev_uuid.strip(), 'commit_date': date})

        return revisions

    @asyncio.coroutine
    def get_remote_branches(self):
        cmd = '%s branch -r' % self.vcsbin

        remote_branches = (yield from self.exec_cmd(cmd)).split('\n')
        # master, with some shitty arrow...
        remote_branches.pop(0)
        return [b.strip().split('/')[1] for b in remote_branches]

VCS_TYPES = {'git': Git}

def get_vcs(vcs_type):
    """ Retuns a subclass of :class:`toxicbuild.core.vcs.VCS` for ``vcs_type``
    """
    vcs = VCS_TYPES.get(vcs_type)
    if not vcs:
        raise VCSError('VCS not found for {}'.format(vcs_type))
    return vcs
<commit_msg>removing useless import<commit_after># -*- coding: utf-8 -*-

# Copyright 2015 Juca Crispim <juca@poraodojuca.net>

# This file is part of toxicbuild.

# toxicbuild 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.

# toxicbuild 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 toxicbuild. If not, see <http://www.gnu.org/licenses/>.

from abc import ABCMeta, abstractmethod
import asyncio
import os
from toxicbuild.core.exceptions import VCSError
from toxicbuild.core.utils import(exec_cmd, inherit_docs, string2datetime,
                                  datetime2string)

class VCS(metaclass=ABCMeta):

    """ Generic inteface to a vcs (clone, fetch, get revisions etc...).
    """
    vcsbin = None

    def __init__(self, workdir):
        """:param workdir: Directory where repository will be cloned and
        all action will happen.
        """
        self.workdir = workdir

    @asyncio.coroutine
    def exec_cmd(self, cmd, cwd=None):
        """ Executes a shell command. If ``cwd`` is None ``self.workdir``
        will be used.

        :param cwd: Directory where the command will be executed.
        """
        if cwd is None:
            cwd = self.workdir

        ret = yield from exec_cmd(cmd, cwd)
        return ret

    def workdir_exists(self):
        """ Informs if the workdir for this vcs exists
        """
        return os.path.exists(self.workdir)

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def clone(self, url):
        """ Clones a repository into ``self.workdir``
        :param url: repository url
        """

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def fetch(self):
        """ Fetch changes from remote repository
        """

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def checkout(self, named_tree):
        """ Checkout to ``named_tree``
        :param named_tree: A commit, branch, tag...
        """

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def pull(self, branch_name):
        """ Pull changes from ``branch_name`` on remote repo.

        :param branch_name: A branch name, like 'master'.
        """

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def has_changes(self):
        """ Informs if there are new revisions in the repository
        """

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def get_revisions(self, since={}):
        """ Returns the revisions for all branches since ``since``.
        :param since: dictionary in the format: {branch_name: since_date}.
          ``since`` is a datetime object.
        """

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def get_revisions_for_branch(self, branch, since=None):
        """ Returns the revisions for ``branch`` since ``since``.
        If ``since`` is None, all revisions will be returned.
        :param branch: branch name
        :param since: datetime
        """

    @abstractmethod  # pragma no branch
    @asyncio.coroutine
    def get_remote_branches(self):
        """ Returns a list of the remote branches available.
        """

@inherit_docs
class Git(VCS):

    """ An interface to git version control system
    """

    vcsbin = 'git'
    # this date_format is used to ask git about revisions since
    # some date
    date_format = '%a %b %d %H:%M:%S %Y %z'

    @asyncio.coroutine
    def clone(self, url):

        cmd = '%s clone %s %s' % (self.vcsbin, url, self.workdir)
        # we can't go to self.workdir while we do not clone the repo
        yield from self.exec_cmd(cmd, cwd='.')

    @asyncio.coroutine
    def fetch(self):
        # HACK!
        # fucking git fetch send its response to stderr even
        # if everything was ok
        cmd = '%s %s 2>&1' % (self.vcsbin, 'fetch')

        fetched = yield from self.exec_cmd(cmd)
        return fetched

    @asyncio.coroutine
    def checkout(self, named_tree):

        cmd = '{} checkout {}'.format(self.vcsbin, named_tree)
        yield from self.exec_cmd(cmd)

    @asyncio.coroutine
    def pull(self, branch_name):

        cmd = '{} pull --no-edit origin {}'.format(self.vcsbin, branch_name)

        ret = yield from self.exec_cmd(cmd)
        return ret

    @asyncio.coroutine
    def has_changes(self):
        ret = yield from self.fetch()
        return bool(ret)

    @asyncio.coroutine
    def get_revisions(self, since={}):

        remote_branches = yield from self.get_remote_branches()
        revisions = {}
        for branch in remote_branches:
            yield from self.checkout(branch)
            yield from self.pull(branch)
            since_date = since.get(branch)

            revs = yield from self.get_revisions_for_branch(branch, since_date)
            revisions[branch] = revs

        return revisions

    @asyncio.coroutine
    def get_revisions_for_branch(self, branch, since=None):

        cmd = '{} log --pretty=format:"%H | %ad" '.format(self.vcsbin)
        if since:
            date = datetime2string(since, self.date_format)
            cmd += '--since="%s"' % date

        last_revs = [r for r in (yield from self.exec_cmd(cmd)).split('\n')
                     if r]
        last_revs.reverse()
        revisions = []

        for rev in last_revs:
            rev_uuid, date = rev.split('|')
            date = string2datetime(date.strip(), dtformat=self.date_format)

            revisions.append({'commit': rev_uuid.strip(), 'commit_date': date})

        return revisions

    @asyncio.coroutine
    def get_remote_branches(self):
        cmd = '%s branch -r' % self.vcsbin

        remote_branches = (yield from self.exec_cmd(cmd)).split('\n')
        # master, with some shitty arrow...
        remote_branches.pop(0)
        return [b.strip().split('/')[1] for b in remote_branches]

VCS_TYPES = {'git': Git}

def get_vcs(vcs_type):
    """ Retuns a subclass of :class:`toxicbuild.core.vcs.VCS` for ``vcs_type``
    """
    vcs = VCS_TYPES.get(vcs_type)
    if not vcs:
        raise VCSError('VCS not found for {}'.format(vcs_type))
    return vcs
<|endoftext|>


<commit_before>import os
import re
import sys
import json
import math
import crayons
import requests
import collections
import better_exceptions

from dateutil import parser
from bs4 import BeautifulSoup
from operator import itemgetter
from datetime import date, datetime

better_exceptions.MAX_LENGTH = None
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
last_group = ''

def log(group, text):
    global last_group

    if last_group != group:
        print('')

    last_group = group
    sys.stdout.write('\x1b[2K\r[{} - {}] {}'.format(
        crayons.blue(datetime.now().strftime('%Y-%m-%d %H:%M:%S')), crayons.blue(group), crayons.green(text)))

def pretty(text):
    # This strips and removes tabs, new lines and (double) spaces from our string
    # Doesn't fucking always work
    text = text.replace('\t', '')
    text = text.replace('\n', '')
    text = text.replace('\\t', '')
    text = text.replace('\\n', '')
    text = re.sub(' +', ' ', text)
    text = text.strip()
    if text.startswith('"'):
        text = text[1:]
    if text.endswith('"'):
        text = text[:-1]
    return text

def fix_showname(show_name):
    if show_name == 'MOVIE:':  # Remove the colon plz
        return 'MOVIE'
    elif show_name == 'SPECIAL:':  # Remove the colon plz
        return 'SPECIAL'
    elif show_name == 'Cloudy':  # Fix name
        return 'Cloudy with a Chance of Meatballs'
    elif show_name == 'Cloudy With a Chance of Meatballs':  # Fix name
        return 'Cloudy with a Chance of Meatballs'
    elif show_name == 'The Amazing World of Gumball':  # Fix name
        return 'Amazing World of Gumball'

    return show_name

def fix_episodename(episode_name):
    # Space at the end of titles means there's actually a ", The"
    # Add the "The" back at the beginning and remove the trailing space
    # Also fix when title ends with ", A" and ", An"
    for title in episode_name.split('/'):
        fixed = re.sub(r'(.*?) $', 'The \\1', title)
        fixed = re.sub(r'(.*?), An$', 'An \\1', fixed)
        fixed = re.sub(r'(.*?), A$', 'A \\1', fixed)
        episode_name = episode_name.replace(title, fixed)

    return episode_name

def grab_cnschedule(url):
    # Get the schedule from the "backdoor" and parse it for every available day
    schedule = {}
    available_dates = []

    log('cn', 'Will get today\'s page')

    # Get the file for today and let BS parse it
    d = date.today()
    now = '%02d/%02d/%d' % (d.month, d.day, d.year)
    r = requests.get(url % now)

    log('cn', 'Parsing...')

    soup = BeautifulSoup(r.text, 'html5lib')

    # We'll now save all the available dates
    for select_date in soup.find_all('select')[1].find_all('option'):
        if select_date['value'] != '0':
            available_dates.append(select_date['value'])

    log('cn', 'Parsed. Available dates: ' + ', '.join(available_dates))

    # Now, we'll go throught each day
    for available_date in available_dates:
        # Get a YYYY-MM-DD version of the date
        parsed_date = parser.parse(available_date).strftime('%Y-%m-%d')
        # Init the list and the increment counter
        schedule[parsed_date] = {
            'source': 'Cartoon Network',
            'schedule': []
        }
        i = 0

        log('cn', 'Downloading and parsing ' + parsed_date)

        # Get the day's page
        r = requests.get(url % available_date)
        soup = BeautifulSoup(r.text, 'html5lib')

        log('cn', 'Parsed. Extracting data...')

        # And let's go directly to where the list is (yup, it's a bit complicated)
        trs = soup.find_all('table')[2].find('tr').find_all('td', recursive=False)[1]\
            .find_all('table', recursive=False)[1].find_all('td')[3]\
            .find_all('table', recursive=False)[2].find('tbody').find_all('tr', attrs={'valign': 'top'})

        # And now, for each lines...
        for i, tr in enumerate(trs):
            alt_table = False
            el_time = tr.find(class_='timecell')  # Get the element that contains the time

            if el_time is None:
                el_time = tr.find(class_='timeoncell')
                alt_table = True

            if not pretty(''.join(el_time.strings)).endswith('m'):
                continue

            try:
                # Get the "time" and "show" details
                if alt_table:  # Sometimes, it's using '[...]oncell' instead of just '[...]cell'
                    el_time = tr.find(class_='timeoncell')   # Get the element that contains the time
                    el_show = tr.find_all(class_='showoncell')  # Get the element**s** that contains show details
                    el_show_name = el_show[0].find('a')  # Get the element that contains the show name
                    show_name = pretty(''.join(el_show_name.strings))  # Get the actual show name
                    episode_name = el_show[2].string  # Get the episode title

                    # Show might not be under a link, so we try to get the first string in the element then
                    if show_name == 'See All Showings':
                        show_name = pretty(el_show[0].contents[0])

                    # Episode name might be under a link
                    if episode_name is None:
                        el_episode_name = el_show[2].find('a')
                        episode_name = pretty(''.join(el_episode_name.strings))

                else:  # If it's not, let's get our values
                    el_show = tr.find_all(class_='showcell')  # Get the element**s** that contains show details
                    el_show_name = el_show[1].find('a')  # Get the element that contains the show name
                    show_name = pretty(''.join(el_show_name.strings))  # Get the actual show name
                    episode_name = el_show[3].string  # Get the episode title

                    # Show might not be under a link, so we try to get the first string in the element then
                    if show_name == 'See All Showings':
                        show_name = pretty(el_show[1].contents[0])

                    # Episode name might be under a link
                    try:
                        if episode_name is None:
                            el_episode_name = el_show[3].find('a')
                            episode_name = pretty(''.join(el_episode_name.strings))
                    except:
                        pass

                show_name = fix_showname(show_name)

                if episode_name is None:  # If no episode title is found, return an empty string
                    episode_name = ''

                episode_name = fix_episodename(episode_name)

                try:
                    el_next_time = trs[i + 2].find(class_='timecell')
                    if el_next_time is None:
                        el_next_time = tr.find(class_='timeoncell')   # Get the element that contains the time

                    next_time = pretty(''.join(el_next_time.strings))
                except IndexError:
                    next_time = '6:00 am'

                time = pretty(''.join(el_time.strings))  # Get the air time
                parsed_datetime = parser.parse('%s %s -0400' % (parsed_date, time))  # And let's parse it
                parsed_next_datetime = parser.parse('%s %s -0400' % (parsed_date, next_time))  # And let's parse it

                # If it's before 6am and after (including) 8pm, it's the adultswim part
                if parsed_datetime.hour < 6 or parsed_datetime.hour >= 20:
                    continue

                slots = math.ceil(((int(parsed_next_datetime.timestamp()) - int(parsed_datetime.timestamp())) / 60) / 15)
                if slots < 1:
                    slots = 2

                # Add all the details to our schedule list
                schedule[parsed_date]['schedule'].append({
                    'date': parsed_date,
                    'time': time,
                    'timestamp': int(parsed_datetime.timestamp()),
                    'timestamp_end': int(parsed_next_datetime.timestamp()),
                    'show': show_name,
                    'title': episode_name,
                    'slots': slots
                })
            except:
                # If something goes wrong, show the <tr> and raise the error
                print(tr)
                raise

        log('cn', 'Data extracted.')

    # And now that we have everything we need,
    # let's return our list
    log('cn', 'Done!')
    return schedule

def grab_zapschedule(url):
    # Get the schedule from the "backdoor" and parse it for every available day
    schedule = {}
    available_dates = []

    log('zap', 'Will get today\'s page')

    # Get the file for today and let BS parse it
    r = requests.get(url)

    log('zap', 'Parsing...')

    soup = BeautifulSoup(r.text, 'html5lib')

    # We'll now save all the available dates
    for select_date in soup.find(id='zc-ssl-dayNav-popup').find_all(class_='zc-topbar-dropdown-item'):
        available_dates.append({'date': select_date.string, 'url': select_date['href']})

    log('zap', 'Parsed. Found ' + str(len(available_dates)) + ' days available')

    # Now, we'll go throught each day
    for available_date in available_dates:
        # Get a YYYY-MM-DD version of the date
        parsed_date = parser.parse(available_date['date']).strftime('%Y-%m-%d')
        # Init the list and the increment counter
        schedule[parsed_date] = {
            'source': 'Zap2it',
            'schedule': []
        }
        i = 0

        log('zap', 'Downloading and parsing ' + parsed_date)

        # Get the day's page
        r = requests.get(available_date['url'])
        soup = BeautifulSoup(r.text, 'html5lib')

        log('zap', 'Parsed. Extracting data...')

        # And let's go directly to where the list is (yup, it's a bit complicated)
        trs = soup.find_all(class_='zc-ssl-pg')

        # And now, for each lines...
        for i, tr in enumerate(trs):
            # Well, actually only the even ones
            if tr['id'].startswith('row1'):
                try:
                    # Get the "time" and "show" details
                    el_time = tr.find(class_='zc-ssl-pg-time')  # Get the element that contains the time
                    el_show_name = tr.find(class_='zc-ssl-pg-title')
                    el_episodenumber = tr.find(class_='zc-ssl-pg-ep')

                    try:
                        el_next_time = trs[i + 1].find(class_='zc-ssl-pg-time')
                        next_time = pretty(''.join(el_next_time.strings))
                    except IndexError:
                        next_time = '6:00 am'

                    show_name = pretty(''.join(el_show_name.strings))  # Get the actual show name

                    try:
                        episode_name = pretty(''.join(el_episodenumber.strings))
                    except:
                        episode_name = ''

                    show_name = fix_showname(show_name)

                    time = pretty(''.join(el_time.strings)).lower()  # Get the air time
                    parsed_datetime = parser.parse('%s %s -0500' % (parsed_date, time))  # And let's parse it
                    parsed_next_datetime = parser.parse('%s %s -0500' % (parsed_date, next_time))  # And let's parse it

                    # If it's before 6am and after (including) 8pm, it's the adultswim part
                    if parsed_datetime.hour < 6 or parsed_datetime.hour >= 20:
                        continue

                    slots = math.ceil(((int(parsed_next_datetime.timestamp()) - int(parsed_datetime.timestamp())) / 60) / 15)
                    if slots < 1:
                        slots = 2

                    # Add all the details to our schedule list
                    schedule[parsed_date]['schedule'].append({
                        'date': parsed_date,
                        'time': time,
                        'timestamp': int(parsed_datetime.timestamp()),
                        'timestamp_end': int(parsed_next_datetime.timestamp()),
                        'show': show_name,
                        'title': episode_name,
                        'slots': slots
                    })
                except:
                    # If something goes wrong, show the <tr> and raise the error
                    print(tr)
                    raise

        log('zap', 'Data extracted.')

    # And now that we have everything we need,
    # let's return our list
    log('zap', 'Done!')
    return schedule

def merge_schedules(cn_sch, zap_sch):
    log('merge', 'Fixing empty schedules...')
    for s_date, values in cn_sch.items():
        if len(values['schedule']) == 0:
            cn_sch[s_date] = zap_sch[s_date]

    log('merge', 'Adding Zap2it...')
    for s_date, __ in zap_sch.items():
        if s_date in cn_sch:
            cn_sch[s_date]['alt'] = zap_sch[s_date]
        else:
            cn_sch[s_date] = zap_sch[s_date]

    log('merge', 'Ordering...')
    for day in cn_sch:
        cn_sch[day]['schedule'] = sorted(cn_sch[day]['schedule'], key=itemgetter('timestamp'))

    ordered = collections.OrderedDict(sorted(cn_sch.items()))

    log('merge', 'Done!')
    return ordered

def gen_api(sch):
    # Save our schedule in a json file
    log('json', 'Generating json...')

    sch['_'] = {'generated': int(datetime.utcnow().timestamp())}

    with open(os.path.join(THIS_DIR, 'api', 'cnschedule.json'), 'w') as f:
        f.write(json.dumps(sch, indent=2, sort_keys=False))

    log('json', 'Done!')

if __name__ == '__main__':
    # Using the [as] "backdoor", where we can put a date in the URL
    source_url = 'http://www.adultswim.com/adultswimdynsched/servlet/ScheduleServlet?action=GO&theDate=%s&timeZone=EST'
    # First we grab CN's schedule and put it in a list
    cn_schedule = grab_cnschedule(source_url)

    # Using Zap2it's schedule list for CN to get the list
    source_url = 'http://tvschedule.zap2it.com/tvlistings/ZCSGrid.do?sgt=list&stnNum=12131&aid=tvschedule'
    # Now we grab Zap2it's schedule and put it in a list
    zap_schedule = grab_zapschedule(source_url)

    # We merge and order the schedules
    saved_schedule = merge_schedules(cn_schedule, zap_schedule)

    # Then we save what we've got
    gen_api(saved_schedule)
<commit_msg>script is now running at https://gitlab.com/ctoon/cn-schedule-fetcher<commit_after><|endoftext|>


<commit_before>import datetime
from django.http import HttpResponse
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.utils import feedgenerator
from apps.statistics.models import MStatistics, MFeedback
from apps.profile.models import PaymentHistory
from utils import log as logging

def dashboard_graphs(request):
    statistics = MStatistics.all()
    return render_to_response('statistics/render_statistics_graphs.xhtml', {
        'statistics': statistics,
    }, context_instance=RequestContext(request))

def feedback_table(request):
    feedbacks = MFeedback.all()
    return render_to_response('statistics/render_feedback_table.xhtml', {
        'feedbacks': feedbacks,
    }, context_instance=RequestContext(request))

def revenue(request):
    data = {}
    data['title'] = "NewsBlur Revenue"
    data['link'] = "https://www.newsblur.com"
    data['description'] = "Revenue"
    data['lastBuildDate'] = datetime.datetime.utcnow()
    data['generator'] = 'NewsBlur Revenue Writer'
    data['docs'] = None
    rss = feedgenerator.Atom1Feed(**data)

    report = PaymentHistory.report()
    content = "%s revenue: $%s
%s" % (datetime.datetime.now().strftime('%Y'), report['annual'], report['output'].replace('\n', '
'))

    story = {
        'title': "Daily snapshot: %s" % (datetime.datetime.now().strftime('%A %B %-m, %Y')),
        'link': 'https://www.newsblur.com',
        'description': content,
        'unique_id': datetime.datetime.now().strftime('%A %B %-m, %Y'),
        'pubdate': datetime.datetime.now(),
    }
    rss.add_item(**story)

    logging.user(request, "~FBGenerating Revenue RSS feed: ~FM%s" % (
        request.META.get('HTTP_USER_AGENT', "")[:24]
    ))
    return HttpResponse(rss.writeString('utf-8'), content_type='application/rss+xml')
    <commit_msg>Annual dates<commit_after>import datetime
from django.http import HttpResponse
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.utils import feedgenerator
from apps.statistics.models import MStatistics, MFeedback
from apps.profile.models import PaymentHistory
from utils import log as logging

def dashboard_graphs(request):
    statistics = MStatistics.all()
    return render_to_response('statistics/render_statistics_graphs.xhtml', {
        'statistics': statistics,
    }, context_instance=RequestContext(request))

def feedback_table(request):
    feedbacks = MFeedback.all()
    return render_to_response('statistics/render_feedback_table.xhtml', {
        'feedbacks': feedbacks,
    }, context_instance=RequestContext(request))

def revenue(request):
    data = {}
    data['title'] = "NewsBlur Revenue"
    data['link'] = "https://www.newsblur.com"
    data['description'] = "Revenue"
    data['lastBuildDate'] = datetime.datetime.utcnow()
    data['generator'] = 'NewsBlur Revenue Writer'
    data['docs'] = None
    rss = feedgenerator.Atom1Feed(**data)

    report = PaymentHistory.report()
    content = "%s revenue: $%s
%s" % (datetime.datetime.now().strftime('%Y'), report['annual'], report['output'].replace('\n', '
'))

    story = {
        'title': "Daily snapshot: %s" % (datetime.datetime.now().strftime('%a %b %-m, %Y')),
        'link': 'https://www.newsblur.com',
        'description': content,
        'unique_id': datetime.datetime.now().strftime('%a %b %-m, %Y'),
        'pubdate': datetime.datetime.now(),
    }
    rss.add_item(**story)

    logging.user(request, "~FBGenerating Revenue RSS feed: ~FM%s" % (
        request.META.get('HTTP_USER_AGENT', "")[:24]
    ))
    return HttpResponse(rss.writeString('utf-8'), content_type='application/rss+xml')
    <|endoftext|>


<commit_before>#
# Copyright (C) 2012 Craig Hobbs
#
# See README.md for license.
#

# Class-syntax wrapper around built-in dictionaries.
class Struct(object):

    def __init__(self, _wrap_ = None, **members):

        if _wrap_ is not None:
            assert isinstance(_wrap_, (dict, list, tuple))
            object.__setattr__(self, "_container", _wrap_)
        else:
            object.__setattr__(self, "_container", members)

    def __call__(self):

        return object.__getattribute__(self, "_container")

    def __getattribute__(self, key):

        container = self()
        if isinstance(container, dict):
            return self[key]
        else:
            return type(container).__getattribute__(container, key)

    def __setattr__(self, key, value):

        container = self()
        if isinstance(container, dict):
            self[key] = value
        else:
            return type(container).__setattr__(container, key, value)

    def __getitem__(self, key):

        # Lookup the value in the container - return None if not found
        container = self()
        if isinstance(container, dict):
            value = container.get(key)
        elif isinstance(key, (int, long)) and key >= 0 and key < len(container):
            value = container[key]
        else:
            value = None

        # Return the value - wrap containers
        return Struct(_wrap_ = value) if isinstance(value, (dict, list, tuple)) else value

    def __setitem__(self, key, value):

        # Delete member if value is None
        container = self()
        if value is None:
            if isinstance(container, dict) and key in container:
                del container[key]
            elif isinstance(key, (int, long)) and key >= 0 and key < len(container):
                del container[key]
        else:
            container[key] = value

    def __contains__(self, item):

        return item in self()

    def __len__(self):

        return len(self())

    def __iter__(self):

        class WrapIter:
            def __init__(self, it):
                self._it = it
            def next(self):
                # Return the value - wrap containers
                value = self._it.next()
                return Struct(_wrap_ = value) if isinstance(value, (dict, list, tuple)) else value

        return WrapIter(iter(self()))

    def __cmp__(self, other):

        return cmp(self(), other() if isinstance(other, Struct) else other)
<commit_msg>Don't define classes within functions unless absolutely necessary...<commit_after>#
# Copyright (C) 2012 Craig Hobbs
#
# See README.md for license.
#

# Class-syntax wrapper around built-in dictionaries.
class Struct(object):

    def __init__(self, _wrap_ = None, **members):

        if _wrap_ is not None:
            assert isinstance(_wrap_, (dict, list, tuple))
            object.__setattr__(self, "_container", _wrap_)
        else:
            object.__setattr__(self, "_container", members)

    def __call__(self):

        return object.__getattribute__(self, "_container")

    def __getattribute__(self, key):

        container = self()
        if isinstance(container, dict):
            return self[key]
        else:
            return type(container).__getattribute__(container, key)

    def __setattr__(self, key, value):

        container = self()
        if isinstance(container, dict):
            self[key] = value
        else:
            return type(container).__setattr__(container, key, value)

    def __getitem__(self, key):

        # Lookup the value in the container - return None if not found
        container = self()
        if isinstance(container, dict):
            value = container.get(key)
        elif isinstance(key, (int, long)) and key >= 0 and key < len(container):
            value = container[key]
        else:
            value = None

        # Return the value - wrap containers
        return Struct(_wrap_ = value) if isinstance(value, (dict, list, tuple)) else value

    def __setitem__(self, key, value):

        # Delete member if value is None
        container = self()
        if value is None:
            if isinstance(container, dict) and key in container:
                del container[key]
            elif isinstance(key, (int, long)) and key >= 0 and key < len(container):
                del container[key]
        else:
            container[key] = value

    def __contains__(self, item):

        return item in self()

    def __len__(self):

        return len(self())

    class _WrapIter:
        def __init__(self, it):
            self._it = it
        def next(self):
            # Return the value - wrap containers
            value = self._it.next()
            return Struct(_wrap_ = value) if isinstance(value, (dict, list, tuple)) else value

    def __iter__(self):

        return Struct._WrapIter(iter(self()))

    def __cmp__(self, other):

        return cmp(self(), other() if isinstance(other, Struct) else other)
<|endoftext|>


<commit_before>"""
spaceshooter.py
Author: Roger Danilek
Credit: Adam, Nils, Morgan, Spacewar source code

Assignment:
Write and submit a program that implements the spacewar game:
https://github.com/HHS-IntroProgramming/Spacewar
"""
from ggame import App, RectangleAsset, ImageAsset, Sprite, LineStyle, Color, Frame
import math

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480

class SpaceShip(Sprite):
    """
    Animated space ship
    """
    asset = ImageAsset("images/four_spaceship_by_albertov_with_thrust.png",
        Frame(227,0,292-227,125), 4, 'vertical')

    def __init__(self, position, s):
        super().__init__(SpaceShip.asset, position)
        self.vx = 0
        self.vy = 0
        self.vr = 0
        self.thrust = 0
        self.thrustframe = 1
        self.sun = s
        SpaceGame.listenKeyEvent("keydown", "space", self.thrustOn)
        SpaceGame.listenKeyEvent("keyup", "space", self.thrustOff)
        SpaceGame.listenKeyEvent("keydown", "up arrow", self.goup)
        SpaceGame.listenKeyEvent("keydown", "right arrow", self.turnright)
        SpaceGame.listenKeyEvent("keydown", "left arrow", self.turnleft)
        SpaceGame.listenKeyEvent("keydown", "down arrow", self.goback)

        self.fxcenter = self.fycenter = 0.5

    def step(self):
        self.x += self.vx
        self.y += self.vy
        self.rotation = self.vr
        if self.thrust == 1:
            self.setImage(self.thrustframe)
            self.thrustframe += 1
            if self.thrustframe == 4:
                self.thrustframe = 1
        else:
            self.setImage(0)
        if self.collidingWith(self.sun):
            self.explode()

    def thrustOn(self, event):
        self.thrust = 1

    def thrustOff(self, event):
        self.thrust = 0

    def goup(self, event):
        self.vy+=(-.5*(math.cos(self.rotation)))
        self.vx+=(-.5*(math.sin(self.rotation)))

    def goback(self, event):
        self.vy+=(.5*(math.cos(self.rotation)))
        self.vx+=(.5*(math.sin(self.rotation)))

    def turnright(self, event):
        self.vr-=.4

    def turnleft(self, event):
        self.vr+=.4

    def explode(self):
        explosion(self.position)
        self.destroy()

class explosion(Sprite):
    asset = ImageAsset("images/explosion2.png", Frame(0,0,192-0,195), 25, 'horizontal')
    def __init__(self, position):
        super().__init__(explosion.asset, position)
        self.explosion = 0
        self.explosionframe = 1
    def step(self):
        self.setImage(self.explosionframe)
        self.explosionframe +=1
        if self.explosionframe ==25:
            self.explosionframe = 1

class SpaceGame(App):
    """
    Tutorial4 space game example.
    """
    def __init__(self, width, height):
        super().__init__(width, height)
        black = Color(0, 1)
        noline = LineStyle(0, black)
        bg_asset = ImageAsset("images/starfield.jpg")
        bg = Sprite(bg_asset, (0,0))
        s_asset = ImageAsset("images/sun.png")
        s = Sprite(s_asset, (200,200))
        SpaceShip((100,100),s)

    def step(self):
        for ship in self.getSpritesbyClass(SpaceShip):
            ship.step()
        for explode in self.getSpritesbyClass(explosion):
            explode.step()

myapp = SpaceGame(SCREEN_WIDTH, SCREEN_HEIGHT)
myapp.run()

<commit_msg>Updated from Brython Server: November 10, 2015 7:35:22 PM GMT-5<commit_after>"""
spaceshooter.py
Author: Roger Danilek
Credit: Adam, Nils, Morgan, Spacewar source code

Assignment:
Write and submit a program that implements the spacewar game:
https://github.com/HHS-IntroProgramming/Spacewar
"""
from ggame import App, RectangleAsset, ImageAsset, Sprite, LineStyle, Color, Frame
import math

SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480

class SpaceShip(Sprite):
    """
    Animated space ship
    """
    asset = ImageAsset("images/four_spaceship_by_albertov_with_thrust.png",
        Frame(227,0,292-227,125), 4, 'vertical')

    def __init__(self, position, s):
        super().__init__(SpaceShip.asset, position)
        self.vx = 0
        self.vy = 0
        self.vr = 0
        self.thrust = 0
        self.thrustframe = 1
        self.sun = s
        SpaceGame.listenKeyEvent("keydown", "space", self.thrustOn)
        SpaceGame.listenKeyEvent("keyup", "space", self.thrustOff)
        SpaceGame.listenKeyEvent("keydown", "up arrow", self.goup)
        SpaceGame.listenKeyEvent("keydown", "right arrow", self.turnright)
        SpaceGame.listenKeyEvent("keydown", "left arrow", self.turnleft)
        SpaceGame.listenKeyEvent("keydown", "down arrow", self.goback)

        self.fxcenter = self.fycenter = 0.5

    def step(self):
        self.x += self.vx
        self.y += self.vy
        self.rotation = self.vr
        if self.thrust == 1:
            self.setImage(self.thrustframe)
            self.thrustframe += 1
            if self.thrustframe == 4:
                self.thrustframe = 1
        else:
            self.setImage(0)
        if self.collidingWith(self.sun):
            self.explode()

    def thrustOn(self, event):
        self.thrust = 1

    def thrustOff(self, event):
        self.thrust = 0

    def goup(self, event):
        self.vy+=(-.5*(math.cos(self.rotation)))
        self.vx+=(-.5*(math.sin(self.rotation)))

    def goback(self, event):
        self.vy+=(.5*(math.cos(self.rotation)))
        self.vx+=(.5*(math.sin(self.rotation)))

    def turnright(self, event):
        self.vr-=.4

    def turnleft(self, event):
        self.vr+=.4

    def explode(self):
        explosion(self.position)
        self.destroy()

class explosion(Sprite):
    asset = ImageAsset("images/explosion2.png", Frame(0,0,192-0,195), 25, 'horizontal')
    def __init__(self, position):
        super().__init__(explosion.asset, position)
        self.explosion = 0
        self.explosionframe = 1
    def step(self):
        self.setImage(self.explosionframe)
        self.explosionframe +=1
        if self.explosionframe ==25:
            self.explosionframe = 1
        else:
            self.setImage(0)

class SpaceGame(App):
    """
    Tutorial4 space game example.
    """
    def __init__(self, width, height):
        super().__init__(width, height)
        black = Color(0, 1)
        noline = LineStyle(0, black)
        bg_asset = ImageAsset("images/starfield.jpg")
        bg = Sprite(bg_asset, (0,0))
        s_asset = ImageAsset("images/sun.png")
        s = Sprite(s_asset, (200,200))
        SpaceShip((100,100),s)

    def step(self):
        for ship in self.getSpritesbyClass(SpaceShip):
            ship.step()
        for explode in self.getSpritesbyClass(explosion):
            explode.step()

myapp = SpaceGame(SCREEN_WIDTH, SCREEN_HEIGHT)
myapp.run()

<|endoftext|>


<commit_before># Copyright 2009 Wayne See
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from pychmlib.chm import chm

import socket
import thread
import hhc

HOST = '127.0.0.1'
PORT = 8081

TYPES = {".gif":"image/gif",
         ".jpg":"image/jpeg",
         ".mht":"multipart/related",
         ".html":"text/html",
         ".htm":"text/html"
         }

ERR_NO_HHC = 1
ERR_INVALID_CHM = 2

LOCK = thread.allocate_lock()

STOP_SERVER = False

def start(filename, hhc_callback=None):
    thread.start_new_thread(_serve_chm, (HOST, PORT, filename, hhc_callback))

def stop():
    if LOCK.locked():
        global STOP_SERVER
        STOP_SERVER = True
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            #request shutdown signal
            sock.connect((HOST, PORT))
            sock.close()
            LOCK.acquire() #block method until we are sure server stops
            LOCK.release()
        except:
            pass #cannot connect to server

def _serve_chm(hostname, port, filename, hhc_callback=None):
    LOCK.acquire()
    try:
        try:
            chm_file = chm(filename)
        except Exception, e:
            hhc_callback(error=ERR_INVALID_CHM)
            return
        if hhc_callback:
            hhc_file = chm_file.get_hhc()
            if hhc_file:
                contents = hhc.parse(hhc_file.get_content())
                encoding = chm_file.encoding
                hhc_callback(filename, contents, encoding)
            else:
                chm_file.close()
                hhc_callback(error=ERR_NO_HHC)
                return #no hhc, so what's the sense of continuing?
        try:
            _serve_chm_forever(chm_file, hostname, port)
        except Exception, e:
            # server shutting down because of error
            pass
    finally:
        LOCK.release()

def _serve_chm_forever(chm_file, hostname, port):
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind((hostname, port))
        sock.listen(5)
        try:
            while 1:
                csock, caddr = sock.accept()
                if STOP_SERVER:
                    break
                _service(csock, chm_file)
        finally:
            sock.close()
    finally:
        chm_file.close()

def _read_request(remote):
    return remote.recv(128).strip()

def _write_response(remote, chm_file, filename, type):
    try:
        if STOP_SERVER:
            return
        ui = chm_file.resolve_object(filename)
        if ui:
            if STOP_SERVER:
                return
            _respond(ui.get_content(), remote, type)
        else:
            _respond_not_found(remote)
    except:
        _respond_error(remote)

def _service(csock, chm_file):
    try:
        line = _read_request(csock)
        filename = line[line.find("/"):line.find(" HTTP/")].lower()
        extension = filename[filename.rfind("."):]
        type = TYPES.get(extension, "text/html")
        _write_response(csock, chm_file, filename, type)
    except socket.error:
        csock.close()
    else:
        csock.close()

_HTTP_RESPONSE = """HTTP/1.1 200 OK
Content-Length: %d
Content-Type: %s

%s"""

def _respond(content, remote, type="text/html"):
    remote.sendall(_HTTP_RESPONSE % (len(content), type, content))

def _respond_error(cfile):
    _respond("Page could not be displayed", cfile)

def _respond_not_found(cfile):
    _respond("Page could not be found", cfile)

if __name__ == '__main__':
    import sys
    filenames = sys.argv[1:]
    if filenames:
        start(filenames.pop())
        #serve chm files for 30 seconds
        import time
        time.sleep(30)
        stop()
    else:
        print "Please provide a CHM file as parameter"<commit_msg>changed newline to use CRLF in http response<commit_after># Copyright 2009 Wayne See
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from pychmlib.chm import chm

import socket
import thread
import hhc

HOST = '127.0.0.1'
PORT = 8081

TYPES = {".gif":"image/gif",
         ".jpg":"image/jpeg",
         ".mht":"multipart/related",
         ".html":"text/html",
         ".htm":"text/html"
         }

ERR_NO_HHC = 1
ERR_INVALID_CHM = 2

LOCK = thread.allocate_lock()

STOP_SERVER = False

def start(filename, hhc_callback=None):
    thread.start_new_thread(_serve_chm, (HOST, PORT, filename, hhc_callback))

def stop():
    if LOCK.locked():
        global STOP_SERVER
        STOP_SERVER = True
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            #request shutdown signal
            sock.connect((HOST, PORT))
            sock.close()
            LOCK.acquire() #block method until we are sure server stops
            LOCK.release()
        except:
            pass #cannot connect to server

def _serve_chm(hostname, port, filename, hhc_callback=None):
    LOCK.acquire()
    try:
        try:
            chm_file = chm(filename)
        except Exception, e:
            hhc_callback(error=ERR_INVALID_CHM)
            return
        if hhc_callback:
            hhc_file = chm_file.get_hhc()
            if hhc_file:
                contents = hhc.parse(hhc_file.get_content())
                encoding = chm_file.encoding
                hhc_callback(filename, contents, encoding)
            else:
                chm_file.close()
                hhc_callback(error=ERR_NO_HHC)
                return #no hhc, so what's the sense of continuing?
        try:
            _serve_chm_forever(chm_file, hostname, port)
        except Exception, e:
            # server shutting down because of error
            pass
    finally:
        LOCK.release()

def _serve_chm_forever(chm_file, hostname, port):
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.bind((hostname, port))
        sock.listen(5)
        try:
            while 1:
                csock, caddr = sock.accept()
                if STOP_SERVER:
                    break
                _service(csock, chm_file)
        finally:
            sock.close()
    finally:
        chm_file.close()

def _read_request(remote):
    return remote.recv(128).strip()

def _write_response(remote, chm_file, filename, type):
    try:
        if STOP_SERVER:
            return
        ui = chm_file.resolve_object(filename)
        if ui:
            if STOP_SERVER:
                return
            _respond(ui.get_content(), remote, type)
        else:
            _respond_not_found(remote)
    except:
        _respond_error(remote)

def _service(csock, chm_file):
    try:
        line = _read_request(csock)
        filename = line[line.find("/"):line.find(" HTTP/")].lower()
        extension = filename[filename.rfind("."):]
        type = TYPES.get(extension, "text/html")
        _write_response(csock, chm_file, filename, type)
    except socket.error:
        csock.close()
    else:
        csock.close()

_HTTP_RESPONSE = "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: %s\r\n\r\n%s"

def _respond(content, remote, type="text/html"):
    remote.sendall(_HTTP_RESPONSE % (len(content), type, content))

def _respond_error(cfile):
    _respond("Page could not be displayed", cfile)

def _respond_not_found(cfile):
    _respond("Page could not be found", cfile)

if __name__ == '__main__':
    import sys
    filenames = sys.argv[1:]
    if filenames:
        start(filenames.pop())
        #serve chm files for 30 seconds
        import time
        time.sleep(30)
        stop()
    else:
        print "Please provide a CHM file as parameter"<|endoftext|>


<commit_before>"""
Registry for Djax integrations.
"""
from django.conf import settings
import inspect
from django.db.models import Model
import logging

log = logging.getLogger('djax')

content_registry = {}

class MalformedRegistry(Exception):
    """
    Indicates the Djax registry has been corrupted.
    """

def get_module(module_name):
    """
    Imports and returns the named module.
    """
    module = __import__(module_name)
    components = module_name.split('.')
    for comp in components[1:]:
        module = getattr(module,comp)
    return module

def build_registry():
    """
    Builds the registry.
    """
    from djax.content import AxilentContent

    for app_path in settings.INSTALLED_APPS:
        if app_path != 'djax': # don't load yourself
            try:
                module = get_module('%s.models' % app_path)
                for name, attribute in inspect.getmembers(module):
                    if inspect.isclass(attribute) and issubclass(attribute,Model) and issubclass(attribute,AxilentContent):
                        # this is a content model, add to registry
                        try:
                            content_registry[attribute.Axilent.content_type] = attribute
                        except AttributeError:
                            raise MalformedRegistry('All Axilent content mappings must be defined with an "Axilent" inner class with a "content_type" attribute.')
            except ImportError:
                log.warn('Cannot import %s.  Skipping.' % app_path)
<commit_msg>debug<commit_after>"""
Registry for Djax integrations.
"""
from django.conf import settings
import inspect
from django.db.models import Model
import logging

log = logging.getLogger('djax')

content_registry = {}

class MalformedRegistry(Exception):
    """
    Indicates the Djax registry has been corrupted.
    """

def get_module(module_name):
    """
    Imports and returns the named module.
    """
    module = __import__(module_name)
    components = module_name.split('.')
    for comp in components[1:]:
        module = getattr(module,comp)
    return module

def build_registry():
    """
    Builds the registry.
    """
    from djax.content import AxilentContent

    for app_path in settings.INSTALLED_APPS:
        print 'examing app',app_path
        if app_path != 'djax': # don't load yourself
            try:
                print 'loading axilent content mappings for',app_path
                module = get_module('%s.models' % app_path)
                for name, attribute in inspect.getmembers(module):
                    print 'inspecting attribute',name
                    if inspect.isclass(attribute) and issubclass(attribute,Model) and issubclass(attribute,AxilentContent):
                        # this is a content model, add to registry
                        try:
                            print 'adding',name,'to content registry'
                            content_registry[attribute.Axilent.content_type] = attribute
                        except AttributeError:
                            raise MalformedRegistry('All Axilent content mappings must be defined with an "Axilent" inner class with a "content_type" attribute.')
            except ImportError:
                print 'cannot import',app_path,'skipping'
                log.warn('Cannot import %s.  Skipping.' % app_path)
<|endoftext|>


<commit_before>from django.template import RequestContext
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseForbidden
from django.template import RequestContext, Context, loader
from sentry.client.models import get_client
import logging

class Http403(Exception):
    pass

def render_to_403(*args, **kwargs):
    """
        Returns a HttpResponseForbidden whose content is filled with the result of calling
        django.template.loader.render_to_string() with the passed arguments.
    """
    if not isinstance(args,list):
        args = []
        args.append('403.html')

    httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)}
    response = HttpResponseForbidden(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)

    return response

class Http403Middleware(object):
    def process_exception(self,request,exception):
        if isinstance(exception,Http403):
            #if settings.DEBUG:
            #    raise PermissionDenied
            return render_to_403(context_instance=RequestContext(request))

class TuranSentry404CatchMiddleware(object):
    def process_response(self, request, response):
        if response.status_code == 404 and request.META.get('HTTP_REFERER', ''):
            message_id = get_client().create_from_text('Http 404 %s' %request.path, request=request, level=logging.INFO, logger='http404')
            request.sentry = {
                'id': message_id,
                }
        return response

class TuranSentryMarkup(object):
    '''Add more information to the sentry log'''

    def process_exception(self, request, exception):
        # Make sure the exception signal is fired for Sentry
        if request.user:
            request.META['TURANUSER'] = request.user
        return None
<commit_msg>Log user name for 404s too<commit_after>from django.template import RequestContext
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseForbidden
from django.template import RequestContext, Context, loader
from sentry.client.models import get_client
import logging

class Http403(Exception):
    pass

def render_to_403(*args, **kwargs):
    """
        Returns a HttpResponseForbidden whose content is filled with the result of calling
        django.template.loader.render_to_string() with the passed arguments.
    """
    if not isinstance(args,list):
        args = []
        args.append('403.html')

    httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)}
    response = HttpResponseForbidden(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)

    return response

class Http403Middleware(object):
    def process_exception(self,request,exception):
        if isinstance(exception,Http403):
            #if settings.DEBUG:
            #    raise PermissionDenied
            return render_to_403(context_instance=RequestContext(request))

class TuranSentry404CatchMiddleware(object):
    def process_response(self, request, response):
        if response.status_code == 404 and request.META.get('HTTP_REFERER', ''):
            request.META['TURANUSER'] = request.user
            message_id = get_client().create_from_text('Http 404 %s' %request.path, request=request, level=logging.INFO, logger='http404')
            request.sentry = {
                'id': message_id,
                }
        return response

class TuranSentryMarkup(object):
    '''Add more information to the sentry log'''

    def process_exception(self, request, exception):
        # Make sure the exception signal is fired for Sentry
        if request.user:
            request.META['TURANUSER'] = request.user
        return None
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#
# Copyright (C) 2005-2009 Edgewall Software
# Copyright (C) 2005-2006 Christian Boos <cboos@neuf.fr>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author: Christian Boos <cboos@neuf.fr>

import re

from genshi.builder import Element, tag

from trac.core import *
from trac.mimeview import Context
from trac.perm import PermissionError
from trac.util.translation import _
from trac.web import IRequestHandler
from trac.wiki.api import IWikiMacroProvider
from trac.wiki.formatter import extract_link

class InterTracDispatcher(Component):
    """InterTrac dispatcher."""

    implements(IRequestHandler, IWikiMacroProvider)

    # IRequestHandler methods

    def match_request(self, req):
        match = re.match(r'^/intertrac/(.*)', req.path_info)
        if match:
            if match.group(1):
                req.args['link'] = match.group(1)
            return True

    def process_request(self, req):
        link = req.args.get('link', '')
        parts = link.split(':', 1)
        if len(parts) > 1:
            resolver, target = parts
            if target and (target[0] not in '\'"' or target[0] != target[-1]):
                link = '%s:"%s"' % (resolver, target)
        link_elt = extract_link(self.env, Context.from_request(req), link)
        if isinstance(link_elt, Element):
            href = link_elt.attrib.get('href')
            if href is None: # most probably no permissions to view
                raise PermissionError(_("Can't view %(link)s:", link=link))
        else:
            href = req.href(link.rstrip(':'))
        req.redirect(href)

    # IWikiMacroProvider methods

    def get_macros(self):
        yield 'InterTrac'

    def get_macro_description(self, name):
        return "Provide a list of known InterTrac prefixes."

    def expand_macro(self, formatter, name, content):
        intertracs = {}
        for key, value in self.config.options('intertrac'):
            idx = key.rfind('.') # rsplit only in 2.4
            if idx > 0: # 0 itself doesn't help much: .xxx = ...
                prefix, attribute = key[:idx], key[idx+1:]
                intertrac = intertracs.setdefault(prefix, {})
                intertrac[attribute] = value
            else:
                intertracs[key] = value # alias

        def generate_prefix(prefix):
            intertrac = intertracs[prefix]
            if isinstance(intertrac, basestring):
                yield tag.tr(tag.td(tag.b(prefix)),
                             tag.td('Alias for ', tag.b(intertrac)))
            else:
                url = intertrac.get('url', '')
                if url:
                    title = intertrac.get('title', url)
                    yield tag.tr(tag.td(tag.a(tag.b(prefix),
                                              href=url + '/timeline')),
                                 tag.td(tag.a(title, href=url)))

        return tag.table(class_="wiki intertrac")(
            tag.tr(tag.th(tag.em('Prefix')), tag.th(tag.em('Trac Site'))),
            [generate_prefix(p) for p in sorted(intertracs.keys())])
<commit_msg>0.12.1dev: Fixed InterTrac to also work with links that generate a `Fragment` instead of an `Element` (`attachment:`, `source:`), by finding the first tag containing an `href` attribute.<commit_after># -*- coding: utf-8 -*-
#
# Copyright (C) 2005-2009 Edgewall Software
# Copyright (C) 2005-2006 Christian Boos <cboos@neuf.fr>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author: Christian Boos <cboos@neuf.fr>

import re

from genshi.builder import Element, Fragment, tag

from trac.core import *
from trac.mimeview import Context
from trac.perm import PermissionError
from trac.util.translation import _
from trac.web import IRequestHandler
from trac.wiki.api import IWikiMacroProvider
from trac.wiki.formatter import extract_link

class InterTracDispatcher(Component):
    """InterTrac dispatcher."""

    implements(IRequestHandler, IWikiMacroProvider)

    # IRequestHandler methods

    def match_request(self, req):
        match = re.match(r'^/intertrac/(.*)', req.path_info)
        if match:
            if match.group(1):
                req.args['link'] = match.group(1)
            return True

    def process_request(self, req):
        link = req.args.get('link', '')
        parts = link.split(':', 1)
        if len(parts) > 1:
            resolver, target = parts
            if target and (target[0] not in '\'"' or target[0] != target[-1]):
                link = '%s:"%s"' % (resolver, target)
        link_frag = extract_link(self.env, Context.from_request(req), link)

        def get_first_href(item):
            """Depth-first search for the first `href` attribute."""
            if isinstance(item, Element):
                href = item.attrib.get('href')
                if href is not None:
                    return href
            if isinstance(item, Fragment):
                for each in item.children:
                    href = get_first_href(each)
                    if href is not None:
                        return href

        if isinstance(link_frag, (Element, Fragment)):
            href = get_first_href(link_frag)
            if href is None: # most probably no permissions to view
                raise PermissionError(_("Can't view %(link)s:", link=link))
        else:
            href = req.href(link.rstrip(':'))
        req.redirect(href)

    # IWikiMacroProvider methods

    def get_macros(self):
        yield 'InterTrac'

    def get_macro_description(self, name):
        return "Provide a list of known InterTrac prefixes."

    def expand_macro(self, formatter, name, content):
        intertracs = {}
        for key, value in self.config.options('intertrac'):
            idx = key.rfind('.') # rsplit only in 2.4
            if idx > 0: # 0 itself doesn't help much: .xxx = ...
                prefix, attribute = key[:idx], key[idx+1:]
                intertrac = intertracs.setdefault(prefix, {})
                intertrac[attribute] = value
            else:
                intertracs[key] = value # alias

        def generate_prefix(prefix):
            intertrac = intertracs[prefix]
            if isinstance(intertrac, basestring):
                yield tag.tr(tag.td(tag.b(prefix)),
                             tag.td('Alias for ', tag.b(intertrac)))
            else:
                url = intertrac.get('url', '')
                if url:
                    title = intertrac.get('title', url)
                    yield tag.tr(tag.td(tag.a(tag.b(prefix),
                                              href=url + '/timeline')),
                                 tag.td(tag.a(title, href=url)))

        return tag.table(class_="wiki intertrac")(
            tag.tr(tag.th(tag.em('Prefix')), tag.th(tag.em('Trac Site'))),
            [generate_prefix(p) for p in sorted(intertracs.keys())])
<|endoftext|>


<commit_before>import re

from django.utils.encoding import smart_str

MAXVERSION = 2 ** 63

version_re = re.compile(r"""(?P<major>\d+)         # major (x in x.y)
                            \.?(?P<minor1>\d+|\*)? # minor1 (y in x.y)
                            \.?(?P<minor2>\d+|\*)? # minor2 (z in x.y.z)
                            \.?(?P<minor3>\d+|\*)? # minor3 (w in x.y.z.w)
                            (?P<alpha>[a|b]?)      # alpha/beta
                            (?P<alpha_ver>\d*)     # alpha/beta version
                            (?P
pre)?          # pre release
                            (?P<pre_ver>\d)?       # pre release version
                        """,
                        re.VERBOSE)

def dict_from_int(version_int):
    """Converts a version integer into a dictionary with major/minor/...
    info."""
    d = {}
    rem = version_int
    (rem, d['pre_ver']) = divmod(rem, 100)
    (rem, d['pre']) = divmod(rem, 10)
    (rem, d['alpha_ver']) = divmod(rem, 100)
    (rem, d['alpha']) = divmod(rem, 10)
    (rem, d['minor3']) = divmod(rem, 100)
    (rem, d['minor2']) = divmod(rem, 100)
    (rem, d['minor1']) = divmod(rem, 100)
    (rem, d['major']) = divmod(rem, 100)
    d['pre'] = None if d['pre'] else 'pre'
    d['alpha'] = {0: 'a', 1: 'b'}.get(d['alpha'])

    return d

def num(vint):
    return '{major}.{minor1}.{minor2}.{minor3}'.format(**dict_from_int(vint))

def version_dict(version):
    """Turn a version string into a dict with major/minor/... info."""
    match = version_re.match(version or '')
    letters = 'alpha pre'.split()
    numbers = 'major minor1 minor2 minor3 alpha_ver pre_ver'.split()
    if match:
        d = match.groupdict()
        for letter in letters:
            d[letter] = d[letter] if d[letter] else None
        for num in numbers:
            if d[num] == '*':
                d[num] = 99
            else:
                d[num] = int(d[num]) if d[num] else None
    else:
        d = dict((k, None) for k in numbers)
        d.update((k, None) for k in letters)
    return d

def version_int(version):
    d = version_dict(smart_str(version))
    for key in ['alpha_ver', 'major', 'minor1', 'minor2', 'minor3',
                'pre_ver']:
        if not d[key]:
            d[key] = 0
    atrans = {'a': 0, 'b': 1}
    d['alpha'] = atrans.get(d['alpha'], 2)
    d['pre'] = 0 if d['pre'] else 1

    v = "%d%02d%02d%02d%d%02d%d%02d" % (d['major'], d['minor1'],
            d['minor2'], d['minor3'], d['alpha'], d['alpha_ver'], d['pre'],
            d['pre_ver'])
    return min(int(v), MAXVERSION)
<commit_msg>Change MAXVERSION to fit into elasticsearch<commit_after>import re

from django.utils.encoding import smart_str

MAXVERSION = 2 ** 63 - 1

version_re = re.compile(r"""(?P<major>\d+)         # major (x in x.y)
                            \.?(?P<minor1>\d+|\*)? # minor1 (y in x.y)
                            \.?(?P<minor2>\d+|\*)? # minor2 (z in x.y.z)
                            \.?(?P<minor3>\d+|\*)? # minor3 (w in x.y.z.w)
                            (?P<alpha>[a|b]?)      # alpha/beta
                            (?P<alpha_ver>\d*)     # alpha/beta version
                            (?P
pre)?          # pre release
                            (?P<pre_ver>\d)?       # pre release version
                        """,
                        re.VERBOSE)

def dict_from_int(version_int):
    """Converts a version integer into a dictionary with major/minor/...
    info."""
    d = {}
    rem = version_int
    (rem, d['pre_ver']) = divmod(rem, 100)
    (rem, d['pre']) = divmod(rem, 10)
    (rem, d['alpha_ver']) = divmod(rem, 100)
    (rem, d['alpha']) = divmod(rem, 10)
    (rem, d['minor3']) = divmod(rem, 100)
    (rem, d['minor2']) = divmod(rem, 100)
    (rem, d['minor1']) = divmod(rem, 100)
    (rem, d['major']) = divmod(rem, 100)
    d['pre'] = None if d['pre'] else 'pre'
    d['alpha'] = {0: 'a', 1: 'b'}.get(d['alpha'])

    return d

def num(vint):
    return '{major}.{minor1}.{minor2}.{minor3}'.format(**dict_from_int(vint))

def version_dict(version):
    """Turn a version string into a dict with major/minor/... info."""
    match = version_re.match(version or '')
    letters = 'alpha pre'.split()
    numbers = 'major minor1 minor2 minor3 alpha_ver pre_ver'.split()
    if match:
        d = match.groupdict()
        for letter in letters:
            d[letter] = d[letter] if d[letter] else None
        for num in numbers:
            if d[num] == '*':
                d[num] = 99
            else:
                d[num] = int(d[num]) if d[num] else None
    else:
        d = dict((k, None) for k in numbers)
        d.update((k, None) for k in letters)
    return d

def version_int(version):
    d = version_dict(smart_str(version))
    for key in ['alpha_ver', 'major', 'minor1', 'minor2', 'minor3',
                'pre_ver']:
        if not d[key]:
            d[key] = 0
    atrans = {'a': 0, 'b': 1}
    d['alpha'] = atrans.get(d['alpha'], 2)
    d['pre'] = 0 if d['pre'] else 1

    v = "%d%02d%02d%02d%d%02d%d%02d" % (d['major'], d['minor1'],
            d['minor2'], d['minor3'], d['alpha'], d['alpha_ver'], d['pre'],
            d['pre_ver'])
    return min(int(v), MAXVERSION)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

import time
import hashlib
import pickle
from threading import RLock

cache = {}

def is_obsolete(entry, duration):
    return time.time() - entry['time'] > duration

def compute_key(function, args, kwargs):
    key = pickle.dumps((function.func_name, args, kwargs))
    return hashlib.sha1(key).hexdigest()

def memoize(duration=10, interval=50):
    gc = GC(duration, interval)
    def _memoize(function):
        def __memoize(*args, **kwargs):
            gc()
            key = compute_key(function, args, kwargs)
            entry = cache.get(key, None)
            if entry is not None and not is_obsolete(entry, duration):
                return entry['value']
            result = function(*args, **kwargs)
            cache[key] = {'value': result, 'time': time.time()}
            return result
        return __memoize
    return _memoize

class GC(object):
    def __init__(self, duration=10, interval=50):
        self.duration = duration
        self.interval = interval
        self.lock = RLock()
        self.count = self.interval

    def __call__(self):
        self.count -= 1
        if self.count > 0:
            return
        if not self.lock.acquire(False):
            return
        try:
            self.count = self.interval
            for key in cache.keys():
                entry = cache.get(key, None)
                if entry is not None and is_obsolete(entry, duration):
                    cache.pop(entry, None)
        finally:
            lock.release()
<commit_msg>change to reset timeout of the cache entry when reading it<commit_after># -*- coding: utf-8 -*-

import time
import hashlib
import pickle
from threading import RLock

cache = {}

def is_obsolete(entry, duration):
    return time.time() - entry['time'] > duration

def compute_key(function, args, kwargs):
    key = pickle.dumps((function.func_name, args, kwargs))
    return hashlib.sha1(key).hexdigest()

def memoize(duration=10, interval=50):
    gc = GC(duration, interval)
    def _memoize(function):
        def __memoize(*args, **kwargs):
            gc()
            key = compute_key(function, args, kwargs)
            entry = cache.get(key, None)
            if entry is not None and not is_obsolete(entry, duration):
                entry['time'] = time.time()
                return entry['value']
            result = function(*args, **kwargs)
            cache[key] = {'value': result, 'time': time.time()}
            return result
        return __memoize
    return _memoize

class GC(object):
    def __init__(self, duration=10, interval=50):
        self.duration = duration
        self.interval = interval
        self.lock = RLock()
        self.count = self.interval

    def __call__(self):
        self.count -= 1
        if self.count > 0:
            return
        if not self.lock.acquire(False):
            return
        try:
            self.count = self.interval
            for key in cache.keys():
                entry = cache.get(key, None)
                if entry is not None and is_obsolete(entry, duration):
                    cache.pop(entry, None)
        finally:
            lock.release()
<|endoftext|>