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

from django.db import models
from django.core.urlresolvers import reverse
from django.utils import timezone
from django.utils.translation import get_language, ugettext_lazy as _
from django.utils.encoding import python_2_unicode_compatible

from mptt.models import MPTTModel, TreeForeignKey
from hvad.models import TranslatableModel, TranslatedFields
from hvad.manager import TranslationManager
from taggit.managers import TaggableManager
from taggit.models import TagBase, ItemBase
from cms.models.fields import PlaceholderField
from filer.fields.image import FilerImageField

from blogit import settings as bs
from blogit.utils.translation import get_translation
from blogit.utils.noconflict import classmaker

# Author.
@python_2_unicode_compatible
class Author(TranslatableModel):
    slug = models.SlugField(
        _('slug'), max_length=100, unique=True,
        help_text=_('Text used in the url.'))
    user = models.ForeignKey(
        bs.AUTH_USER_MODEL, blank=True, null=True, unique=True,
        verbose_name=_('user'), help_text=_(
            'If selected, fields "First name", "Last name" and '
            '"Email address" will fallback tu "User" values if they are '
            'left empty.'))
    first_name = models.CharField(
        _('first name'), max_length=30, blank=True, null=True)
    last_name = models.CharField(
        _('last name'), max_length=30, blank=True, null=True)
    email = models.EmailField(_('email address'), blank=True, null=True)
    picture = FilerImageField(
        blank=True, null=True, related_name='author_image',
        verbose_name=_('picture'))

    translations = TranslatedFields(
        description=models.TextField(_('description'), blank=True, null=True),
    )

    bio = PlaceholderField(
        'blogit_author_bio', verbose_name=_('bio'))

    class Meta:
        db_table = 'blogit_authors'
        verbose_name = _('author')
        verbose_name_plural = _('authors')

    def __str__(self):
        name = self.get_full_name()
        if not name and self.user and self.user.username:
            name = self.user.username
        return name or 'Author: {}'.format(self.pk)

    def get_absolute_url(self, language=None):
        if not language:
            language = get_language()

        return reverse('blogit_author_detail', kwargs={
            'url': get_translation(
                bs.AUTHOR_URL, bs.AUTHOR_URL_TRANSLATION, language),
            'slug': self.get_slug()
        })

    def get_full_name(self):
        # Returns first_name plus last_name, with a space in between.
        name = '{} {}'.format(self.get_first_name(), self.get_last_name())
        return name.strip()

    def get_first_name(self):
        # Returns first_name, fallbacks to users first_name.
        if not self.first_name and self.user and self.user.first_name:
            return self.user.first_name
        return self.first_name or ''

    def get_last_name(self):
        # Returns last_name, fallbacks to users last_name.
        if not self.last_name and self.user and self.user.last_name:
            return self.user.last_name
        return self.last_name or ''

    def get_email(self):
        # Returns email, fallbacks to users email.
        if not self.email and self.user and self.user.email:
            return self.user.email
        return self.email or ''

    def get_posts(self):
        # Returns all posts by author.
        return Post.objects.public().filter(author=self)

@python_2_unicode_compatible
class AuthorLink(models.Model):
    author = models.ForeignKey(
        Author, related_name='links', verbose_name=_('author'))
    link_type = models.CharField(
        _('type'), max_length=255, blank=True, null=True,
        choices=bs.AUTHOR_LINK_TYPE_CHOICES)
    url = models.URLField(_('url'))

    class Meta:
        db_table = 'blogit_author_links'
        verbose_name = _('link')
        verbose_name_plural = _('links')
        ordering = ('pk',)

    def __str__(self):
        return self.url

    @property
    def type(self):
        return self.link_type

# Category.
@python_2_unicode_compatible
class Category(TranslatableModel, MPTTModel):
    __metaclass__ = classmaker()

    parent = TreeForeignKey(
        'self', blank=True, null=True, related_name='children', db_index=True)

    date_created = models.DateTimeField(
        _('date created'), default=timezone.now)
    last_modified = models.DateTimeField(
        _('last modified'), default=timezone.now)

    translations = TranslatedFields(
        title=models.CharField(_('title'), max_length=255),
        slug=models.SlugField(_('slug'), max_length=255),
    )

    class Meta:
        db_table = 'blogit_categories'
        verbose_name = _('category')
        verbose_name_plural = _('categories')
        ordering = ('date_created',)

    class MPTTMeta:
        pass

    def __str__(self):
        return self.lazy_translation_getter(
            'title', '{}: {}'.format(_('Category'), self.pk))

    def save(self, *args, **kwargs):
        self.last_modified = timezone.now()
        super(Category, self).save(*args, **kwargs)

    def get_absolute_url(self, language=None):
        if not language:
            language = get_language()

        return reverse('blogit_category_detail', kwargs={
            'url': get_translation(
                bs.CATEGORY_URL, bs.CATEGORY_URL_TRANSLATION, language),
            'slug': self.get_slug()
        })

    def get_slug(self):
        return self.lazy_translation_getter('slug')

# Tag.
@python_2_unicode_compatible
class Tag(TagBase):
    class Meta:
        db_table = 'blogit_tags'
        verbose_name = _('tag')
        verbose_name_plural = _('tags')
        ordering = ('name',)

    def __str__(self):
        return self.name

    def get_absolute_url(self, language=None):
        if not language:
            language = get_language()

        return reverse('blogit_tag_detail', kwargs={
            'url': get_translation(
                bs.TAG_URL, bs.TAG_URL_TRANSLATION, language),
            'slug': self.slug
        })

@python_2_unicode_compatible
class TaggedPost(ItemBase):
    tag = models.ForeignKey(
        Tag, related_name="tagged_posts", verbose_name=_('tag'))
    content_object = models.ForeignKey(
        'PostTranslation', verbose_name=_('post'))

    class Meta:
        db_table = 'blogit_tagged_post_translations'
        verbose_name = _('tagged post')
        verbose_name_plural = _('tagged posts')

    def __str__(self):
        return self.content_object.title

    @classmethod
    def tags_for(cls, model, instance=None):
        if instance is not None:
            return cls.tag_model().objects.filter(**{
                '%s__content_object' % cls.tag_relname(): instance
            })
        return cls.tag_model().objects.filter(**{
            '%s__content_object__isnull' % cls.tag_relname(): False
        }).distinct()

# Post.
class PostManager(TranslationManager):
    def public(self, language_code=None):
        queryset = self.language(language_code)
        return queryset.filter(is_public=True)

@python_2_unicode_compatible
class Post(TranslatableModel):
    category = models.ForeignKey(
        Category, blank=True, null=True, on_delete=models.SET_NULL,
        verbose_name=_('category'))
    author = models.ForeignKey(
        Author, blank=True, null=True, on_delete=models.SET_NULL,
        verbose_name=_('author'))
    featured_image = FilerImageField(
        blank=True, null=True, verbose_name=_('featured image'))
    date_created = models.DateTimeField(
        _('date created'), blank=True, null=True, default=timezone.now)
    last_modified = models.DateTimeField(
        _('last modified'), default=timezone.now)
    date_published = models.DateTimeField(
        _('date published'), default=timezone.now)

    translations = TranslatedFields(
        title=models.CharField(_('title'), max_length=255),
        slug=models.SlugField(
            _('slug'), max_length=255,
            help_text=_('Text used in the url.')),
        is_public=models.BooleanField(
            _('is public'), default=True,
            help_text=_('Designates whether the post is visible to the '
                        'public.')),
        subtitle=models.CharField(
            _('subtitle'), max_length=255, blank=True, null=True),
        description=models.TextField(
            _('description'), blank=True, null=True),
        tags=TaggableManager(
            through=TaggedPost, blank=True, verbose_name=_('tags')),
        meta_title=models.CharField(
            _('page title'), max_length=255, blank=True, null=True,
            help_text=_('Overwrites what is displayed at the top of your '
                        'browser or in bookmarks.')),
        meta_description=models.TextField(
            _('description meta tag'), blank=True, null=True,
            help_text=_('A description of the page sometimes used by '
                        'search engines.')),
        meta_keywords=models.CharField(
            _('keywords meta tag'), max_length=255, blank=True, null=True,
            help_text=_('A list of comma separated keywords sometimes used '
                        'by search engines.')),
    )

    content = PlaceholderField(
        'blogit_post_content', verbose_name=_('content'))

    objects = PostManager()

    class Meta:
        db_table = 'blogit_posts'
        verbose_name = _('post')
        verbose_name_plural = _('posts')

    def __str__(self):
        return self.lazy_translation_getter(
            'title', '{}: {}'.format(_('Post'), self.pk))

    def save(self, *args, **kwargs):
        self.last_modified = timezone.now()
        super(Post, self).save(*args, **kwargs)

    def get_absolute_url(self):
        if bs.POST_DETAIL_URL_BY_DATE:
            return reverse('blogit_post_detail_by_date', kwargs={
                'year': self.date_published.strftime(bs.URL_YEAR_FORMAT),
                'month': self.date_published.strftime(
                    bs.URL_MONTH_FORMAT).lower(),
                'day': self.date_published.strftime(bs.URL_DAY_FORMAT),
                'slug': self.get_slug()
            })
        return reverse('blogit_post_detail', kwargs={'slug': self.get_slug()})

    def get_slug(self):
        return self.lazy_translation_getter('slug')

    def get_tags(self):
        return self.lazy_translation_getter('tags')

    def get_previous(self):
        # Returns previous post if it exists, if not returns None.
        posts = Post.objects.language().filter(
            date_published__lt=self.date_published).order_by('-date_published')
        return posts[0] if posts else None

    def get_next(self):
        # Returns next post if it exists, if not returns None.
        posts = Post.objects.language().filter(
            date_published__gt=self.date_published).order_by('date_published')
        return posts[0] if posts else None

# Set PostTranslation unicode.
def post_translation_unicode(self):
    return self.title
PostTranslation.__unicode__ = post_translation_unicode  # noqa
PostTranslation.__str__ = post_translation_unicode  # noqa
<commit_msg>Author get_slug fix<commit_after># -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models
from django.core.urlresolvers import reverse
from django.utils import timezone
from django.utils.translation import get_language, ugettext_lazy as _
from django.utils.encoding import python_2_unicode_compatible

from mptt.models import MPTTModel, TreeForeignKey
from hvad.models import TranslatableModel, TranslatedFields
from hvad.manager import TranslationManager
from taggit.managers import TaggableManager
from taggit.models import TagBase, ItemBase
from cms.models.fields import PlaceholderField
from filer.fields.image import FilerImageField

from blogit import settings as bs
from blogit.utils.translation import get_translation
from blogit.utils.noconflict import classmaker

# Author.
@python_2_unicode_compatible
class Author(TranslatableModel):
    slug = models.SlugField(
        _('slug'), max_length=100, unique=True,
        help_text=_('Text used in the url.'))
    user = models.ForeignKey(
        bs.AUTH_USER_MODEL, blank=True, null=True, unique=True,
        verbose_name=_('user'), help_text=_(
            'If selected, fields "First name", "Last name" and '
            '"Email address" will fallback tu "User" values if they are '
            'left empty.'))
    first_name = models.CharField(
        _('first name'), max_length=30, blank=True, null=True)
    last_name = models.CharField(
        _('last name'), max_length=30, blank=True, null=True)
    email = models.EmailField(_('email address'), blank=True, null=True)
    picture = FilerImageField(
        blank=True, null=True, related_name='author_image',
        verbose_name=_('picture'))

    translations = TranslatedFields(
        description=models.TextField(_('description'), blank=True, null=True),
    )

    bio = PlaceholderField(
        'blogit_author_bio', verbose_name=_('bio'))

    class Meta:
        db_table = 'blogit_authors'
        verbose_name = _('author')
        verbose_name_plural = _('authors')

    def __str__(self):
        name = self.get_full_name()
        if not name and self.user and self.user.username:
            name = self.user.username
        return name or 'Author: {}'.format(self.pk)

    def get_absolute_url(self, language=None):
        if not language:
            language = get_language()

        return reverse('blogit_author_detail', kwargs={
            'url': get_translation(
                bs.AUTHOR_URL, bs.AUTHOR_URL_TRANSLATION, language),
            'slug': self.slug
        })

    def get_full_name(self):
        # Returns first_name plus last_name, with a space in between.
        name = '{} {}'.format(self.get_first_name(), self.get_last_name())
        return name.strip()

    def get_first_name(self):
        # Returns first_name, fallbacks to users first_name.
        if not self.first_name and self.user and self.user.first_name:
            return self.user.first_name
        return self.first_name or ''

    def get_last_name(self):
        # Returns last_name, fallbacks to users last_name.
        if not self.last_name and self.user and self.user.last_name:
            return self.user.last_name
        return self.last_name or ''

    def get_email(self):
        # Returns email, fallbacks to users email.
        if not self.email and self.user and self.user.email:
            return self.user.email
        return self.email or ''

    def get_posts(self):
        # Returns all posts by author.
        return Post.objects.public().filter(author=self)

@python_2_unicode_compatible
class AuthorLink(models.Model):
    author = models.ForeignKey(
        Author, related_name='links', verbose_name=_('author'))
    link_type = models.CharField(
        _('type'), max_length=255, blank=True, null=True,
        choices=bs.AUTHOR_LINK_TYPE_CHOICES)
    url = models.URLField(_('url'))

    class Meta:
        db_table = 'blogit_author_links'
        verbose_name = _('link')
        verbose_name_plural = _('links')
        ordering = ('pk',)

    def __str__(self):
        return self.url

    @property
    def type(self):
        return self.link_type

# Category.
@python_2_unicode_compatible
class Category(TranslatableModel, MPTTModel):
    __metaclass__ = classmaker()

    parent = TreeForeignKey(
        'self', blank=True, null=True, related_name='children', db_index=True)

    date_created = models.DateTimeField(
        _('date created'), default=timezone.now)
    last_modified = models.DateTimeField(
        _('last modified'), default=timezone.now)

    translations = TranslatedFields(
        title=models.CharField(_('title'), max_length=255),
        slug=models.SlugField(_('slug'), max_length=255),
    )

    class Meta:
        db_table = 'blogit_categories'
        verbose_name = _('category')
        verbose_name_plural = _('categories')
        ordering = ('date_created',)

    class MPTTMeta:
        pass

    def __str__(self):
        return self.lazy_translation_getter(
            'title', '{}: {}'.format(_('Category'), self.pk))

    def save(self, *args, **kwargs):
        self.last_modified = timezone.now()
        super(Category, self).save(*args, **kwargs)

    def get_absolute_url(self, language=None):
        if not language:
            language = get_language()

        return reverse('blogit_category_detail', kwargs={
            'url': get_translation(
                bs.CATEGORY_URL, bs.CATEGORY_URL_TRANSLATION, language),
            'slug': self.get_slug()
        })

    def get_slug(self):
        return self.lazy_translation_getter('slug')

# Tag.
@python_2_unicode_compatible
class Tag(TagBase):
    class Meta:
        db_table = 'blogit_tags'
        verbose_name = _('tag')
        verbose_name_plural = _('tags')
        ordering = ('name',)

    def __str__(self):
        return self.name

    def get_absolute_url(self, language=None):
        if not language:
            language = get_language()

        return reverse('blogit_tag_detail', kwargs={
            'url': get_translation(
                bs.TAG_URL, bs.TAG_URL_TRANSLATION, language),
            'slug': self.slug
        })

@python_2_unicode_compatible
class TaggedPost(ItemBase):
    tag = models.ForeignKey(
        Tag, related_name="tagged_posts", verbose_name=_('tag'))
    content_object = models.ForeignKey(
        'PostTranslation', verbose_name=_('post'))

    class Meta:
        db_table = 'blogit_tagged_post_translations'
        verbose_name = _('tagged post')
        verbose_name_plural = _('tagged posts')

    def __str__(self):
        return self.content_object.title

    @classmethod
    def tags_for(cls, model, instance=None):
        if instance is not None:
            return cls.tag_model().objects.filter(**{
                '%s__content_object' % cls.tag_relname(): instance
            })
        return cls.tag_model().objects.filter(**{
            '%s__content_object__isnull' % cls.tag_relname(): False
        }).distinct()

# Post.
class PostManager(TranslationManager):
    def public(self, language_code=None):
        queryset = self.language(language_code)
        return queryset.filter(is_public=True)

@python_2_unicode_compatible
class Post(TranslatableModel):
    category = models.ForeignKey(
        Category, blank=True, null=True, on_delete=models.SET_NULL,
        verbose_name=_('category'))
    author = models.ForeignKey(
        Author, blank=True, null=True, on_delete=models.SET_NULL,
        verbose_name=_('author'))
    featured_image = FilerImageField(
        blank=True, null=True, verbose_name=_('featured image'))
    date_created = models.DateTimeField(
        _('date created'), blank=True, null=True, default=timezone.now)
    last_modified = models.DateTimeField(
        _('last modified'), default=timezone.now)
    date_published = models.DateTimeField(
        _('date published'), default=timezone.now)

    translations = TranslatedFields(
        title=models.CharField(_('title'), max_length=255),
        slug=models.SlugField(
            _('slug'), max_length=255,
            help_text=_('Text used in the url.')),
        is_public=models.BooleanField(
            _('is public'), default=True,
            help_text=_('Designates whether the post is visible to the '
                        'public.')),
        subtitle=models.CharField(
            _('subtitle'), max_length=255, blank=True, null=True),
        description=models.TextField(
            _('description'), blank=True, null=True),
        tags=TaggableManager(
            through=TaggedPost, blank=True, verbose_name=_('tags')),
        meta_title=models.CharField(
            _('page title'), max_length=255, blank=True, null=True,
            help_text=_('Overwrites what is displayed at the top of your '
                        'browser or in bookmarks.')),
        meta_description=models.TextField(
            _('description meta tag'), blank=True, null=True,
            help_text=_('A description of the page sometimes used by '
                        'search engines.')),
        meta_keywords=models.CharField(
            _('keywords meta tag'), max_length=255, blank=True, null=True,
            help_text=_('A list of comma separated keywords sometimes used '
                        'by search engines.')),
    )

    content = PlaceholderField(
        'blogit_post_content', verbose_name=_('content'))

    objects = PostManager()

    class Meta:
        db_table = 'blogit_posts'
        verbose_name = _('post')
        verbose_name_plural = _('posts')

    def __str__(self):
        return self.lazy_translation_getter(
            'title', '{}: {}'.format(_('Post'), self.pk))

    def save(self, *args, **kwargs):
        self.last_modified = timezone.now()
        super(Post, self).save(*args, **kwargs)

    def get_absolute_url(self):
        if bs.POST_DETAIL_URL_BY_DATE:
            return reverse('blogit_post_detail_by_date', kwargs={
                'year': self.date_published.strftime(bs.URL_YEAR_FORMAT),
                'month': self.date_published.strftime(
                    bs.URL_MONTH_FORMAT).lower(),
                'day': self.date_published.strftime(bs.URL_DAY_FORMAT),
                'slug': self.get_slug()
            })
        return reverse('blogit_post_detail', kwargs={'slug': self.get_slug()})

    def get_slug(self):
        return self.lazy_translation_getter('slug')

    def get_tags(self):
        return self.lazy_translation_getter('tags')

    def get_previous(self):
        # Returns previous post if it exists, if not returns None.
        posts = Post.objects.language().filter(
            date_published__lt=self.date_published).order_by('-date_published')
        return posts[0] if posts else None

    def get_next(self):
        # Returns next post if it exists, if not returns None.
        posts = Post.objects.language().filter(
            date_published__gt=self.date_published).order_by('date_published')
        return posts[0] if posts else None

# Set PostTranslation unicode.
def post_translation_unicode(self):
    return self.title
PostTranslation.__unicode__ = post_translation_unicode  # noqa
PostTranslation.__str__ = post_translation_unicode  # noqa
<|endoftext|>


<commit_before>import os
import os.path
import subprocess
import sys

class GitError(EnvironmentError):
    pass

def unroot():
    """
    Drop privileges gained through sudo(1).
    """
    if 'SUDO_UID' in os.environ and 'SUDO_GID' in os.environ:
        uid = int(os.environ['SUDO_UID'])
        gid = int(os.environ['SUDO_GID'])
        os.setgid(gid)
        os.setegid(gid)
        os.setuid(uid)
        os.seteuid(uid)

def init():
    """
    Initialize the Git repository.
    """
    dirname = repo()
    try:
        os.makedirs(dirname)
        if 'SUDO_UID' in os.environ and 'SUDO_GID' in os.environ:
            uid = int(os.environ['SUDO_UID'])
            gid = int(os.environ['SUDO_GID'])
            os.chown(dirname, uid, gid)
    except OSError:
        pass
    p = subprocess.Popen(['git', '--git-dir', repo(), 'init', '--bare'],
                         close_fds=True,
                         preexec_fn=unroot,
                         stdout=sys.stderr)
    p.communicate()
    if 0 != p.returncode:
        #sys.exit(p.returncode)
        raise GitError(p.returncode)

def git(*args, **kwargs):
    """
    Execute a Git command.  Raises GitError on non-zero exits unless the
    raise_exc keyword argument is falsey.
    """
    p = subprocess.Popen(['git',
                          '--git-dir', repo(),
                          '--work-tree', os.getcwd()] + list(args),
                         close_fds=True,
                         preexec_fn=unroot,
                         stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE)
    stdout, stderr = p.communicate(kwargs.get('stdin'))
    if 0 != p.returncode and kwargs.get('raise_exc', True):
        raise GitError(p.returncode)
    return p.returncode, stdout

def repo():
    """
    Return the full path to the Git repository.
    """
    return os.path.expanduser('~/.blueprints.git')

def rev_parse(refname):
    """
    Return the referenced commit or None.
    """
    status, stdout = git('rev-parse', '-q', '--verify', refname,
                         raise_exc=False)
    if 0 != status:
        return None
    return stdout.rstrip()

def tree(commit):
    """
    Return the tree in the given commit or None.
    """
    status, stdout = git('show', '--pretty=format:%T', commit)
    if 0 != status:
        return None
    return stdout[0:40]

def ls_tree(tree, dirname=[]):
    """
    Generate all the pathnames in the given tree.
    """
    status, stdout = git('ls-tree', tree)
    for line in stdout.splitlines():
        mode, type, sha, filename = line.split()
        if 'tree' == type:
            for entry in ls_tree(sha, dirname + [filename]):
                yield entry
        else:
            yield mode, type, sha, os.path.join(*dirname + [filename])

def blob(tree, pathname):
    """
    Return the SHA of the blob by the given name in the given tree.
    """
    for mode, type, sha, pathname2 in ls_tree(tree):
        if pathname == pathname2:
            return sha
    return None

def content(blob):
    """
    Return the content of the given blob.
    """
    status, stdout = git('show', blob)
    if 0 != status:
        return None
    return stdout

def write_tree():
    status, stdout = git('write-tree')
    if 0 != status:
        return None
    return stdout.rstrip()

def commit_tree(tree, message='', parent=None):
    if parent is None:
        status, stdout = git('commit-tree', tree, stdin=message)
    else:
        status, stdout = git('commit-tree', tree, '-p', parent, stdin=message)
    if 0 != status:
        return None
    return stdout.rstrip()
<commit_msg>Show output of git-init commands.<commit_after>import os
import os.path
import subprocess
import sys

class GitError(EnvironmentError):
    pass

def unroot():
    """
    Drop privileges gained through sudo(1).
    """
    if 'SUDO_UID' in os.environ and 'SUDO_GID' in os.environ:
        uid = int(os.environ['SUDO_UID'])
        gid = int(os.environ['SUDO_GID'])
        os.setgid(gid)
        os.setegid(gid)
        os.setuid(uid)
        os.seteuid(uid)

def init():
    """
    Initialize the Git repository.
    """
    dirname = repo()
    try:
        os.makedirs(dirname)
        if 'SUDO_UID' in os.environ and 'SUDO_GID' in os.environ:
            uid = int(os.environ['SUDO_UID'])
            gid = int(os.environ['SUDO_GID'])
            os.chown(dirname, uid, gid)
    except OSError:
        pass
    p = subprocess.Popen(['git', '--git-dir', repo(), 'init', '--bare'],
                         close_fds=True,
                         preexec_fn=unroot)
    p.communicate()
    if 0 != p.returncode:
        #sys.exit(p.returncode)
        raise GitError(p.returncode)

def git(*args, **kwargs):
    """
    Execute a Git command.  Raises GitError on non-zero exits unless the
    raise_exc keyword argument is falsey.
    """
    p = subprocess.Popen(['git',
                          '--git-dir', repo(),
                          '--work-tree', os.getcwd()] + list(args),
                         close_fds=True,
                         preexec_fn=unroot,
                         stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE)
    stdout, stderr = p.communicate(kwargs.get('stdin'))
    if 0 != p.returncode and kwargs.get('raise_exc', True):
        raise GitError(p.returncode)
    return p.returncode, stdout

def repo():
    """
    Return the full path to the Git repository.
    """
    return os.path.expanduser('~/.blueprints.git')

def rev_parse(refname):
    """
    Return the referenced commit or None.
    """
    status, stdout = git('rev-parse', '-q', '--verify', refname,
                         raise_exc=False)
    if 0 != status:
        return None
    return stdout.rstrip()

def tree(commit):
    """
    Return the tree in the given commit or None.
    """
    status, stdout = git('show', '--pretty=format:%T', commit)
    if 0 != status:
        return None
    return stdout[0:40]

def ls_tree(tree, dirname=[]):
    """
    Generate all the pathnames in the given tree.
    """
    status, stdout = git('ls-tree', tree)
    for line in stdout.splitlines():
        mode, type, sha, filename = line.split()
        if 'tree' == type:
            for entry in ls_tree(sha, dirname + [filename]):
                yield entry
        else:
            yield mode, type, sha, os.path.join(*dirname + [filename])

def blob(tree, pathname):
    """
    Return the SHA of the blob by the given name in the given tree.
    """
    for mode, type, sha, pathname2 in ls_tree(tree):
        if pathname == pathname2:
            return sha
    return None

def content(blob):
    """
    Return the content of the given blob.
    """
    status, stdout = git('show', blob)
    if 0 != status:
        return None
    return stdout

def write_tree():
    status, stdout = git('write-tree')
    if 0 != status:
        return None
    return stdout.rstrip()

def commit_tree(tree, message='', parent=None):
    if parent is None:
        status, stdout = git('commit-tree', tree, stdin=message)
    else:
        status, stdout = git('commit-tree', tree, '-p', parent, stdin=message)
    if 0 != status:
        return None
    return stdout.rstrip()
<|endoftext|>


<commit_before>from .run_engine import Msg
from .utils import Struct
import numpy as np

class Scan(Struct):
    def __iter__(self):
        return self._gen()

class Count(Scan):
    """
    Take one or more readings from the detectors. Do not move anything.

    Parameters
    ----------
    detectors : list
        list of 'readable' objects
    num : integer, optional
        number of readings to take; default is 1
    delay : float
        time delay between successive readings; default is 0

    Examples
    --------
    Count three detectors.

    >>> c = Count([det1, det2, det3])
    >>> RE(c)

    Count them five times with a one-second delay between readings.

    >>> c = Count([det1, det2, det3], 5, 1)
    >>> RE(c)
    """

    # This class does not actually use Struct because there are defaults.
    def __init__(self, detectors, num=1, delay=0):
        self.detectors = detectors
        self.num = num
        self.delay = delay

    def _gen(self):
        dets = self.detectors
        delay = self.delay
        for i in range(self.num):
            yield Msg('checkpoint')
            yield Msg('create')
            for det in dets:
                yield Msg('trigger', det, block_group='A')
            for det in dets:
                yield Msg('wait', None, 'A')
            for det in dets:
                yield Msg('read', det)
            yield Msg('save')
            yield Msg('sleep', None, delay)

class Scan1D(Scan):
    _fields = ['motor', 'detectors', 'steps']

    def _gen(self):
        dets = self.detectors
        for step in self._steps:
            yield Msg('checkpoint')
            yield Msg('set', self.motor, step, block_group='A')
            yield Msg('wait', None, 'A')
            yield Msg('create')
            yield Msg('read', self.motor)
            for det in dets:
                yield Msg('trigger', det, block_group='B')
            for det in dets:
                yield Msg('wait', None, 'B')
            for det in dets:
                yield Msg('read', det)
            yield Msg('save')

class Ascan(Scan1D):
    """
    Absolute scan over one variable in user-specified steps

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    steps : list
        list of positions
    """
    def _gen(self):
        self._steps = self.steps
        yield from super()._gen()

class Dscan(Scan1D):
    """
    Delta (relative) scan over one variable in user-specified steps

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    steps : list
        list of positions relative to current position
    """
    def _gen(self):
        ret = yield Msg('read', self.motor)
        if len(ret.keys()) > 1:
            raise NotImplementedError("Can't DScan this motor")
        key, = ret.keys()
        current_value = ret[key]['value']
        self._steps = self.steps + current_value
        yield from super()._gen()

class LinAscan(Scan1D):
    """
    Absolute scan over one variable in equally spaced steps

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    start : float
        starting position of motor
    stop : float
        ending position of motor
    num : int
        number of steps

    Examples
    --------
    Scan motor1 from 0 to 1 in ten steps.

    >>> my_scan = LinAscan(motor1, [det1, det2], 0, 1, 10)
    >>> RE(my_scan)
    # Adjust a Parameter and run again.
    >>> my_scan.num = 100
    >>> RE(my_scan)
    """
    _fields = ['motor', 'detectors', 'start', 'stop', 'num']

    def _gen(self):
        self._steps = np.linspace(self.start, self.stop, self.num)
        yield from super()._gen()

class LogAscan(Scan1D):
    """
    Absolute scan over one variable in log-spaced steps

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    start : float
        starting position of motor
    stop : float
        ending position of motor
    num : int
        number of steps

    Examples
    --------
    Scan motor1 from 0 to 10 in ten log-spaced steps.

    >>> my_scan = LogAscan(motor1, [det1, det2], 0, 1, 10)
    >>> RE(my_scan)
    # Adjust a Parameter and run again.
    >>> my_scan.num = 100
    >>> RE(my_scan)
    """
    _fields = ['motor', 'detectors', 'start', 'stop', 'num']

    def _gen(self):
        self._steps = np.logspace(self.start, self.stop, self.num)
        yield from super()._gen()

class LinDscan(Dscan):
    """
    Delta (relative) scan over one variable in equally spaced steps

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    start : float
        starting position of motor
    stop : float
        ending position of motor
    num : int
        number of steps

    Examples
    --------
    Scan motor1 from 0 to 1 in ten steps.

    >>> my_scan = LinDscan(motor1, [det1, det2], 0, 1, 10)
    >>> RE(my_scan)
    # Adjust a Parameter and run again.
    >>> my_scan.num = 100
    >>> RE(my_scan)
    """
    _fields = ['motor', 'detectors', 'start', 'stop', 'num']

    def _gen(self):
        self.steps = np.linspace(self.start, self.stop, self.num)
        yield from super()._gen()

class LogDscan(Dscan):
    """
    Delta (relative) scan over one variable in log-spaced steps

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    start : float
        starting position of motor
    stop : float
        ending position of motor
    num : int
        number of steps

    Examples
    --------
    Scan motor1 from 0 to 10 in ten log-spaced steps.

    >>> my_scan = LogDscan(motor1, [det1, det2], 0, 1, 10)
    >>> RE(my_scan)
    # Adjust a Parameter and run again.
    >>> my_scan.num = 100
    >>> RE(my_scan)
    """
    _fields = ['motor', 'detectors', 'start', 'stop', 'num']

    def _gen(self):
        self.steps = np.logspace(self.start, self.stop, self.num)
        yield from super()._gen()

class _AdaptiveScan(Scan1D):
    _fields = ['motor', 'detectors', 'target_field', 'start', 'stop',
               'min_step', 'max_step', 'target_delta']
    THRESHOLD = 0.8  # threshold for going backward and rescanning a region.

    def _gen(self):
        start = self.start + self._offset
        stop = self.stop + self._offset
        next_pos = start
        step = (self.max_step - self.min_step) / 2

        past_I = None
        cur_I = None
        cur_det = {}
        motor = self.motor
        dets = self.detectors
        target_field = self.target_field
        while next_pos < stop:
            yield Msg('checkpoint')
            yield Msg('set', motor, next_pos)
            yield Msg('wait', None, 'A')
            yield Msg('create')
            yield Msg('read', motor)
            for det in dets:
                yield Msg('trigger', det, block_group='B')
            for det in dets:
                yield Msg('wait', None, 'B')
            for det in dets:
                cur_det = yield Msg('read', det)
                if target_field in cur_det:
                    cur_I = cur_det[target_field]['value']
            yield Msg('save')

            # special case first first loop
            if past_I is None:
                past_I = cur_I
                next_pos += step
                continue

            dI = np.abs(cur_I - past_I)

            slope = dI / step

            new_step = np.clip(self.target_delta / slope, self.min_step,
                               self.max_step)
            # if we over stepped, go back and try again
            if new_step < step * self.THRESHOLD:
                next_pos -= step
            else:
                past_I = cur_I
            step = new_step
            next_pos += step

class AdaptiveAscan(_AdaptiveScan):
    """
    Absolute scan over one variable with adaptively tuned step size

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    target_field : string
        data field whose output is the focus of the adaptive tuning
    start : float
        starting position of motor
    stop : float
        ending position of motor
    min_step : float
        smallest step for fast-changing regions
    max_step : float
        largest step for slow-chaning regions
    target_delta : float
        desired fractional change in detector signal between steps
    """
    def _gen(self):
        self._offset = 0
        yield from super()._gen()

class AdaptiveDscan(_AdaptiveScan):
    """
    Delta (relative) scan over one variable with adaptively tuned step size

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    target_detector : obj
        detector whose output is the focus of the adaptive tuning
    start : float
        starting position of motor
    stop : float
        ending position of motor
    min_step : float
        smallest step for fast-changing regions
    max_step : float
        largest step for slow-chaning regions
    target_delta : float
        desired fractional change in detector signal between steps
    """
    def _gen(self):
        ret = yield Msg('read', self.motor)
        if len(ret.keys()) > 1:
            raise NotImplementedError("Can't DScan this motor")
        key, = ret.keys()
        current_value = ret[key]['value']
        self._offset = current_value
        yield from super()._gen()
<commit_msg>ENH: first pass at getting logbook integration<commit_after>from .run_engine import Msg
from .utils import Struct
import numpy as np

BASE_MSG = """
Scan id: {uid}
Scan Class: {scn_cls}
"""

class Scan(Struct):
    def __iter__(self):
        yield Msg('logbook', None, self.logmsg(), **self.logdict())
        yield from self._gen()

    def logmsg(self):
        msgs = [BASE_MSG, ]
        for k in self._fields:
            msgs.append('{k}: {{{k}!r}}'.format(k=k))
        return '\n'.join(msgs)

    def logdict(self):
        out_dict = {k: getattr(self, k) for k in self._fields}
        out_dict['scn_cls'] = self.__class__.__name__
        return out_dict

class Count(Scan):
    """
    Take one or more readings from the detectors. Do not move anything.

    Parameters
    ----------
    detectors : list
        list of 'readable' objects
    num : integer, optional
        number of readings to take; default is 1
    delay : float
        time delay between successive readings; default is 0

    Examples
    --------
    Count three detectors.

    >>> c = Count([det1, det2, det3])
    >>> RE(c)

    Count them five times with a one-second delay between readings.

    >>> c = Count([det1, det2, det3], 5, 1)
    >>> RE(c)
    """

    # This class does not actually use Struct because there are defaults.
    def __init__(self, detectors, num=1, delay=0):
        self.detectors = detectors
        self.num = num
        self.delay = delay

    def logdict(self):
        out = super().logdict()
        out['detectors'] = self.detectors
        out['num'] = self.num
        out['delay'] = self.delay
        return out

    def logmsg(self):
        base_msg = super().logmsg()
        msgs = [base_msg]
        msgs.append('detectors: {detectors!r}')
        msgs.append('num: {num}')
        msgs.append('delay: {delay}')
        return '\n'.join(msgs)

    def _gen(self):
        dets = self.detectors
        delay = self.delay
        for i in range(self.num):
            yield Msg('checkpoint')
            yield Msg('create')
            for det in dets:
                yield Msg('trigger', det, block_group='A')
            for det in dets:
                yield Msg('wait', None, 'A')
            for det in dets:
                yield Msg('read', det)
            yield Msg('save')
            yield Msg('sleep', None, delay)

class Scan1D(Scan):
    _fields = ['motor', 'detectors', 'steps']

    def _gen(self):
        dets = self.detectors
        for step in self._steps:
            yield Msg('checkpoint')
            yield Msg('set', self.motor, step, block_group='A')
            yield Msg('wait', None, 'A')
            yield Msg('create')
            yield Msg('read', self.motor)
            for det in dets:
                yield Msg('trigger', det, block_group='B')
            for det in dets:
                yield Msg('wait', None, 'B')
            for det in dets:
                yield Msg('read', det)
            yield Msg('save')

class Ascan(Scan1D):
    """
    Absolute scan over one variable in user-specified steps

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    steps : list
        list of positions
    """
    def _gen(self):
        self._steps = self.steps
        yield from super()._gen()

class Dscan(Scan1D):
    """
    Delta (relative) scan over one variable in user-specified steps

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    steps : list
        list of positions relative to current position
    """
    def _gen(self):
        ret = yield Msg('read', self.motor)
        if len(ret.keys()) > 1:
            raise NotImplementedError("Can't DScan this motor")
        key, = ret.keys()
        current_value = ret[key]['value']
        self._steps = self.steps + current_value
        yield from super()._gen()

class LinAscan(Scan1D):
    """
    Absolute scan over one variable in equally spaced steps

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    start : float
        starting position of motor
    stop : float
        ending position of motor
    num : int
        number of steps

    Examples
    --------
    Scan motor1 from 0 to 1 in ten steps.

    >>> my_scan = LinAscan(motor1, [det1, det2], 0, 1, 10)
    >>> RE(my_scan)
    # Adjust a Parameter and run again.
    >>> my_scan.num = 100
    >>> RE(my_scan)
    """
    _fields = ['motor', 'detectors', 'start', 'stop', 'num']

    def _gen(self):
        self._steps = np.linspace(self.start, self.stop, self.num)
        yield from super()._gen()

class LogAscan(Scan1D):
    """
    Absolute scan over one variable in log-spaced steps

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    start : float
        starting position of motor
    stop : float
        ending position of motor
    num : int
        number of steps

    Examples
    --------
    Scan motor1 from 0 to 10 in ten log-spaced steps.

    >>> my_scan = LogAscan(motor1, [det1, det2], 0, 1, 10)
    >>> RE(my_scan)
    # Adjust a Parameter and run again.
    >>> my_scan.num = 100
    >>> RE(my_scan)
    """
    _fields = ['motor', 'detectors', 'start', 'stop', 'num']

    def _gen(self):
        self._steps = np.logspace(self.start, self.stop, self.num)
        yield from super()._gen()

class LinDscan(Dscan):
    """
    Delta (relative) scan over one variable in equally spaced steps

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    start : float
        starting position of motor
    stop : float
        ending position of motor
    num : int
        number of steps

    Examples
    --------
    Scan motor1 from 0 to 1 in ten steps.

    >>> my_scan = LinDscan(motor1, [det1, det2], 0, 1, 10)
    >>> RE(my_scan)
    # Adjust a Parameter and run again.
    >>> my_scan.num = 100
    >>> RE(my_scan)
    """
    _fields = ['motor', 'detectors', 'start', 'stop', 'num']

    def _gen(self):
        self.steps = np.linspace(self.start, self.stop, self.num)
        yield from super()._gen()

class LogDscan(Dscan):
    """
    Delta (relative) scan over one variable in log-spaced steps

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    start : float
        starting position of motor
    stop : float
        ending position of motor
    num : int
        number of steps

    Examples
    --------
    Scan motor1 from 0 to 10 in ten log-spaced steps.

    >>> my_scan = LogDscan(motor1, [det1, det2], 0, 1, 10)
    >>> RE(my_scan)
    # Adjust a Parameter and run again.
    >>> my_scan.num = 100
    >>> RE(my_scan)
    """
    _fields = ['motor', 'detectors', 'start', 'stop', 'num']

    def _gen(self):
        self.steps = np.logspace(self.start, self.stop, self.num)
        yield from super()._gen()

class _AdaptiveScan(Scan1D):
    _fields = ['motor', 'detectors', 'target_field', 'start', 'stop',
               'min_step', 'max_step', 'target_delta']
    THRESHOLD = 0.8  # threshold for going backward and rescanning a region.

    def _gen(self):
        start = self.start + self._offset
        stop = self.stop + self._offset
        next_pos = start
        step = (self.max_step - self.min_step) / 2

        past_I = None
        cur_I = None
        cur_det = {}
        motor = self.motor
        dets = self.detectors
        target_field = self.target_field
        while next_pos < stop:
            yield Msg('checkpoint')
            yield Msg('set', motor, next_pos)
            yield Msg('wait', None, 'A')
            yield Msg('create')
            yield Msg('read', motor)
            for det in dets:
                yield Msg('trigger', det, block_group='B')
            for det in dets:
                yield Msg('wait', None, 'B')
            for det in dets:
                cur_det = yield Msg('read', det)
                if target_field in cur_det:
                    cur_I = cur_det[target_field]['value']
            yield Msg('save')

            # special case first first loop
            if past_I is None:
                past_I = cur_I
                next_pos += step
                continue

            dI = np.abs(cur_I - past_I)

            slope = dI / step

            new_step = np.clip(self.target_delta / slope, self.min_step,
                               self.max_step)
            # if we over stepped, go back and try again
            if new_step < step * self.THRESHOLD:
                next_pos -= step
            else:
                past_I = cur_I
            step = new_step
            next_pos += step

class AdaptiveAscan(_AdaptiveScan):
    """
    Absolute scan over one variable with adaptively tuned step size

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    target_field : string
        data field whose output is the focus of the adaptive tuning
    start : float
        starting position of motor
    stop : float
        ending position of motor
    min_step : float
        smallest step for fast-changing regions
    max_step : float
        largest step for slow-chaning regions
    target_delta : float
        desired fractional change in detector signal between steps
    """
    def _gen(self):
        self._offset = 0
        yield from super()._gen()

class AdaptiveDscan(_AdaptiveScan):
    """
    Delta (relative) scan over one variable with adaptively tuned step size

    Parameters
    ----------
    motor : object
        any 'setable' object (motor, temp controller, etc.)
    detectors : list
        list of 'readable' objects
    target_detector : obj
        detector whose output is the focus of the adaptive tuning
    start : float
        starting position of motor
    stop : float
        ending position of motor
    min_step : float
        smallest step for fast-changing regions
    max_step : float
        largest step for slow-chaning regions
    target_delta : float
        desired fractional change in detector signal between steps
    """
    def _gen(self):
        ret = yield Msg('read', self.motor)
        if len(ret.keys()) > 1:
            raise NotImplementedError("Can't DScan this motor")
        key, = ret.keys()
        current_value = ret[key]['value']
        self._offset = current_value
        yield from super()._gen()
<|endoftext|>


<commit_before># -*- coding: utf8 -*-
from __future__ import unicode_literals
import sys
print(sys.version)

def main():
    print('234'.isdecimal())

if __name__ == '__main__':
    main()
<commit_msg>add commit<commit_after># -*- coding: utf8 -*-
from __future__ import unicode_literals

def main():
    print('234'.isdecimal())

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


<commit_before>""" Collection of core plotting objects, which can be represented in the
Javascript layer.  The object graph formed by composing the objects in
this module can be stored as a backbone.js model graph, and stored in a
plot server or serialized into JS for embedding in HTML or an IPython
notebook.
"""
from __future__ import absolute_import

import warnings
import logging
logger = logging.getLogger(__file__)

from .properties import (HasProps, Dict, Enum, Either, Float, Instance, Int,
    List, String, Color, Include, Bool, Tuple, Any)
from .mixins import FillProps, LineProps, TextProps
from .enums import Units, Orientation, Location, Dimension, BorderSymmetry
from .plotobject import PlotObject
from .glyphs import BaseGlyph

class DataSource(PlotObject):
    """ Base class for data sources """
    # List of names of the fields of each tuple in self.data
    # ordering is incoporated here
    column_names = List(String)
    selected = List(Int) # index of selected points

    def columns(self, *columns):
        """ Returns a ColumnsRef object that points to a column or set of
        columns on this data source
        """
        return ColumnsRef(source=self, columns=list(columns))

class ColumnsRef(HasProps):
    source = Instance(DataSource, has_ref=True)
    columns = List(String)

class ColumnDataSource(DataSource):
    # Maps names of columns to sequences or arrays
    data = Dict(String, Any)

    # Maps field/column name to a DataRange or FactorRange object. If the
    # field is not in the dict, then a range is created automatically.
    cont_ranges = Dict(String, Instance(".objects.Range"))
    discrete_ranges = Dict(String, Instance(".objects.Range"))

    def __init__(self, *args, **kw):
        """ Modify the basic DataSource/PlotObj constructor so that if we
        are called with a single argument that is a dict, then we treat
        that implicitly as our "data" attribute.
        """
        if len(args) == 1 and "data" not in kw:
            kw["data"] = args[0]
        raw_data = kw.pop("data", {})
        if not isinstance(raw_data, dict):
            import pandas as pd
            if isinstance(raw_data, pd.DataFrame):
                new_data = {}
                for colname in raw_data:
                    new_data[colname] = raw_data[colname].tolist()
                raw_data = new_data
        for name, data in raw_data.items():
            self.add(data, name)
        super(ColumnDataSource, self).__init__(**kw)

    def add(self, data, name=None):
        """ Appends the data to the list of columns.  Returns the name
        that was inserted.
        """
        if name is None:
            n = len(self.data)
            while "Series %d"%n in self.data:
                n += 1
            name = "Series %d"%n
        self.column_names.append(name)
        self.data[name] = data
        return name

    def remove(self, name):
        try:
            self.column_names.remove(name)
            del self.data[name]
        except (ValueError, KeyError):
            warnings.warn("Unable to find column '%s' in datasource" % name)

class ServerDataSource(DataSource):
    data_url = String()
    owner_username = String()
    # allow us to add some data that isn't on the remote source
    # and join it to the remote data
    data = Dict(String, Any)
    # allow us to specify slicing of data on updates
    index_slice = List(Any)
    data_slice = List(Any)
    # allow us to transpose data on updates (for image data)
    transpose = Bool(False)

class PandasDataSource(DataSource):
    """ Represents serverside data.  This gets stored into the plot server's
    database, but it does not have any client side representation.  Instead,
    a PandasPlotSource needs to be created and pointed at it.
    """

    data = Dict(String, Any)

class Range(PlotObject):
    pass

class Range1d(Range):
    start = Float()
    end = Float()

class DataRange(Range):
    sources = List(Instance(ColumnsRef), has_ref=True)

    def finalize(self, models):
        props = super(DataRange, self).finalize(models)
        props['sources'] = [ ColumnsRef(**source) for source in props['sources'] ]
        return props

class DataRange1d(DataRange):
    """ Represents a range in a scalar dimension """
    rangepadding = Float(0.1)
    start = Float
    end = Float

class FactorRange(Range):
    """ Represents a range in a categorical dimension """
    factors = List(Any)

class Renderer(PlotObject):
    pass

class Ticker(PlotObject):
    pass

class AdaptiveTicker(Ticker):
    base = Float(10.0)
    min_interval = Float(0.0)
    max_interval = Float(100.0)

class CompositeTicker(Ticker):
    tickers = List(Instance(Ticker))

class SingleIntervalTicker(Ticker):
    interval = Float

class DaysTicker(Ticker):
    days = List(Int)

class MonthsTicker(Ticker):
    months = List(Int)

class YearsTicker(Ticker):
    pass

class BasicTicker(Ticker):
    pass

class CategoricalTicker(Ticker):
    pass

class DatetimeTicker(Ticker):
    pass

class TickFormatter(PlotObject):
    pass

class BasicTickFormatter(TickFormatter):
    """ Represents a basic tick formatter for an axis object """
    precision = Any('auto')
    use_scientific = Bool(True)
    power_limit_high = Int(5)
    power_limit_low = Int(-3)

class CategoricalTickFormatter(TickFormatter):
    """ Represents a categorical tick formatter for an axis object """
    pass

class DatetimeTickFormatter(TickFormatter):
    """ Represents a categorical tick formatter for an axis object """
    pass

class Glyph(Renderer):
    server_data_source = Instance(ServerDataSource, has_ref=True)
    data_source = Instance(DataSource, has_ref=True)
    xdata_range = Instance(Range, has_ref=True)
    ydata_range = Instance(Range, has_ref=True)

    # How to intepret the values in the data_source
    units = Enum(Units)

    glyph = Instance(BaseGlyph)

    # Optional glyph used when data is selected.
    selection_glyph = Instance(BaseGlyph)
    # Optional glyph used when data is unselected.
    nonselection_glyph = Instance(BaseGlyph)

    def vm_serialize(self):
        # Glyphs need to serialize their state a little differently,
        # because the internal glyph instance is turned into a glyphspec
        data =  {"id" : self._id,
                 "data_source": self.data_source,
                 "server_data_source" : self.server_data_source,
                 "xdata_range": self.xdata_range,
                 "ydata_range": self.ydata_range,
                 "glyphspec": self.glyph.to_glyphspec()
                 }
        if self.selection_glyph:
            data['selection_glyphspec'] = self.selection_glyph.to_glyphspec()
        if self.nonselection_glyph:
            data['nonselection_glyphspec'] = self.nonselection_glyph.to_glyphspec()
        return data

    def finalize(self, models):
        props = super(Glyph, self).finalize(models)

        if hasattr(self, "_special_props"):
            glyphspec = self._special_props.pop('glyphspec', None)
            if glyphspec is not None:
                cls = PlotObject.get_class(glyphspec.pop('type'))
                props['glyph'] = cls(**glyphspec)

            selection_glyphspec = self._special_props.pop('selection_glyphspec', None)
            if selection_glyphspec is not None:
                cls = PlotObject.get_class(selection_glyphspec.pop('type'))
                props['selection_glyph'] = cls(**selection_glyphspec)

            nonselection_glyphspec = self._special_props.pop('nonselection_glyphspec', None)
            if nonselection_glyphspec is not None:
                cls = PlotObject.get_class(nonselection_glyphspec.pop('type'))
                props['nonselection_glyph'] = cls(**nonselection_glyphspec)

        return props

class Plot(PlotObject):
    """ Object representing a plot, containing glyphs, guides, annotations.
    """

    data_sources = List(Instance(DataSource), has_ref=True)

    x_range = Instance(Range, has_ref=True)
    y_range = Instance(Range, has_ref=True)
    png = String('')
    title = String('')
    outline_props = Include(LineProps, prefix="outline")

    # A list of all renderers on this plot; this includes guides as well
    # as glyph renderers
    renderers = List(Instance(Renderer), has_ref=True)
    tools = List(Instance(".objects.Tool"), has_ref=True)

    # TODO: These don't appear in the CS source, but are created by mpl.py, so
    # I'm leaving them here for initial compatibility testing.
    # axes = List(has_ref=True)

    # TODO: How do we want to handle syncing of the different layers?
    # image = List()
    # underlay = List()
    # glyph = List()
    #
    # annotation = List()

    height = Int(600)
    width = Int(600)

    background_fill = Color("white")
    border_fill = Color("white")
    canvas_width = Int(400)
    canvas_height = Int(400)
    outer_width = Int(400)
    outer_height = Int(400)
    min_border_top = Int(50)
    min_border_bottom = Int(50)
    min_border_left = Int(50)
    min_border_right = Int(50)
    min_border = Int(50)
    border_symmetry = Enum(BorderSymmetry)
    script_inject_snippet = String("")

    def vm_props(self):
        # FIXME: We need to duplicate the height and width into canvas and
        # outer height/width.  This is a quick fix for the gorpiness, but this
        # needs to be fixed more structurally on the JS side, and then this
        # should be revisited on the Python side.
        if hasattr(self.session, "root_url"):
            self.script_inject_snippet = self.create_html_snippet(server=True)
        if "canvas_width" not in self._changed_vars:
            self.canvas_width = self.width
        if "outer_width" not in self._changed_vars:
            self.outer_width = self.width
        if "canvas_height" not in self._changed_vars:
            self.canvas_height = self.height
        if "outer_height" not in self._changed_vars:
            self.outer_height = self.height
        return super(Plot, self).vm_props()

class MapOptions(HasProps):
    lat = Float
    lng = Float
    zoom = Int(12)

class GMapPlot(Plot):
    map_options = Instance(MapOptions)

    def vm_serialize(self):
        data = super(GMapPlot, self).vm_serialize()
        self._session.raw_js_snippets(self)
        return data

    def get_raw_js(self):
        return '<script src="https://maps.googleapis.com/maps/api/js?sensor=false"></script>'

class GridPlot(Plot):
    """ A 2D grid of plots """

    children = List(List(Instance(Plot), has_ref=True), has_ref=True)
    border_space = Int(0)

class GuideRenderer(Renderer):
    plot = Instance(Plot, has_ref=True)

    def __init__(self, **kwargs):
        super(GuideRenderer, self).__init__(**kwargs)

        if self.plot is not None:
            if self not in self.plot.renderers:
                self.plot.renderers.append(self)

class Axis(GuideRenderer):
    type = String("axis")

    dimension = Int(0)
    location = Either(Enum(Location), Float)
    bounds = Either(Enum('auto'), Tuple(Float, Float))

    ticker = Instance(Ticker, has_ref=True)
    formatter = Instance(TickFormatter, has_ref=True)

    axis_label = String
    axis_label_standoff = Int
    axis_label_props = Include(TextProps, prefix="axis_label")

    major_label_standoff = Int
    major_label_orientation = Either(Enum("horizontal", "vertical"), Float)
    major_label_props = Include(TextProps, prefix="major_label")

    # Line props
    axis_props = Include(LineProps, prefix="axis")
    tick_props = Include(LineProps, prefix="major_tick")

    major_tick_in = Int
    major_tick_out = Int

class LinearAxis(Axis):
    type = String("linear_axis")

    def __init__(self, **kwargs):
        if 'ticker' not in kwargs:
            kwargs['ticker'] = BasicTicker()
        if 'formatter' not in kwargs:
            kwargs['formatter'] = BasicTickFormatter()
        super(LinearAxis, self).__init__(**kwargs)

class CategoricalAxis(Axis):
    type = String("categorical_axis")

    def __init__(self, **kwargs):
        if 'ticker' not in kwargs:
            kwargs['ticker'] = CategoricalTicker()
        if 'formatter' not in kwargs:
            kwargs['formatter'] = CategoricalTickFormatter()
        super(CategoricalAxis, self).__init__(**kwargs)

class DatetimeAxis(LinearAxis):
    type = String("datetime_axis")

    axis_label = String("date")
    scale = String("time")
    num_labels = Int(8)
    char_width = Int(10)
    fill_ratio = Float(0.3)
    formats = Dict(String, List(String), {"days": ["%m/%d/%Y"]})

    def __init__(self, **kwargs):
        if 'ticker' not in kwargs:
            kwargs['ticker'] = DatetimeTicker()
        if 'formatter' not in kwargs:
            kwargs['formatter'] = DatetimeTickFormatter()
        super(DatetimeAxis, self).__init__(**kwargs)

class Grid(GuideRenderer):
    """ 1D Grid component """
    type = String("grid")

    dimension = Int(0)
    bounds = String('auto')

    axis = Instance(Axis, has_ref=True)

    # Line props
    grid_props = Include(LineProps, prefix="grid")

class Tool(PlotObject):
    plot = Instance(Plot, has_ref=True)

class PanTool(Tool):
    dimensions = List(Enum(Dimension))

class WheelZoomTool(Tool):
    dimensions = List(Enum(Dimension))

class PreviewSaveTool(Tool):
    pass

class EmbedTool(Tool):
    pass

class ResetTool(Tool):
    pass

class ResizeTool(Tool):
    pass

class CrosshairTool(Tool):
    pass

class BoxZoomTool(Tool):
    pass

class BoxSelectTool(Tool):
    renderers = List(Instance(Renderer), has_ref=True)
    select_every_mousemove = Bool(True)

class BoxSelectionOverlay(Renderer):
    __view_model__ = 'BoxSelection'
    tool = Instance(Tool, has_ref=True)

class HoverTool(Tool):
    renderers = List(Instance(Renderer), has_ref=True)
    tooltips = Dict(String, String)

class ObjectExplorerTool(Tool):
    pass

class DataRangeBoxSelectTool(Tool):
    xselect = List(Instance(Range), has_ref=True)
    yselect = List(Instance(Range), has_ref=True)

class Legend(Renderer):
    plot = Instance(Plot, has_ref=True)
    orientation = Enum(Orientation)
    border = Include(LineProps, prefix="border")

    label_props = Include(TextProps, prefix="label")
    label_standoff = Int(15)
    label_height = Int(20)
    label_width = Int(50)

    glyph_height = Int(20)
    glyph_width = Int(20)

    legend_padding = Int(10)
    legend_spacing = Int(3)
    legends = Dict(String, Any)

class DataSlider(Renderer):
    plot = Instance(Plot, has_ref=True)
    data_source = Instance(DataSource, has_ref=True)
    field = String()

class PlotContext(PlotObject):
    children = List(Any, has_ref=True)

class PlotList(PlotContext):
    # just like plot context, except plot context has special meaning
    # everywhere, so plotlist is the generic one
    pass
<commit_msg> changed plotobject def as per @mattpap suggestion<commit_after>""" Collection of core plotting objects, which can be represented in the
Javascript layer.  The object graph formed by composing the objects in
this module can be stored as a backbone.js model graph, and stored in a
plot server or serialized into JS for embedding in HTML or an IPython
notebook.
"""
from __future__ import absolute_import

import warnings
import logging
logger = logging.getLogger(__file__)

from .properties import (HasProps, Dict, Enum, Either, Float, Instance, Int,
    List, String, Color, Include, Bool, Tuple, Any)
from .mixins import FillProps, LineProps, TextProps
from .enums import Units, Orientation, Location, Dimension, BorderSymmetry
from .plotobject import PlotObject
from .glyphs import BaseGlyph

class DataSource(PlotObject):
    """ Base class for data sources """
    # List of names of the fields of each tuple in self.data
    # ordering is incoporated here
    column_names = List(String)
    selected = List(Int) # index of selected points

    def columns(self, *columns):
        """ Returns a ColumnsRef object that points to a column or set of
        columns on this data source
        """
        return ColumnsRef(source=self, columns=list(columns))

class ColumnsRef(HasProps):
    source = Instance(DataSource, has_ref=True)
    columns = List(String)

class ColumnDataSource(DataSource):
    # Maps names of columns to sequences or arrays
    data = Dict(String, Any)

    # Maps field/column name to a DataRange or FactorRange object. If the
    # field is not in the dict, then a range is created automatically.
    cont_ranges = Dict(String, Instance(".objects.Range"))
    discrete_ranges = Dict(String, Instance(".objects.Range"))

    def __init__(self, *args, **kw):
        """ Modify the basic DataSource/PlotObj constructor so that if we
        are called with a single argument that is a dict, then we treat
        that implicitly as our "data" attribute.
        """
        if len(args) == 1 and "data" not in kw:
            kw["data"] = args[0]
        raw_data = kw.pop("data", {})
        if not isinstance(raw_data, dict):
            import pandas as pd
            if isinstance(raw_data, pd.DataFrame):
                new_data = {}
                for colname in raw_data:
                    new_data[colname] = raw_data[colname].tolist()
                raw_data = new_data
        for name, data in raw_data.items():
            self.add(data, name)
        super(ColumnDataSource, self).__init__(**kw)

    def add(self, data, name=None):
        """ Appends the data to the list of columns.  Returns the name
        that was inserted.
        """
        if name is None:
            n = len(self.data)
            while "Series %d"%n in self.data:
                n += 1
            name = "Series %d"%n
        self.column_names.append(name)
        self.data[name] = data
        return name

    def remove(self, name):
        try:
            self.column_names.remove(name)
            del self.data[name]
        except (ValueError, KeyError):
            warnings.warn("Unable to find column '%s' in datasource" % name)

class ServerDataSource(DataSource):
    data_url = String()
    owner_username = String()
    # allow us to add some data that isn't on the remote source
    # and join it to the remote data
    data = Dict(String, Any)
    # allow us to specify slicing of data on updates
    index_slice = List(Any)
    data_slice = List(Any)
    # allow us to transpose data on updates (for image data)
    transpose = Bool(False)

class PandasDataSource(DataSource):
    """ Represents serverside data.  This gets stored into the plot server's
    database, but it does not have any client side representation.  Instead,
    a PandasPlotSource needs to be created and pointed at it.
    """

    data = Dict(String, Any)

class Range(PlotObject):
    pass

class Range1d(Range):
    start = Float()
    end = Float()

class DataRange(Range):
    sources = List(Instance(ColumnsRef), has_ref=True)

    def finalize(self, models):
        props = super(DataRange, self).finalize(models)
        props['sources'] = [ ColumnsRef(**source) for source in props['sources'] ]
        return props

class DataRange1d(DataRange):
    """ Represents a range in a scalar dimension """
    rangepadding = Float(0.1)
    start = Float
    end = Float

class FactorRange(Range):
    """ Represents a range in a categorical dimension """
    factors = List(Any)

class Renderer(PlotObject):
    pass

class Ticker(PlotObject):
    pass

class AdaptiveTicker(Ticker):
    base = Float(10.0)
    min_interval = Float(0.0)
    max_interval = Float(100.0)

class CompositeTicker(Ticker):
    tickers = List(Instance(Ticker))

class SingleIntervalTicker(Ticker):
    interval = Float

class DaysTicker(Ticker):
    days = List(Int)

class MonthsTicker(Ticker):
    months = List(Int)

class YearsTicker(Ticker):
    pass

class BasicTicker(Ticker):
    pass

class CategoricalTicker(Ticker):
    pass

class DatetimeTicker(Ticker):
    pass

class TickFormatter(PlotObject):
    pass

class BasicTickFormatter(TickFormatter):
    """ Represents a basic tick formatter for an axis object """
    precision = Any('auto')
    use_scientific = Bool(True)
    power_limit_high = Int(5)
    power_limit_low = Int(-3)

class CategoricalTickFormatter(TickFormatter):
    """ Represents a categorical tick formatter for an axis object """
    pass

class DatetimeTickFormatter(TickFormatter):
    """ Represents a categorical tick formatter for an axis object """
    pass

class Glyph(Renderer):
    server_data_source = Instance(ServerDataSource, has_ref=True)
    data_source = Instance(DataSource, has_ref=True)
    xdata_range = Instance(Range, has_ref=True)
    ydata_range = Instance(Range, has_ref=True)

    # How to intepret the values in the data_source
    units = Enum(Units)

    glyph = Instance(BaseGlyph)

    # Optional glyph used when data is selected.
    selection_glyph = Instance(BaseGlyph)
    # Optional glyph used when data is unselected.
    nonselection_glyph = Instance(BaseGlyph)

    def vm_serialize(self):
        # Glyphs need to serialize their state a little differently,
        # because the internal glyph instance is turned into a glyphspec
        data =  {"id" : self._id,
                 "data_source": self.data_source,
                 "server_data_source" : self.server_data_source,
                 "xdata_range": self.xdata_range,
                 "ydata_range": self.ydata_range,
                 "glyphspec": self.glyph.to_glyphspec()
                 }
        if self.selection_glyph:
            data['selection_glyphspec'] = self.selection_glyph.to_glyphspec()
        if self.nonselection_glyph:
            data['nonselection_glyphspec'] = self.nonselection_glyph.to_glyphspec()
        return data

    def finalize(self, models):
        props = super(Glyph, self).finalize(models)

        if hasattr(self, "_special_props"):
            glyphspec = self._special_props.pop('glyphspec', None)
            if glyphspec is not None:
                cls = PlotObject.get_class(glyphspec.pop('type'))
                props['glyph'] = cls(**glyphspec)

            selection_glyphspec = self._special_props.pop('selection_glyphspec', None)
            if selection_glyphspec is not None:
                cls = PlotObject.get_class(selection_glyphspec.pop('type'))
                props['selection_glyph'] = cls(**selection_glyphspec)

            nonselection_glyphspec = self._special_props.pop('nonselection_glyphspec', None)
            if nonselection_glyphspec is not None:
                cls = PlotObject.get_class(nonselection_glyphspec.pop('type'))
                props['nonselection_glyph'] = cls(**nonselection_glyphspec)

        return props

class Plot(PlotObject):
    """ Object representing a plot, containing glyphs, guides, annotations.
    """

    data_sources = List(Instance(DataSource), has_ref=True)

    x_range = Instance(Range, has_ref=True)
    y_range = Instance(Range, has_ref=True)
    png = String('')
    title = String('')
    outline_props = Include(LineProps, prefix="outline")

    # A list of all renderers on this plot; this includes guides as well
    # as glyph renderers
    renderers = List(Instance(Renderer), has_ref=True)
    tools = List(Instance(".objects.Tool"), has_ref=True)

    # TODO: These don't appear in the CS source, but are created by mpl.py, so
    # I'm leaving them here for initial compatibility testing.
    # axes = List(has_ref=True)

    # TODO: How do we want to handle syncing of the different layers?
    # image = List()
    # underlay = List()
    # glyph = List()
    #
    # annotation = List()

    height = Int(600)
    width = Int(600)

    background_fill = Color("white")
    border_fill = Color("white")
    canvas_width = Int(400)
    canvas_height = Int(400)
    outer_width = Int(400)
    outer_height = Int(400)
    min_border_top = Int(50)
    min_border_bottom = Int(50)
    min_border_left = Int(50)
    min_border_right = Int(50)
    min_border = Int(50)
    border_symmetry = Enum(BorderSymmetry)
    script_inject_snippet = String("")

    def vm_props(self):
        # FIXME: We need to duplicate the height and width into canvas and
        # outer height/width.  This is a quick fix for the gorpiness, but this
        # needs to be fixed more structurally on the JS side, and then this
        # should be revisited on the Python side.
        if hasattr(self.session, "root_url"):
            self.script_inject_snippet = self.create_html_snippet(server=True)
        if "canvas_width" not in self._changed_vars:
            self.canvas_width = self.width
        if "outer_width" not in self._changed_vars:
            self.outer_width = self.width
        if "canvas_height" not in self._changed_vars:
            self.canvas_height = self.height
        if "outer_height" not in self._changed_vars:
            self.outer_height = self.height
        return super(Plot, self).vm_props()

class MapOptions(HasProps):
    lat = Float
    lng = Float
    zoom = Int(12)

class GMapPlot(Plot):
    map_options = Instance(MapOptions)

    def vm_serialize(self):
        data = super(GMapPlot, self).vm_serialize()
        self._session.raw_js_snippets(self)
        return data

    def get_raw_js(self):
        return '<script src="https://maps.googleapis.com/maps/api/js?sensor=false"></script>'

class GridPlot(Plot):
    """ A 2D grid of plots """

    children = List(List(Instance(Plot), has_ref=True), has_ref=True)
    border_space = Int(0)

class GuideRenderer(Renderer):
    plot = Instance(Plot, has_ref=True)

    def __init__(self, **kwargs):
        super(GuideRenderer, self).__init__(**kwargs)

        if self.plot is not None:
            if self not in self.plot.renderers:
                self.plot.renderers.append(self)

class Axis(GuideRenderer):
    type = String("axis")

    dimension = Int(0)
    location = Either(Enum(Location), Float)
    bounds = Either(Enum('auto'), Tuple(Float, Float))

    ticker = Instance(Ticker, has_ref=True)
    formatter = Instance(TickFormatter, has_ref=True)

    axis_label = String
    axis_label_standoff = Int
    axis_label_props = Include(TextProps, prefix="axis_label")

    major_label_standoff = Int
    major_label_orientation = Either(Enum("horizontal", "vertical"), Float)
    major_label_props = Include(TextProps, prefix="major_label")

    # Line props
    axis_props = Include(LineProps, prefix="axis")
    tick_props = Include(LineProps, prefix="major_tick")

    major_tick_in = Int
    major_tick_out = Int

class LinearAxis(Axis):
    type = String("linear_axis")

    def __init__(self, **kwargs):
        if 'ticker' not in kwargs:
            kwargs['ticker'] = BasicTicker()
        if 'formatter' not in kwargs:
            kwargs['formatter'] = BasicTickFormatter()
        super(LinearAxis, self).__init__(**kwargs)

class CategoricalAxis(Axis):
    type = String("categorical_axis")

    def __init__(self, **kwargs):
        if 'ticker' not in kwargs:
            kwargs['ticker'] = CategoricalTicker()
        if 'formatter' not in kwargs:
            kwargs['formatter'] = CategoricalTickFormatter()
        super(CategoricalAxis, self).__init__(**kwargs)

class DatetimeAxis(LinearAxis):
    type = String("datetime_axis")

    axis_label = String("date")
    scale = String("time")
    num_labels = Int(8)
    char_width = Int(10)
    fill_ratio = Float(0.3)
    formats = Dict(String, List(String), {"days": ["%m/%d/%Y"]})

    def __init__(self, **kwargs):
        if 'ticker' not in kwargs:
            kwargs['ticker'] = DatetimeTicker()
        if 'formatter' not in kwargs:
            kwargs['formatter'] = DatetimeTickFormatter()
        super(DatetimeAxis, self).__init__(**kwargs)

class Grid(GuideRenderer):
    """ 1D Grid component """
    type = String("grid")

    dimension = Int(0)
    bounds = String('auto')

    axis = Instance(Axis, has_ref=True)

    # Line props
    grid_props = Include(LineProps, prefix="grid")

class Tool(PlotObject):
    plot = Instance(Plot, has_ref=True)

class PanTool(Tool):
    dimensions = List(Enum(Dimension))

class WheelZoomTool(Tool):
    dimensions = List(Enum(Dimension))

class PreviewSaveTool(Tool):
    pass

class EmbedTool(Tool):
    pass

class ResetTool(Tool):
    pass

class ResizeTool(Tool):
    pass

class CrosshairTool(Tool):
    pass

class BoxZoomTool(Tool):
    pass

class BoxSelectTool(Tool):
    renderers = List(Instance(Renderer), has_ref=True)
    select_every_mousemove = Bool(True)

class BoxSelectionOverlay(Renderer):
    __view_model__ = 'BoxSelection'
    tool = Instance(Tool, has_ref=True)

class HoverTool(Tool):
    renderers = List(Instance(Renderer), has_ref=True)
    tooltips = Dict(String, String)

class ObjectExplorerTool(Tool):
    pass

class DataRangeBoxSelectTool(Tool):
    xselect = List(Instance(Range), has_ref=True)
    yselect = List(Instance(Range), has_ref=True)

class Legend(Renderer):
    plot = Instance(Plot, has_ref=True)
    orientation = Enum(Orientation)
    border = Include(LineProps, prefix="border")

    label_props = Include(TextProps, prefix="label")
    label_standoff = Int(15)
    label_height = Int(20)
    label_width = Int(50)

    glyph_height = Int(20)
    glyph_width = Int(20)

    legend_padding = Int(10)
    legend_spacing = Int(3)
    legends = Dict(String, Any)

class DataSlider(Renderer):
    plot = Instance(Plot, has_ref=True)
    data_source = Instance(DataSource, has_ref=True)
    field = String()

class PlotContext(PlotObject):
    children = List(Instance(PlotObject, has_ref=True), has_ref=True)

class PlotList(PlotContext):
    # just like plot context, except plot context has special meaning
    # everywhere, so plotlist is the generic one
    pass
<|endoftext|>