<commit_before>from scrapy.crawler import Crawler
from scrapy.settings import Settings
from selenium import webdriver

from scrapy_webdriver.manager import WebdriverManager

BASE_SETTINGS = dict(
    DOWNLOAD_HANDLERS={
        'http': 'scrapy_webdriver.download.WebdriverDownloadHandler',
        'https': 'scrapy_webdriver.download.WebdriverDownloadHandler',
    },
    SPIDER_MIDDLEWARES={
        'scrapy_webdriver.middlewares.WebdriverSpiderMiddleware': 543,
    })

class TestManager:
    @classmethod
    def setup_class(cls):
        cls._settings = BASE_SETTINGS

    def settings(self, **options):
        settings = self._settings.copy()
        settings.update(**options)
        return settings

    def test_browser_config(self):
        class TestBrowser(object):
            pass

        settings = self.settings(WEBDRIVER_BROWSER='Firefox')
        crawler = Crawler(Settings(values=settings))
        crawler.configure()
        browser = WebdriverManager(crawler)
        assert issubclass(browser._browser, webdriver.Firefox)

        settings = self.settings(WEBDRIVER_BROWSER=TestBrowser)
        crawler = Crawler(Settings(values=settings))
        crawler.configure()
        browser = WebdriverManager(crawler)
        assert issubclass(browser._browser, TestBrowser)

        settings = self.settings(WEBDRIVER_BROWSER=TestBrowser())
        crawler = Crawler(Settings(values=settings))
        crawler.configure()
        browser = WebdriverManager(crawler)
        assert isinstance(browser._webdriver, TestBrowser)
<commit_msg>Fixed test.<commit_after>from scrapy.crawler import Crawler
from scrapy.settings import Settings
from scrapy.spiders import CrawlSpider
from selenium import webdriver

from scrapy_webdriver.manager import WebdriverManager

BASE_SETTINGS = dict(
    DOWNLOAD_HANDLERS={
        'http': 'scrapy_webdriver.download.WebdriverDownloadHandler',
        'https': 'scrapy_webdriver.download.WebdriverDownloadHandler',
    },
    SPIDER_MIDDLEWARES={
        'scrapy_webdriver.middlewares.WebdriverSpiderMiddleware': 543,
    })

class TestManager:
    @classmethod
    def setup_class(cls):
        cls._settings = BASE_SETTINGS

    def settings(self, **options):
        settings = self._settings.copy()
        settings.update(**options)
        return settings

    def test_browser_config(self):
        class TestBrowser(object):
            pass

        settings = self.settings(WEBDRIVER_BROWSER='Firefox')
        crawler = Crawler(CrawlSpider, settings=Settings(values=settings))
        browser = WebdriverManager(crawler)
        assert issubclass(browser._browser, webdriver.Firefox)

        settings = self.settings(WEBDRIVER_BROWSER=TestBrowser)
        crawler = Crawler(CrawlSpider, settings=Settings(values=settings))
        browser = WebdriverManager(crawler)
        assert issubclass(browser._browser, TestBrowser)

        settings = self.settings(WEBDRIVER_BROWSER=TestBrowser())
        crawler = Crawler(CrawlSpider, settings=Settings(values=settings))
        browser = WebdriverManager(crawler)
        assert isinstance(browser._webdriver, TestBrowser)
<|endoftext|>


<commit_before># -*- encoding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
#    $Id$
#
#    This program 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.
#
#    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

import time
from report import report_sxw
from osv import osv
import pooler

class product_pricelist(report_sxw.rml_parse):
    def __init__(self, cr, uid, name, context):
        super(product_pricelist, self).__init__(cr, uid, name, context)
        self.pricelist=False
        self.quantity=[]
        self.localcontext.update({
            'time': time,
            'get_pricelist': self._get_pricelist,
            'get_currency': self._get_currency,
            'get_categories': self._get_categories,
            'get_price': self._get_price,
            'get_titles': self._get_titles,
        })

    def _get_titles(self,form):
        lst = []
        vals = {}
        qtys = 1

        for i in range(1,6):
            if form['qty'+str(i)] >= 0 and form['qty'+str(i)] not in vals.values():
                vals['qty'+str(qtys)] = form['qty'+str(i)]
                qtys += 1
        lst.append(vals)
        return lst

    def _set_quantity(self,form):
        for i in range(1,6):
            q = 'qty%d'%i
            if form[q] >=0 and form[q] not in self.quantity:
                self.quantity.append(form[q])
#            else:
#                self.quantity.append(0)
        return True

    def _get_pricelist(self, pricelist_id):
        pool = pooler.get_pool(self.cr.dbname)
        pricelist = pool.get('product.pricelist').read(self.cr,self.uid,[pricelist_id],['name'])[0]
        return pricelist['name']

    def _get_currency(self, pricelist_id):
        pool = pooler.get_pool(self.cr.dbname)
        pricelist = pool.get('product.pricelist').read(self.cr,self.uid,[pricelist_id],['currency_id'])[0]
        return pricelist['currency_id'][1]

    def _get_categories(self, products,form):
        cat_ids=[]
        res=[]
        self.pricelist = form['price_list']
        self._set_quantity(form)
        pool = pooler.get_pool(self.cr.dbname)
        pro_ids=[]
        for product in products:
            pro_ids.append(product.id)
            if product.categ_id.id not in cat_ids:
                cat_ids.append(product.categ_id.id)
        cats = pool.get('product.category').read(self.cr,self.uid,cat_ids,['name'])
        for cat in cats:
            product_ids=pool.get('product.product').search(self.cr,self.uid,[('id','in',pro_ids),('categ_id','=',cat['id'])])
            products = []
            for product in pool.get('product.product').read(self.cr,self.uid,product_ids,['name','code']):
                val={
                         'id':product['id'],
                         'name':product['name'],
                         'code':product['code']
                         }
                i = 1
                for qty in self.quantity:
                    if qty == 0:
                        val['qty'+str(i)] = ""
                    else:
                        val['qty'+str(i)]=self._get_price(self.pricelist,product['id'],qty)
                        i += 1
                products.append(val)
            res.append({'name':cat['name'],'products':products})
        return res

    def _get_price(self,pricelist_id, product_id,qty):
        pool = pooler.get_pool(self.cr.dbname)
        price_dict = pool.get('product.pricelist').price_get(self.cr,self.uid,[pricelist_id],product_id,qty)
        if price_dict[pricelist_id]:
            price = self.formatLang(price_dict[pricelist_id])
        else:
            res = pool.get('product.product').read(self.cr, self.uid,[product_id])
            price =  self.formatLang(res[0]['list_price'])
        return price

report_sxw.report_sxw('report.product.pricelist','product.product','addons/product/report/product_pricelist.rml',parser=product_pricelist)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

<commit_msg>[FIX] Product : Pricelist report corrected for suitable columns<commit_after># -*- encoding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
#    $Id$
#
#    This program 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.
#
#    This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

import time
from report import report_sxw
from osv import osv
import pooler

class product_pricelist(report_sxw.rml_parse):
    def __init__(self, cr, uid, name, context):
        super(product_pricelist, self).__init__(cr, uid, name, context)
        self.pricelist=False
        self.quantity=[]
        self.localcontext.update({
            'time': time,
            'get_pricelist': self._get_pricelist,
            'get_currency': self._get_currency,
            'get_categories': self._get_categories,
            'get_price': self._get_price,
            'get_titles': self._get_titles,
        })

    def _get_titles(self,form):
        lst = []
        vals = {}
        qtys = 1

        for i in range(1,6):
            if form['qty'+str(i)] > 0 and form['qty'+str(i)] not in vals.values():
                vals['qty'+str(qtys)] = form['qty'+str(i)]
                qtys += 1
        lst.append(vals)
        return lst

    def _set_quantity(self,form):
        for i in range(1,6):
            q = 'qty%d'%i
            if form[q] >0 and form[q] not in self.quantity:
                self.quantity.append(form[q])
#            else:
#                self.quantity.append(0)
        return True

    def _get_pricelist(self, pricelist_id):
        pool = pooler.get_pool(self.cr.dbname)
        pricelist = pool.get('product.pricelist').read(self.cr,self.uid,[pricelist_id],['name'])[0]
        return pricelist['name']

    def _get_currency(self, pricelist_id):
        pool = pooler.get_pool(self.cr.dbname)
        pricelist = pool.get('product.pricelist').read(self.cr,self.uid,[pricelist_id],['currency_id'])[0]
        return pricelist['currency_id'][1]

    def _get_categories(self, products,form):
        cat_ids=[]
        res=[]
        self.pricelist = form['price_list']
        self._set_quantity(form)
        pool = pooler.get_pool(self.cr.dbname)
        pro_ids=[]
        for product in products:
            pro_ids.append(product.id)
            if product.categ_id.id not in cat_ids:
                cat_ids.append(product.categ_id.id)
        cats = pool.get('product.category').read(self.cr,self.uid,cat_ids,['name'])
        for cat in cats:
            product_ids=pool.get('product.product').search(self.cr,self.uid,[('id','in',pro_ids),('categ_id','=',cat['id'])])
            products = []
            for product in pool.get('product.product').read(self.cr,self.uid,product_ids,['name','code']):
                val={
                         'id':product['id'],
                         'name':product['name'],
                         'code':product['code']
                         }
                i = 1
                for qty in self.quantity:
                    if qty == 0:
                        val['qty'+str(i)] = ""
                    else:
                        val['qty'+str(i)]=self._get_price(self.pricelist,product['id'],qty)
                        i += 1
                products.append(val)
            res.append({'name':cat['name'],'products':products})
        return res

    def _get_price(self,pricelist_id, product_id,qty):
        pool = pooler.get_pool(self.cr.dbname)
        price_dict = pool.get('product.pricelist').price_get(self.cr,self.uid,[pricelist_id],product_id,qty)
        if price_dict[pricelist_id]:
            price = self.formatLang(price_dict[pricelist_id])
        else:
            res = pool.get('product.product').read(self.cr, self.uid,[product_id])
            price =  self.formatLang(res[0]['list_price'])
        return price

report_sxw.report_sxw('report.product.pricelist','product.product','addons/product/report/product_pricelist.rml',parser=product_pricelist)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from setuptools import setup, find_packages

import statapython

setup(
    name='statapython',
    version=statapython.__version__,

    description="Mr.Statamutation build chain system (mutate, test, report).",
    long_description=open('../README.md').read(),

    author="Mr.Statamutation Team",
    url="https://github.com/Lydwen/Mr.Statamutation/tree/master/Mr.Statapython",

    packages=find_packages(),
    package_data={
        'statapython.templates': ['*.html', '*.css']
    }
)
<commit_msg>[Add] Install dependencies<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from setuptools import setup, find_packages

import statapython

setup(
    name='statapython',
    version=statapython.__version__,

    description="Mr.Statamutation build chain system (mutate, test, report).",
    long_description=open('../README.md').read(),

    author="Mr.Statamutation Team",
    url="https://github.com/Lydwen/Mr.Statamutation/tree/master/Mr.Statapython",

    packages=find_packages(),
    package_data={
        'statapython.templates': ['*.html', '*.css']
    },
    install_requires=['Jinja2'],
)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-Today OpenERP SA (<http://www.openerp.com>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program 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 Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp import tools
from openerp import SUPERUSER_ID
from openerp.osv import osv, fields
from openerp.tools.translate import _

import difflib

class BlogCategory(osv.Model):
    _name = 'blog.category'
    _description = 'Blog Category'
    _inherit = ['mail.thread', 'website.seo.metadata']
    _order = 'name'

    _columns = {
        'name': fields.char('Name', required=True),
        'description': fields.text('Description'),
        'blog_post_ids': fields.one2many(
            'blog.post', 'category_id',
            'Blogs',
        ),
    }

class BlogTag(osv.Model):
    _name = 'blog.tag'
    _description = 'Blog Tag'
    _inherit = ['website.seo.metadata']
    _order = 'name'

    _columns = {
        'name': fields.char('Name', required=True),
        'blog_post_ids': fields.many2many(
            'blog.post', string='Posts',
        ),
    }

class BlogPost(osv.Model):
    _name = "blog.post"
    _description = "Blog Post"
    _inherit = ['mail.thread', 'website.seo.metadata']
    _order = 'write_date DESC'
    # maximum number of characters to display in summary
    _shorten_max_char = 250

    def get_shortened_content(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for page in self.browse(cr, uid, ids, context=context):
            try:
                body_short = tools.html_email_clean(
                    page.content,
                    remove=True,
                    shorten=True,
                    max_length=self._shorten_max_char,
                    expand_options={
                        'oe_expand_container_tag': 'div',
                        'oe_expand_container_class': 'oe_mail_expand text-center',
                        'oe_expand_container_content': '',
                        'oe_expand_a_href': '/blog/%d/' % page.id,
                        'oe_expand_a_class': 'oe_mail_expand btn btn-info',
                        'oe_expand_separator_node': 'br',
                    },
                    protect_sections=True,
                )
            except Exception:
                body_short = False
            res[page.id] = body_short
        return res

    _columns = {
        'name': fields.char('Title', required=True),
        'category_id': fields.many2one(
            'blog.category', 'Category',
            required=True, ondelete='cascade',
        ),
        'tag_ids': fields.many2many(
            'blog.tag', string='Tags',
        ),
        'content': fields.html('Content'),
        'shortened_content': fields.function(
            get_shortened_content,
            type='html',
            string='Shortened Content',
            help="Shortened content of the page that serves as a summary"
        ),
        # website control
        'website_published': fields.boolean(
            'Publish', help="Publish on the website"
        ),
        'website_published_datetime': fields.datetime(
            'Publish Date'
        ),
        # TDE TODO FIXME: when website_mail/mail_thread.py inheritance work -> this field won't be necessary
        'website_message_ids': fields.one2many(
            'mail.message', 'res_id',
            domain=lambda self: [
                '&', ('model', '=', self._name), ('type', '=', 'comment')
            ],
            string='Website Messages',
            help="Website communication history",
        ),
        # technical stuff: history, menu (to keep ?)
        'history_ids': fields.one2many(
            'blog.post.history', 'post_id',
            'History', help='Last post modifications'
        ),
        'menu_id': fields.many2one('ir.ui.menu', "Menu", readonly=True),
        # creation / update stuff
        'create_date': fields.datetime(
            'Created on',
            select=True, readonly=True,
        ),
        'create_uid': fields.many2one(
            'res.users', 'Author',
            select=True, readonly=True,
        ),
        'write_date': fields.datetime(
            'Last Modified on',
            select=True, readonly=True,
        ),
        'write_uid': fields.many2one(
            'res.users', 'Last Contributor',
            select=True, readonly=True,
        ),
    }
    _defaults = {
        'website_published': False
    }

    def create_history(self, cr, uid, ids, vals, context=None):
        for i in ids:
            history = self.pool.get('blog.post.history')
            if vals.get('content'):
                res = {
                    'content': vals.get('content', ''),
                    'post_id': i,
                }
                history.create(cr, uid, res)

    def create(self, cr, uid, vals, context=None):
        if context is None:
            context = {}
        create_context = dict(context, mail_create_nolog=True)
        post_id = super(BlogPost, self).create(cr, uid, vals, context=create_context)
        self.create_history(cr, uid, [post_id], vals, context)
        return post_id

    def write(self, cr, uid, ids, vals, context=None):
        result = super(BlogPost, self).write(cr, uid, ids, vals, context)
        self.create_history(cr, uid, ids, vals, context)
        return result

    def copy(self, cr, uid, id, default=None, context=None):
        if default is None:
            default = {}
        default.update({
            'website_message_ids': [],
            'website_published': False,
            'website_published_datetime': False,
        })
        return super(BlogPost, self).copy(cr, uid, id, default=default, context=context)

    def img(self, cr, uid, ids, field='image_small', context=None):
        post = self.browse(cr, SUPERUSER_ID, ids[0], context=context)
        return "/website/image?model=%s&field=%s&id=%s" % ('res.users', field, post.create_uid.id)

class BlogPostHistory(osv.Model):
    _name = "blog.post.history"
    _description = "Blog Post History"
    _order = 'id DESC'
    _rec_name = "create_date"

    _columns = {
        'post_id': fields.many2one('blog.post', 'Blog Post'),
        'summary': fields.char('Summary', size=256, select=True),
        'content': fields.text("Content"),
        'create_date': fields.datetime("Date"),
        'create_uid': fields.many2one('res.users', "Modified By"),
    }

    def getDiff(self, cr, uid, v1, v2, context=None):
        history_pool = self.pool.get('blog.post.history')
        text1 = history_pool.read(cr, uid, [v1], ['content'])[0]['content']
        text2 = history_pool.read(cr, uid, [v2], ['content'])[0]['content']
        line1 = line2 = ''
        if text1:
            line1 = text1.splitlines(1)
        if text2:
            line2 = text2.splitlines(1)
        if (not line1 and not line2) or (line1 == line2):
            raise osv.except_osv(_('Warning!'), _('There are no changes in revisions.'))
        diff = difflib.HtmlDiff()
        return diff.make_table(line1, line2, "Revision-%s" % (v1), "Revision-%s" % (v2), context=True)

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<commit_msg>[FIX] Another blog URL bug<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-Today OpenERP SA (<http://www.openerp.com>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program 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 Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp import tools
from openerp import SUPERUSER_ID
from openerp.osv import osv, fields
from openerp.tools.translate import _

import difflib

class BlogCategory(osv.Model):
    _name = 'blog.category'
    _description = 'Blog Category'
    _inherit = ['mail.thread', 'website.seo.metadata']
    _order = 'name'

    _columns = {
        'name': fields.char('Name', required=True),
        'description': fields.text('Description'),
        'blog_post_ids': fields.one2many(
            'blog.post', 'category_id',
            'Blogs',
        ),
    }

class BlogTag(osv.Model):
    _name = 'blog.tag'
    _description = 'Blog Tag'
    _inherit = ['website.seo.metadata']
    _order = 'name'

    _columns = {
        'name': fields.char('Name', required=True),
        'blog_post_ids': fields.many2many(
            'blog.post', string='Posts',
        ),
    }

class BlogPost(osv.Model):
    _name = "blog.post"
    _description = "Blog Post"
    _inherit = ['mail.thread', 'website.seo.metadata']
    _order = 'write_date DESC'
    # maximum number of characters to display in summary
    _shorten_max_char = 250

    def get_shortened_content(self, cr, uid, ids, name, arg, context=None):
        res = {}
        for page in self.browse(cr, uid, ids, context=context):
            try:
                body_short = tools.html_email_clean(
                    page.content,
                    remove=True,
                    shorten=True,
                    max_length=self._shorten_max_char,
                    expand_options={
                        'oe_expand_container_tag': 'div',
                        'oe_expand_container_class': 'oe_mail_expand text-center',
                        'oe_expand_container_content': '',
                        'oe_expand_a_href': '/blogpost/%d' % page.id,
                        'oe_expand_a_class': 'oe_mail_expand btn btn-info',
                        'oe_expand_separator_node': 'br',
                    },
                    protect_sections=True,
                )
            except Exception:
                body_short = False
            res[page.id] = body_short
        return res

    _columns = {
        'name': fields.char('Title', required=True),
        'category_id': fields.many2one(
            'blog.category', 'Category',
            required=True, ondelete='cascade',
        ),
        'tag_ids': fields.many2many(
            'blog.tag', string='Tags',
        ),
        'content': fields.html('Content'),
        'shortened_content': fields.function(
            get_shortened_content,
            type='html',
            string='Shortened Content',
            help="Shortened content of the page that serves as a summary"
        ),
        # website control
        'website_published': fields.boolean(
            'Publish', help="Publish on the website"
        ),
        'website_published_datetime': fields.datetime(
            'Publish Date'
        ),
        # TDE TODO FIXME: when website_mail/mail_thread.py inheritance work -> this field won't be necessary
        'website_message_ids': fields.one2many(
            'mail.message', 'res_id',
            domain=lambda self: [
                '&', ('model', '=', self._name), ('type', '=', 'comment')
            ],
            string='Website Messages',
            help="Website communication history",
        ),
        # technical stuff: history, menu (to keep ?)
        'history_ids': fields.one2many(
            'blog.post.history', 'post_id',
            'History', help='Last post modifications'
        ),
        'menu_id': fields.many2one('ir.ui.menu', "Menu", readonly=True),
        # creation / update stuff
        'create_date': fields.datetime(
            'Created on',
            select=True, readonly=True,
        ),
        'create_uid': fields.many2one(
            'res.users', 'Author',
            select=True, readonly=True,
        ),
        'write_date': fields.datetime(
            'Last Modified on',
            select=True, readonly=True,
        ),
        'write_uid': fields.many2one(
            'res.users', 'Last Contributor',
            select=True, readonly=True,
        ),
    }
    _defaults = {
        'website_published': False
    }

    def create_history(self, cr, uid, ids, vals, context=None):
        for i in ids:
            history = self.pool.get('blog.post.history')
            if vals.get('content'):
                res = {
                    'content': vals.get('content', ''),
                    'post_id': i,
                }
                history.create(cr, uid, res)

    def create(self, cr, uid, vals, context=None):
        if context is None:
            context = {}
        create_context = dict(context, mail_create_nolog=True)
        post_id = super(BlogPost, self).create(cr, uid, vals, context=create_context)
        self.create_history(cr, uid, [post_id], vals, context)
        return post_id

    def write(self, cr, uid, ids, vals, context=None):
        result = super(BlogPost, self).write(cr, uid, ids, vals, context)
        self.create_history(cr, uid, ids, vals, context)
        return result

    def copy(self, cr, uid, id, default=None, context=None):
        if default is None:
            default = {}
        default.update({
            'website_message_ids': [],
            'website_published': False,
            'website_published_datetime': False,
        })
        return super(BlogPost, self).copy(cr, uid, id, default=default, context=context)

    def img(self, cr, uid, ids, field='image_small', context=None):
        post = self.browse(cr, SUPERUSER_ID, ids[0], context=context)
        return "/website/image?model=%s&field=%s&id=%s" % ('res.users', field, post.create_uid.id)

class BlogPostHistory(osv.Model):
    _name = "blog.post.history"
    _description = "Blog Post History"
    _order = 'id DESC'
    _rec_name = "create_date"

    _columns = {
        'post_id': fields.many2one('blog.post', 'Blog Post'),
        'summary': fields.char('Summary', size=256, select=True),
        'content': fields.text("Content"),
        'create_date': fields.datetime("Date"),
        'create_uid': fields.many2one('res.users', "Modified By"),
    }

    def getDiff(self, cr, uid, v1, v2, context=None):
        history_pool = self.pool.get('blog.post.history')
        text1 = history_pool.read(cr, uid, [v1], ['content'])[0]['content']
        text2 = history_pool.read(cr, uid, [v2], ['content'])[0]['content']
        line1 = line2 = ''
        if text1:
            line1 = text1.splitlines(1)
        if text2:
            line2 = text2.splitlines(1)
        if (not line1 and not line2) or (line1 == line2):
            raise osv.except_osv(_('Warning!'), _('There are no changes in revisions.'))
        diff = difflib.HtmlDiff()
        return diff.make_table(line1, line2, "Revision-%s" % (v1), "Revision-%s" % (v2), context=True)

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    Author: Dave Lasley <dave@laslabs.com>
#    Copyright: 2015 LasLabs, Inc.
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program 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 Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import models, fields, api
from os import urandom
from oauth_hook import OAuthHook
from Crypto.PublicKey import RSA
from urlparse import parse_qsl
import requests

class ProjectJiraOauth(models.Model):
    ''' Handle OAuth for Jira '''
    _name = 'project.jira.oauth'

    RSA_BITS = 4096
    KEY_LEN = 256
    OAUTH_BASE = 'plugins/servlet/oauth'
    REST_VER = '2'
    REST_BASE = 'rest/api'

    def __compute_default_consumer_key_val(self, ):
        ''' Generate a rnd consumer key of length self.KEY_LEN '''
        return urandom(self.KEY_LEN).encode('hex')

    consumer_key = fields.Char(default=__compute_default_consumer_key_val,
                               readonly=True)
    private_key = fields.Char(readonly=True)
    public_key = fields.Char(readonly=True)

    request_token = fields.Char(readonly=True)
    request_secret = fields.Char(readonly=True)
    auth_uri = fields.Char(readonly=True)

    access_token = fields.Char(readonly=True)
    access_secret = fields.Char(readonly=True)

    company_id = fields.Many2one('res.company')
    project_ids = fields.Many2one('project.jira.project')
    uri = fields.Char()

    @api.one
    def __create_rsa_key_vals(self, ):
        ''' Create public/private RSA keypair   '''
        private = RSA.generate(self.RSA_BITS)
        self.public_key = private.publickey().exportKey()
        self.private_key = private.exportKey()

    def _do_oauth_leg_1(self, ):
        ''' Perform OAuth step1 to get req_token, req_secret, and auth_uri '''

        self.__create_rsa_key_vals() #< Gen new keypairs
        oauth_hook = OAuthHook(
            consumer_key=self.consumer_key, consumer_secret='',
            key_cert = self.private_key, header_auth=True
        )
        req = requests.post(
            '%s/%s/request-token' % (self.uri, self.OAUTH_BASE),
            verify=self.uri.startswith('https'),
            hooks={'pre_request': oauth_hook}
        )
        resp = dict(parse_qsl(req.text))

        token = resp.get('oauth_token', False)
        secret = resp.get('oauth_token_secret', False)

        if False in [token, secret]:
            raise KeyError('Did not get token (%s) or secret (%s). Resp %s',
                           token, secret, resp)

        self.write({
            'request_token': token,
            'request_secret': secret,
            'auth_uri': '%s/%s/authorize?oauth_token=%s' % (
                self.uri, self.OAUTH_BASE
            ),
        })

    def _do_oauth_leg_3(self, ):
        ''' Perform OAuth step 3 to get access_token and secret '''

        oauth_hook = OAuthHook(
            consumer_key=self.consumer_key, consumer_secret='',
            access_token=self.request_token,
            access_token_secret=self.request_secret,
            key_cert=self.private_key, header_auth=True
        )
        req = requests.post(
            '%s/%s/access-token' % (self.uri, self.OAUTH_BASE),
            hooks={'pre_request': oauth_hook}
        )
        resp = dict(parse_qsl(req.text))

        token = resp.get('oauth_token', False)
        secret = resp.get('oauth_token_secret', False)

        if False in [token, secret]:
            raise KeyError('Did not get token (%s) or secret (%s). Resp %s',
                           token, secret, resp)

        self.write({
            'access_token': token,
            'access_secret': secret,
        })

    @api.model
    def create(self, vals):
        ''' Hook into create, start oauth process & validate '''
        rec = super(ProjectJiraOauth, self).create(vals)
        rec._do_oauth_leg_1()

    @api.one
    def write(self, vals):
        ''' Hook into write, update oauth on URI change '''
        super(ProjectJiraOauth, self).write(vals)
        if vals.get('uri'):
            self._do_oauth_leg_1()

class ProjectJiraProject(models.Model):
    _name = 'project.jira.project'
    jira_id = fields.One2many('project.jira.oauth')
    project_ids = fields.One2many('project.project')

class ProjectProject(models.Model):
    _inherit = 'project.project'
    jira_project_id = fields.Many2one('project.jira.project')

#
# class ProjectTask(models.Model):
#     _inherit = 'project.task'

class ResCompany(models.Model):
    _inherit = 'res.company'
    jira_oauth_ids = fields.One2many('project.jira.oauth')<commit_msg>* removed need for ProjectJiraProject model by using direct relations<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    Author: Dave Lasley <dave@laslabs.com>
#    Copyright: 2015 LasLabs, Inc.
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program 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 Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import models, fields, api
from os import urandom
from oauth_hook import OAuthHook
from Crypto.PublicKey import RSA
from urlparse import parse_qsl
import requests

class ProjectJiraOauth(models.Model):
    ''' Handle OAuth for Jira '''
    _name = 'project.jira.oauth'

    RSA_BITS = 4096
    KEY_LEN = 256
    OAUTH_BASE = 'plugins/servlet/oauth'
    REST_VER = '2'
    REST_BASE = 'rest/api'

    def __compute_default_consumer_key_val(self, ):
        ''' Generate a rnd consumer key of length self.KEY_LEN '''
        return urandom(self.KEY_LEN).encode('hex')

    consumer_key = fields.Char(default=__compute_default_consumer_key_val,
                               readonly=True)
    private_key = fields.Char(readonly=True)
    public_key = fields.Char(readonly=True)

    request_token = fields.Char(readonly=True)
    request_secret = fields.Char(readonly=True)
    auth_uri = fields.Char(readonly=True)

    access_token = fields.Char(readonly=True)
    access_secret = fields.Char(readonly=True)

    company_id = fields.Many2one('res.company')
    project_ids = fields.Many2one('project.project')
    uri = fields.Char()

    @api.one
    def __create_rsa_key_vals(self, ):
        ''' Create public/private RSA keypair   '''
        private = RSA.generate(self.RSA_BITS)
        self.public_key = private.publickey().exportKey()
        self.private_key = private.exportKey()

    def _do_oauth_leg_1(self, ):
        ''' Perform OAuth step1 to get req_token, req_secret, and auth_uri '''

        self.__create_rsa_key_vals() #< Gen new keypairs
        oauth_hook = OAuthHook(
            consumer_key=self.consumer_key, consumer_secret='',
            key_cert = self.private_key, header_auth=True
        )
        req = requests.post(
            '%s/%s/request-token' % (self.uri, self.OAUTH_BASE),
            verify=self.uri.startswith('https'),
            hooks={'pre_request': oauth_hook}
        )
        resp = dict(parse_qsl(req.text))

        token = resp.get('oauth_token', False)
        secret = resp.get('oauth_token_secret', False)

        if False in [token, secret]:
            raise KeyError('Did not get token (%s) or secret (%s). Resp %s',
                           token, secret, resp)

        self.write({
            'request_token': token,
            'request_secret': secret,
            'auth_uri': '%s/%s/authorize?oauth_token=%s' % (
                self.uri, self.OAUTH_BASE
            ),
        })

    def _do_oauth_leg_3(self, ):
        ''' Perform OAuth step 3 to get access_token and secret '''

        oauth_hook = OAuthHook(
            consumer_key=self.consumer_key, consumer_secret='',
            access_token=self.request_token,
            access_token_secret=self.request_secret,
            key_cert=self.private_key, header_auth=True
        )
        req = requests.post(
            '%s/%s/access-token' % (self.uri, self.OAUTH_BASE),
            hooks={'pre_request': oauth_hook}
        )
        resp = dict(parse_qsl(req.text))

        token = resp.get('oauth_token', False)
        secret = resp.get('oauth_token_secret', False)

        if False in [token, secret]:
            raise KeyError('Did not get token (%s) or secret (%s). Resp %s',
                           token, secret, resp)

        self.write({
            'access_token': token,
            'access_secret': secret,
        })

    @api.model
    def create(self, vals):
        ''' Hook into create, start oauth process & validate '''
        rec = super(ProjectJiraOauth, self).create(vals)
        rec._do_oauth_leg_1()

    @api.one
    def write(self, vals):
        ''' Hook into write, update oauth on URI change '''
        super(ProjectJiraOauth, self).write(vals)
        if vals.get('uri'):
            self._do_oauth_leg_1()

class ProjectProject(models.Model):
    _inherit = 'project.project'
    jira_id = fields.One2many('project.jira.oauth')

#
# class ProjectTask(models.Model):
#     _inherit = 'project.task'

class ResCompany(models.Model):
    _inherit = 'res.company'
    jira_oauth_ids = fields.One2many('project.jira.oauth')<|endoftext|>


<commit_before>import os.path
import re

class PropertyFormatter(object):
    """
    An object that lazily formats properties of a model, exposing them as
    dictionary keys.
    """
    def __init__(self, model, lowercase, nonwordchars, word_delimiter='_'):
        self.__model = model
        self.__lowercase = lowercase
        self.__nonwordchars = nonwordchars
        self.__word_delimiter = word_delimiter

    def __getitem__(self, key):
        value = unicode(getattr(self.__model, key))
        if self.__lowercase:
            value = value.lower()
        if not self.__nonwordchars:
            value = re.sub('[^\w\s]+', '', value)
        return re.sub('\s+', self.__word_delimiter, value)

    def keys(self):
        return self.__model.__dict__.keys()

def format_filename(pattern, add_extension=True, lowercase=True, nonwordchars=False, word_delimiter='_'):
    """
    Creates a method to be used as a value for Django models' upload_to
    argument. The returned method will format a filename based on properties of
    the model.

    Usage:
        thumbnail = models.ImageField(upload_to=format_filename('profile_images/{last_name}_{first_name}'))
    """
    def upload_to(self, old_filename):
        extension = os.path.splitext(old_filename)[1]
        wrapper = PropertyFormatter(self, lowercase=lowercase, nonwordchars=nonwordchars, word_delimiter=word_delimiter)
        filename = pattern.format(**wrapper)
        if add_extension:
            filename += extension
        return filename

    return upload_to

class Enum(object):
    """
    A class for easily creating enumeration types.

    Usage::

        # models.py
        class MyModel(models.Model):

            Color = Enum(
                RED=('r', 'Red'),
                GREEN=('g', 'Green'),
                BLUE=('b', 'Blue'),
            )

            color = models.CharField(max_length=1, choices=Color.choices())

        # Elsewhere...
        m = MyModel.objects.filter(color=MyModel.Color.RED)

    """

    def __init__(self, *args, **kwargs):
        """
        Accepts kwargs where the keyword is the constant name and the value is
        a tuple containing the ENUM value and a label. If order is important
        (i.e. for choices), you can also pass 3-tuples::

            Color = Enum(
                ('RED', 'r', 'Red'),
                ('GREEN', 'g', 'Green'),
                ('BLUE', 'b', 'Blue'),
            )

        """
        self._constlist = list(args)
        choices = []
        for key, (value, label) in kwargs.items():
            self._constlist.append((key, value, label))
        for key, value, label in self._constlist:
            setattr(self, key, value)
            choices.append((key, label))
        self.__choices = choices

    def choices(self):
        """
        Returns a list formatted for use as field choices.
        (See https://docs.djangoproject.com/en/dev/ref/models/fields/#choices)
        """
        return [(v, l) for k, v, l in self._constlist]

    def keys(self):
        return [k for k, v, l in self._constlist]

    def values(self):
        return [v for k, v, l in self._constlist]

    def labels(self):
        return [l for k, v, l in self._constlist]

    def get_label(self, enum_value):
        for key, value, label in self._constlist:
            if enum_value == value:
                return label
<commit_msg>Greatly improves `format_filename`<commit_after>import os.path
import re
from string import Formatter

class FilenameFormatter(Formatter):
    """
    Formats values for use in a filename.

    """
    def __init__(self, lowercase, nonwordchars, word_delimiter='_'):
        self.lowercase = lowercase
        self.nonwordchars = nonwordchars
        self.word_delimiter = word_delimiter

    def format_field(self, value, format_spec):
        """Formats the fields according to the options provided to the
        constructor.

        """
        value = super(FilenameFormatter, self).format_field(value, format_spec)
        if self.lowercase:
            value = value.lower()
        if not self.nonwordchars:
            value = re.sub('[^\w\s]+', '', value)
        value = re.sub('\s+', self.word_delimiter, value)
        return value

class Wrapper(object):
    """Wraps a model to provide access to attributes as dict values so that it
    can be used with formatter classes.

    """
    def __init__(self, wrapped):
        self._wrapped = wrapped

    def __getitem__(self, key):
        return getattr(self._wrapped, key)

def format_filename(pattern, add_extension=True, lowercase=True, nonwordchars=False, word_delimiter='_'):
    """
    Creates a method to be used as a value for Django models' upload_to
    argument. The returned method will format a filename based on properties of
    the model.

    Usage:
        thumbnail = models.ImageField(upload_to=format_filename('profile_images/{last_name}_{first_name}'))
    """
    def upload_to(self, old_filename):
        extension = os.path.splitext(old_filename)[1]
        formatter = FilenameFormatter(lowercase=lowercase,
                nonwordchars=nonwordchars, word_delimiter=word_delimiter)
        filename = formatter.vformat(pattern, [], Wrapper(self))
        if add_extension:
            filename += extension
        return filename

    return upload_to

class Enum(object):
    """
    A class for easily creating enumeration types.

    Usage::

        # models.py
        class MyModel(models.Model):

            Color = Enum(
                RED=('r', 'Red'),
                GREEN=('g', 'Green'),
                BLUE=('b', 'Blue'),
            )

            color = models.CharField(max_length=1, choices=Color.choices())

        # Elsewhere...
        m = MyModel.objects.filter(color=MyModel.Color.RED)

    """

    def __init__(self, *args, **kwargs):
        """
        Accepts kwargs where the keyword is the constant name and the value is
        a tuple containing the ENUM value and a label. If order is important
        (i.e. for choices), you can also pass 3-tuples::

            Color = Enum(
                ('RED', 'r', 'Red'),
                ('GREEN', 'g', 'Green'),
                ('BLUE', 'b', 'Blue'),
            )

        """
        self._constlist = list(args)
        choices = []
        for key, (value, label) in kwargs.items():
            self._constlist.append((key, value, label))
        for key, value, label in self._constlist:
            setattr(self, key, value)
            choices.append((key, label))
        self.__choices = choices

    def choices(self):
        """
        Returns a list formatted for use as field choices.
        (See https://docs.djangoproject.com/en/dev/ref/models/fields/#choices)
        """
        return [(v, l) for k, v, l in self._constlist]

    def keys(self):
        return [k for k, v, l in self._constlist]

    def values(self):
        return [v for k, v, l in self._constlist]

    def labels(self):
        return [l for k, v, l in self._constlist]

    def get_label(self, enum_value):
        for key, value, label in self._constlist:
            if enum_value == value:
                return label
<|endoftext|>


<commit_before>import os
import yaml
import logging
import collections

def init_logging():
    log = logging.getLogger(__name__)
    return log

log = init_logging()

class YamlConfig(collections.MutableMapping):
    """
    A configuration object populated by parsing a yaml file, with optional
    default values.

    Note that modifying the _defaults attribute of an instance can potentially
    yield confusing results; if you need to do modify defaults, use the class
    variable or create a subclass.
    """
    _defaults = dict()

    def __init__(self, yaml_path=None):
        self.yaml_path = yaml_path
        if self.yaml_path:
            self.load()
        else:
            self._conf = dict()

    def load(self):
        if os.path.exists(self.yaml_path):
            self._conf = yaml.safe_load(file(self.yaml_path))
        else:
            log.debug("%s not found", self.yaml_path)
            self._conf = dict()

    def update(self, in_dict):
        """
        Update an existing configuration using dict.update()

        :param in_dict: The dict to use to update
        """
        self._conf.update(in_dict)

    @classmethod
    def from_dict(cls, in_dict):
        """
        Build a config object from a dict.

        :param in_dict: The dict to use
        :returns:       The config object
        """
        conf_obj = cls()
        conf_obj._conf = in_dict
        return conf_obj

    def to_dict(self):
        """
        :returns: A shallow copy of the configuration as a dict
        """
        return dict(self._conf)

    @classmethod
    def from_str(cls, in_str):
        """
        Build a config object from a string or yaml stream.

        :param in_str: The stream or string
        :returns:      The config object
        """
        conf_obj = cls()
        conf_obj._conf = yaml.safe_load(in_str)
        return conf_obj

    def to_str(self):
        """
        :returns: str(self)
        """
        return str(self)

    def __str__(self):
        return yaml.safe_dump(self._conf, default_flow_style=False).strip()

    def __repr__(self):
        return self.__str__()

    def __getitem__(self, name):
        return self.__getattr__(name)

    def __getattr__(self, name):
        return self._conf.get(name, self._defaults.get(name))

    def __contains__(self, name):
        return self._conf.__contains__(name)

    def __setattr__(self, name, value):
        if name.endswith('_conf') or name in ('yaml_path'):
            object.__setattr__(self, name, value)
        else:
            self._conf[name] = value

    def __delattr__(self, name):
        del self._conf[name]

    def __len__(self):
        return self._conf.__len__()

    def __iter__(self):
        return self._conf.__iter__()

    def __setitem__(self, name, value):
        self._conf.__setitem__(name, value)

    def __delitem__(self, name):
        self._conf.__delitem__(name)

class TeuthologyConfig(YamlConfig):
    """
    This class is intended to unify teuthology's many configuration files and
    objects. Currently it serves as a convenient interface to
    ~/.teuthology.yaml and nothing else.
    """
    yaml_path = os.path.join(os.path.expanduser('~/.teuthology.yaml'))
    _defaults = {
        'archive_base': '/var/lib/teuthworker/archive',
        'automated_scheduling': False,
        'reserve_machines': 5,
        'ceph_git_base_url': 'https://github.com/ceph/',
        'gitbuilder_host': 'gitbuilder.ceph.com',
        'lab_domain': 'front.sepia.ceph.com',
        'lock_server': 'http://paddles.front.sepia.ceph.com/',
        'max_job_time': 259200,  # 3 days
        'results_server': 'http://paddles.front.sepia.ceph.com/',
        'results_sending_email': 'teuthology',
        'results_timeout': 43200,
        'src_base_path': os.path.expanduser('~/src'),
        'verify_host_keys': True,
        'watchdog_interval': 120,
        'kojihub_url': 'http://koji.fedoraproject.org/kojihub',
        'kojiroot_url': 'http://kojipkgs.fedoraproject.org/packages',
        'koji_task_url': 'https://kojipkgs.fedoraproject.org/work/',
    }

    def __init__(self, yaml_path=None):
        super(TeuthologyConfig, self).__init__(yaml_path or self.yaml_path)

class JobConfig(YamlConfig):
    pass

class FakeNamespace(YamlConfig):
    """
    This class is meant to behave like a argparse Namespace. It mimics the old
    way of doing things with argparse and teuthology.misc.read_config.

    We'll use this as a stop-gap as we refactor commands but allow the tasks
    to still be passed a single namespace object for the time being.
    """
    def __init__(self, config_dict=None, yaml_path=None):
        if not yaml_path:
            yaml_path = _get_config_path()
        if not config_dict:
            config_dict = dict()
        self._conf = self._clean_config(config_dict)
        # avoiding circular imports
        from .misc import read_config
        # teuthology.misc.read_config attaches the teuthology config
        # to a teuthology_config key.
        read_config(self)

    def _clean_config(self, config_dict):
        """
        Makes sure that the keys of config_dict are able to be used.  For
        example the "--" prefix of a docopt dict isn't valid and won't populate
        correctly.
        """
        result = dict()
        for key, value in config_dict.iteritems():
            new_key = key
            if new_key.startswith("--"):
                new_key = new_key[2:]
            elif new_key.startswith("<") and new_key.endswith(">"):
                new_key = new_key[1:-1]

            if "-" in new_key:
                new_key = new_key.replace("-", "_")

            result[new_key] = value

        return result

    def __getattr__(self, name):
        """
        We need to modify this for FakeNamespace so that getattr() will
        work correctly on a FakeNamespace instance.
        """
        if name in self._conf:
            return self._conf[name]
        elif name in self._defaults:
            return self._defaults[name]
        raise AttributeError(name)

    def __repr__(self):
        return repr(self._conf)

    def __str__(self):
        return str(self._conf)

def _get_config_path():
    system_config_path = '/etc/teuthology.yaml'
    if not os.path.exists(TeuthologyConfig.yaml_path) and \
            os.path.exists(system_config_path):
        return system_config_path
    return TeuthologyConfig.yaml_path

config = TeuthologyConfig(yaml_path=_get_config_path())
<commit_msg>Add missing default for results_ui_server<commit_after>import os
import yaml
import logging
import collections

def init_logging():
    log = logging.getLogger(__name__)
    return log

log = init_logging()

class YamlConfig(collections.MutableMapping):
    """
    A configuration object populated by parsing a yaml file, with optional
    default values.

    Note that modifying the _defaults attribute of an instance can potentially
    yield confusing results; if you need to do modify defaults, use the class
    variable or create a subclass.
    """
    _defaults = dict()

    def __init__(self, yaml_path=None):
        self.yaml_path = yaml_path
        if self.yaml_path:
            self.load()
        else:
            self._conf = dict()

    def load(self):
        if os.path.exists(self.yaml_path):
            self._conf = yaml.safe_load(file(self.yaml_path))
        else:
            log.debug("%s not found", self.yaml_path)
            self._conf = dict()

    def update(self, in_dict):
        """
        Update an existing configuration using dict.update()

        :param in_dict: The dict to use to update
        """
        self._conf.update(in_dict)

    @classmethod
    def from_dict(cls, in_dict):
        """
        Build a config object from a dict.

        :param in_dict: The dict to use
        :returns:       The config object
        """
        conf_obj = cls()
        conf_obj._conf = in_dict
        return conf_obj

    def to_dict(self):
        """
        :returns: A shallow copy of the configuration as a dict
        """
        return dict(self._conf)

    @classmethod
    def from_str(cls, in_str):
        """
        Build a config object from a string or yaml stream.

        :param in_str: The stream or string
        :returns:      The config object
        """
        conf_obj = cls()
        conf_obj._conf = yaml.safe_load(in_str)
        return conf_obj

    def to_str(self):
        """
        :returns: str(self)
        """
        return str(self)

    def __str__(self):
        return yaml.safe_dump(self._conf, default_flow_style=False).strip()

    def __repr__(self):
        return self.__str__()

    def __getitem__(self, name):
        return self.__getattr__(name)

    def __getattr__(self, name):
        return self._conf.get(name, self._defaults.get(name))

    def __contains__(self, name):
        return self._conf.__contains__(name)

    def __setattr__(self, name, value):
        if name.endswith('_conf') or name in ('yaml_path'):
            object.__setattr__(self, name, value)
        else:
            self._conf[name] = value

    def __delattr__(self, name):
        del self._conf[name]

    def __len__(self):
        return self._conf.__len__()

    def __iter__(self):
        return self._conf.__iter__()

    def __setitem__(self, name, value):
        self._conf.__setitem__(name, value)

    def __delitem__(self, name):
        self._conf.__delitem__(name)

class TeuthologyConfig(YamlConfig):
    """
    This class is intended to unify teuthology's many configuration files and
    objects. Currently it serves as a convenient interface to
    ~/.teuthology.yaml and nothing else.
    """
    yaml_path = os.path.join(os.path.expanduser('~/.teuthology.yaml'))
    _defaults = {
        'archive_base': '/var/lib/teuthworker/archive',
        'automated_scheduling': False,
        'reserve_machines': 5,
        'ceph_git_base_url': 'https://github.com/ceph/',
        'gitbuilder_host': 'gitbuilder.ceph.com',
        'lab_domain': 'front.sepia.ceph.com',
        'lock_server': 'http://paddles.front.sepia.ceph.com/',
        'max_job_time': 259200,  # 3 days
        'results_server': 'http://paddles.front.sepia.ceph.com/',
        'results_ui_server': 'http://pulpito.ceph.com/',
        'results_sending_email': 'teuthology',
        'results_timeout': 43200,
        'src_base_path': os.path.expanduser('~/src'),
        'verify_host_keys': True,
        'watchdog_interval': 120,
        'kojihub_url': 'http://koji.fedoraproject.org/kojihub',
        'kojiroot_url': 'http://kojipkgs.fedoraproject.org/packages',
        'koji_task_url': 'https://kojipkgs.fedoraproject.org/work/',
    }

    def __init__(self, yaml_path=None):
        super(TeuthologyConfig, self).__init__(yaml_path or self.yaml_path)

class JobConfig(YamlConfig):
    pass

class FakeNamespace(YamlConfig):
    """
    This class is meant to behave like a argparse Namespace. It mimics the old
    way of doing things with argparse and teuthology.misc.read_config.

    We'll use this as a stop-gap as we refactor commands but allow the tasks
    to still be passed a single namespace object for the time being.
    """
    def __init__(self, config_dict=None, yaml_path=None):
        if not yaml_path:
            yaml_path = _get_config_path()
        if not config_dict:
            config_dict = dict()
        self._conf = self._clean_config(config_dict)
        # avoiding circular imports
        from .misc import read_config
        # teuthology.misc.read_config attaches the teuthology config
        # to a teuthology_config key.
        read_config(self)

    def _clean_config(self, config_dict):
        """
        Makes sure that the keys of config_dict are able to be used.  For
        example the "--" prefix of a docopt dict isn't valid and won't populate
        correctly.
        """
        result = dict()
        for key, value in config_dict.iteritems():
            new_key = key
            if new_key.startswith("--"):
                new_key = new_key[2:]
            elif new_key.startswith("<") and new_key.endswith(">"):
                new_key = new_key[1:-1]

            if "-" in new_key:
                new_key = new_key.replace("-", "_")

            result[new_key] = value

        return result

    def __getattr__(self, name):
        """
        We need to modify this for FakeNamespace so that getattr() will
        work correctly on a FakeNamespace instance.
        """
        if name in self._conf:
            return self._conf[name]
        elif name in self._defaults:
            return self._defaults[name]
        raise AttributeError(name)

    def __repr__(self):
        return repr(self._conf)

    def __str__(self):
        return str(self._conf)

def _get_config_path():
    system_config_path = '/etc/teuthology.yaml'
    if not os.path.exists(TeuthologyConfig.yaml_path) and \
            os.path.exists(system_config_path):
        return system_config_path
    return TeuthologyConfig.yaml_path

config = TeuthologyConfig(yaml_path=_get_config_path())
<|endoftext|>


<commit_before># encoding: utf-8

__docformat__ = "restructuredtext en"

#----------------------------------------------------------------------------
#  Copyright (C) 2008-2014, IPython Development Team and Enthought, Inc.
#
#  Distributed under the terms of the BSD License.  The full license is in
#  the file COPYING, distributed as part of this software.
#----------------------------------------------------------------------------

#----------------------------------------------------------------------------
# Imports
#----------------------------------------------------------------------------

from distarray.client import DistArray
from distarray.context import Context
<commit_msg>Add new functions.py module to __init__.py<commit_after># encoding: utf-8

__docformat__ = "restructuredtext en"

#----------------------------------------------------------------------------
#  Copyright (C) 2008-2014, IPython Development Team and Enthought, Inc.
#
#  Distributed under the terms of the BSD License.  The full license is in
#  the file COPYING, distributed as part of this software.
#----------------------------------------------------------------------------

#----------------------------------------------------------------------------
# Imports
#----------------------------------------------------------------------------

from distarray.client import DistArray
from distarray.context import Context
from distarray.functions import *
<|endoftext|>


<commit_before>
#
# Copyright (c) 2012 Jonathan Topf
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#

import pymel.core as pm
import maya.cmds as cmds
from functools import partial
import ms_export
import ms_commands

class AEms_renderSettingsTemplate(pm.uitypes.AETemplate):
        def __init__(self, node):

                self.beginScrollLayout()

                self.callCustom(self.toolbar_create, self.toolbar_edit, 'render_toolbar')

                # export settings
                self.beginLayout('Export settings', collapse=False)
                self.callCustom(self.output_directory_create, self.populate_render_layer_layout, 'output_directory')
                self.addControl('output_file')
                self.addSeparator()
                self.addControl('convert_shading_nodes_to_textures', label='Bake shading networks')
                self.addSeparator()
                self.addControl('convert_textures_to_exr', label='Convert Textures to OpenEXR')
                self.addSeparator()
                self.addControl('overwrite_existing_textures', label='Overwrite Existing Textures Files')
                self.addSeparator()
                self.addControl('overwrite_existing_geometry', label='Overwrite Existing Geometry Files')
                self.addSeparator()
                self.addControl('export_camera_blur', label='Export Camera Transformation Motion Blur')
                self.addSeparator()
                self.addControl('export_transformation_blur', label='Export Assembly Transformation Motion Blur')
                self.addSeparator()
                self.addControl('export_deformation_blur', label='Export Object Deformation Motion Blur')
                self.addSeparator()
                self.addControl('motion_samples')
                self.addControl('shutter_open_time')
                self.addControl('shutter_close_time')
                self.addSeparator()
                self.addControl('export_animation')
                self.addControl('animation_start_frame')
                self.addControl('animation_end_frame')
                self.addControl('export_animated_textures')
                self.endLayout()

                # output settings
                self.beginLayout('Output settings')
                self.callCustom(self.camera_select_create, self.camera_select_update, 'camera')
                self.camera_select_option_menu = None
                self.addControl('frame_width')
                self.addControl('frame_height')
                self.addControl('color_space')
                self.addControl('export_straight_alpha')
                self.endLayout()

                # environment settings
                self.beginLayout('Environment settings')
                self.callCustom(self.environment_select_create, self.environment_select_update, 'environment')
                self.environment_select_option_menu = None
                self.addControl('render_sky')
                self.addControl('scene_index_of_refraction')
                self.endLayout()

                # configuration settings
                self.beginLayout('Configuration settings')
                self.addControl('sampler', changeCommand=self.configuration_settings_sampler_callback)
                self.addControl('adaptive_min_samples')
                self.addControl('adaptive_max_samples')
                self.addControl('adaptive_quality')
                self.addSeparator()
                self.addControl('uniform_samples')
                self.addControl('uniform_decorrelate_pixels', label='Decorrelate pixels')
                self.addSeparator()
                self.addControl('pt_direct_lighting')
                self.addControl('pt_ibl')
                self.addControl('pt_caustics')
                self.addSeparator()
                self.addControl('pt_next_event_estimation')
                self.addControl('pt_max_bounces')
                self.addControl('pt_light_samples')
                self.addControl('pt_environment_samples')
                self.addControl('pt_max_ray_intensity')
                self.addSeparator()
                self.addControl('enable_importance_sampling')
                self.endLayout()

                # render layers
                self.beginLayout('Render layers')
                self.callCustom(self.render_layer_create_layout, self.populate_render_layer_layout, 'render_layers')
                self.render_layer_layout = None
                self.endLayout()

                # advanced settings
                self.beginLayout('Advanced settings')
                self.addControl('profile_export')
                self.addSeparator()
                self.addControl('autodetect_alpha')
                self.addSeparator()
                self.addControl('force_linear_texture_interpretation')
                self.addSeparator()
                self.addControl('force_linear_color_interpretation')
                self.addSeparator()
                self.addControl('export_all_cameras_as_thin_lens')
                self.addSeparator()
                self.addControl('export_maya_lights')

                self.endLayout()

                self.addExtraControls()

                self.endScrollLayout()

                # suppress potential render layers
                for i in range(50):
                    for attr in ms_commands.RENDER_LAYER_ATTRS:
                        self.suppress('render_layer_{0}_{1}'.format(i, attr[0]))

        def get_file_dir(self, *attr):
            file_name = cmds.fileDialog2(fm=3, cap='Select directory', okc='Select')
            if file_name is not None:
                cmds.setAttr(attr[0], file_name[0], type='string')

        def output_directory_create(self, attr):
            cmds.rowLayout(nc=3)
            cmds.text(label='Output Directory')
            self.output_dir_text_field = cmds.textField(fileName=cmds.getAttr(attr))
            self.output_dir_button = cmds.button(' Select directory ', c=partial(self.get_file_dir, attr))

        def output_directory_update(self, attr):
            cmds.textField(self.output_dir_text_field, edit=True, fileName=cmds.getAttr(attr))
            cmds.button(self.output_dir_button, edit=True, c=partial(self.get_file_dir, attr))

        def render_layer_create_layout(self, args):
            self.render_layer_layout_widths = [130, 120, 130, 50, 30]
            self.render_layer_label_layout = cmds.rowLayout('render_layer_label_layout', nc=5, cal=[1, 'left'])
            for i, width in enumerate(self.render_layer_layout_widths):
                cmds.rowLayout(self.render_layer_label_layout, e=True, cw=[i + 1, width])
            cmds.text('name')
            cmds.text('entity type')
            cmds.text('rule')
            cmds.text('order')
            cmds.text(' - ')
            cmds.setParent('..')
            self.render_layer_layout = cmds.columnLayout('render_layer_layout')
            cmds.setParent('..')
            self.populate_render_layer_layout(args)

        def add_render_layer(self, node, refresh=True):
            for i in range(50):
                i += 1

                layer_name = 'render_layer_{0}_name'.format(i)

                if not cmds.attributeQuery(layer_name, exists=True, node=node):
                    for attr in ms_commands.RENDER_LAYER_ATTRS:
                        cmds.addAttr(node, longName='render_layer_{0}_{1}'.format(i, attr[0]), dt="string", k=False, w=False)
                        cmds.setAttr('{0}.render_layer_{1}_{2}'.format(node, i, attr[0]), attr[1], type='string')
                    if refresh:
                        self.populate_render_layer_layout(attr)
                    break

        def remove_render_layer(self, node, number, args):
            for attr in ms_commands.RENDER_LAYER_ATTRS:
                cmds.deleteAttr(n=node, at='render_layer_{0}_{1}'.format(number, attr[0]))
            self.populate_render_layer_layout(node)

        def populate_render_layer_layout(self, attr):
            if self.render_layer_layout is not None:
                node = attr.split('.')[0]
                # delete old ui
                children = cmds.columnLayout(self.render_layer_layout, q=True, childArray=True)
                if children is not None:
                    for name in children:
                        cmds.deleteUI(name)

                for i in range(50):
                    i += 1

                    layer_name = 'render_layer_{0}_name'.format(i)

                    if cmds.attributeQuery(layer_name, exists=True, node=node):
                        cmds.setParent(self.render_layer_layout)
                        current_render_layer_layout = cmds.rowLayout(nc=5)
                        for n, width in enumerate(self.render_layer_layout_widths):
                            cmds.rowLayout(current_render_layer_layout, e=True, cw=[n + 1, width])
                        cmds.textField(cc=partial(self.set_render_layer_name, node, i), text=cmds.getAttr('{0}.render_layer_{1}_name'.format(node, i)))
                        entity_type_menu = cmds.optionMenu(cc=partial(self.set_render_layer_type, node, i))
                        for entity_type in ms_commands.RENDER_LAYER_ENTITY_TYPES:
                            cmds.menuItem(label=entity_type)
                        cmds.optionMenu(entity_type_menu, e=True, v=cmds.getAttr('{0}.render_layer_{1}_type'.format(node, i)))
                        rule_text_field = cmds.textField(cc=partial(self.set_render_layer_rule, node, i), text=cmds.getAttr('{0}.render_layer_{1}_rule'.format(node, i)))
                        cmds.textField(cc=partial(self.set_render_layer_order, i), text=cmds.getAttr('{0}.render_layer_{1}_order'.format(node, i)))
                        cmds.button(' - ', height=20, command=partial(self.remove_render_layer, node, i))

                cmds.setParent(self.render_layer_layout)
                current_render_layer_layout = cmds.rowLayout(nc=2)
                cmds.button(' + ', command=partial(self.add_render_layer, node))

        def camera_select_create(self, attr=None):
            self.camera_select_layout = cmds.rowLayout(nc=3)
            cmds.text('Camera')
            self.camera_select_option_menu = cmds.optionMenu(cc=partial(self.camera_select_set, attr))
            self.camera_select_update(attr)

        def camera_select_update(self, attr):
            if self.camera_select_option_menu is not None:
                items = cmds.optionMenu(self.camera_select_option_menu, q=True, ill=True)
                if items is not None:
                    for item in items:
                        cmds.deleteUI(item)
                cmds.menuItem(label='<none>', p=self.camera_select_option_menu)
                for camera in cmds.ls(type='camera'):
                    if not cmds.getAttr(camera + '.orthographic'):
                        cmds.menuItem(label=camera, p=self.camera_select_option_menu)
                connection = cmds.listConnections(attr, sh=True)
                if connection is None:
                    cmds.optionMenu(self.camera_select_option_menu, e=True, v='<none>')
                else:
                    cmds.optionMenu(self.camera_select_option_menu, e=True, v=connection[0])

        def camera_select_set(self, attr, camera):
            value = cmds.optionMenu(self.camera_select_option_menu, q=True, v=True)
            connection = cmds.listConnections(attr, sh=True)
            if value == '<none>':
                if connection is not None:
                    cmds.disconnectAttr(connection[0] + '.message', attr)
            else:
                if connection is not None:
                    if connection[0] == camera:
                        return
                cmds.connectAttr(camera + '.message', attr, f=True)

        def environment_select_create(self, attr=None):
            self.environment_select_layout = cmds.rowLayout(nc=3)
            cmds.text('Environment')
            self.environment_select_option_menu = cmds.optionMenu(cc=partial(self.environment_select_set, attr))
            if attr is not None:
                self.environment_select_update(attr)

        def environment_select_update(self, attr):
            if self.environment_select_option_menu is not None:
                items = cmds.optionMenu(self.environment_select_option_menu, q=True, ill=True)
                if items is not None:
                    for item in items:
                        cmds.deleteUI(item)
                cmds.menuItem(label='<none>', p=self.environment_select_option_menu)
                for environment in cmds.ls(type='ms_environment') + cmds.ls(type='ms_physical_environment'):
                    cmds.menuItem(label=environment, p=self.environment_select_option_menu)
                connection = cmds.listConnections(attr, sh=True)
                if connection is None:
                    cmds.optionMenu(self.environment_select_option_menu, e=True, v='<none>')
                else:
                    cmds.optionMenu(self.environment_select_option_menu, e=True, v=connection[0])

        def environment_select_set(self, attr, environment):
            value = cmds.optionMenu(self.environment_select_option_menu, q=True, v=True)
            connection = cmds.listConnections(attr, sh=True)
            if value == '<none>':
                if connection is not None:
                    cmds.disconnectAttr(connection[0] + '.message', attr)
            else:
                if connection is not None:
                    if connection[0] == environment:
                        return
                cmds.connectAttr(environment + '.message', attr, f=True)

        def set_render_layer_name(self, node, layer_number, value):
            self.set_render_layer_attr(node, layer_number, 'name', value)

        def set_render_layer_type(self, node, layer_number, value):
            self.set_render_layer_attr(node, layer_number, 'type', value)

        def set_render_layer_rule(self, node, layer_number, value):
            self.set_render_layer_attr(node, layer_number, 'rule', value)

        def set_render_layer_order(self, node, layer_number, value):
            self.set_render_layer_attr(node, layer_number, 'order', value)

        def set_render_layer_attr(self, node, layer_number, name, value):
            cmds.setAttr('{0}.render_layer_{1}_{2}'.format(node, layer_number, name), value, type='string')

        def toolbar_create(self, args):
            cmds.button('Export', bgc=[0, 0.7, 1], command=self.render)
            cmds.button('Refresh attribute editor', command=self.refresh_editor)

        def toolbar_edit(self, args):
            pass

        def configuration_settings_sampler_callback(self, node):
            if cmds.getAttr(node + '.sampler') == 0: # adaptive
                cmds.editorTemplate(dimControl=[node, 'adaptive_min_samples', False])
                cmds.editorTemplate(dimControl=[node, 'adaptive_max_samples', False])
                cmds.editorTemplate(dimControl=[node, 'adaptive_quality', False])
                cmds.editorTemplate(dimControl=[node, 'uniform_samples', True])
                cmds.editorTemplate(dimControl=[node, 'uniform_decorrelate_pixels', True])
            else: # uniform
                cmds.editorTemplate(dimControl=[node, 'adaptive_min_samples', True])
                cmds.editorTemplate(dimControl=[node, 'adaptive_max_samples', True])
                cmds.editorTemplate(dimControl=[node, 'adaptive_quality', True])
                cmds.editorTemplate(dimControl=[node, 'uniform_samples', False])
                cmds.editorTemplate(dimControl=[node, 'uniform_decorrelate_pixels', False])

        def refresh_editor(self, args):
            cmds.refreshEditorTemplates()

        def render(self, args):
            node = cmds.ls(sl=True)
            ms_export.export(node[0])

<commit_msg>renamed render layer params to be consistent with appleseed<commit_after>
#
# Copyright (c) 2012 Jonathan Topf
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#

import pymel.core as pm
import maya.cmds as cmds
from functools import partial
import ms_export
import ms_commands

class AEms_renderSettingsTemplate(pm.uitypes.AETemplate):
        def __init__(self, node):

                self.beginScrollLayout()

                self.callCustom(self.toolbar_create, self.toolbar_edit, 'render_toolbar')

                # export settings
                self.beginLayout('Export settings', collapse=False)
                self.callCustom(self.output_directory_create, self.populate_render_layer_layout, 'output_directory')
                self.addControl('output_file')
                self.addSeparator()
                self.addControl('convert_shading_nodes_to_textures', label='Bake shading networks')
                self.addSeparator()
                self.addControl('convert_textures_to_exr', label='Convert Textures to OpenEXR')
                self.addSeparator()
                self.addControl('overwrite_existing_textures', label='Overwrite Existing Textures Files')
                self.addSeparator()
                self.addControl('overwrite_existing_geometry', label='Overwrite Existing Geometry Files')
                self.addSeparator()
                self.addControl('export_camera_blur', label='Export Camera Transformation Motion Blur')
                self.addSeparator()
                self.addControl('export_transformation_blur', label='Export Assembly Transformation Motion Blur')
                self.addSeparator()
                self.addControl('export_deformation_blur', label='Export Object Deformation Motion Blur')
                self.addSeparator()
                self.addControl('motion_samples')
                self.addControl('shutter_open_time')
                self.addControl('shutter_close_time')
                self.addSeparator()
                self.addControl('export_animation')
                self.addControl('animation_start_frame')
                self.addControl('animation_end_frame')
                self.addControl('export_animated_textures')
                self.endLayout()

                # output settings
                self.beginLayout('Output settings')
                self.callCustom(self.camera_select_create, self.camera_select_update, 'camera')
                self.camera_select_option_menu = None
                self.addControl('frame_width')
                self.addControl('frame_height')
                self.addControl('color_space')
                self.addControl('export_straight_alpha')
                self.endLayout()

                # environment settings
                self.beginLayout('Environment settings')
                self.callCustom(self.environment_select_create, self.environment_select_update, 'environment')
                self.environment_select_option_menu = None
                self.addControl('render_sky')
                self.addControl('scene_index_of_refraction')
                self.endLayout()

                # configuration settings
                self.beginLayout('Configuration settings')
                self.addControl('sampler', changeCommand=self.configuration_settings_sampler_callback)
                self.addControl('adaptive_min_samples')
                self.addControl('adaptive_max_samples')
                self.addControl('adaptive_quality')
                self.addSeparator()
                self.addControl('uniform_samples')
                self.addControl('uniform_decorrelate_pixels', label='Decorrelate pixels')
                self.addSeparator()
                self.addControl('pt_direct_lighting')
                self.addControl('pt_ibl')
                self.addControl('pt_caustics')
                self.addSeparator()
                self.addControl('pt_next_event_estimation')
                self.addControl('pt_max_bounces')
                self.addControl('pt_light_samples')
                self.addControl('pt_environment_samples')
                self.addControl('pt_max_ray_intensity')
                self.addSeparator()
                self.addControl('enable_importance_sampling')
                self.endLayout()

                # render layers
                self.beginLayout('Render layers')
                self.callCustom(self.render_layer_create_layout, self.populate_render_layer_layout, 'render_layers')
                self.render_layer_layout = None
                self.endLayout()

                # advanced settings
                self.beginLayout('Advanced settings')
                self.addControl('profile_export')
                self.addSeparator()
                self.addControl('autodetect_alpha')
                self.addSeparator()
                self.addControl('force_linear_texture_interpretation')
                self.addSeparator()
                self.addControl('force_linear_color_interpretation')
                self.addSeparator()
                self.addControl('export_all_cameras_as_thin_lens')
                self.addSeparator()
                self.addControl('export_maya_lights')

                self.endLayout()

                self.addExtraControls()

                self.endScrollLayout()

                # suppress potential render layers
                for i in range(50):
                    for attr in ms_commands.RENDER_LAYER_ATTRS:
                        self.suppress('render_layer_{0}_{1}'.format(i, attr[0]))

        def get_file_dir(self, *attr):
            file_name = cmds.fileDialog2(fm=3, cap='Select directory', okc='Select')
            if file_name is not None:
                cmds.setAttr(attr[0], file_name[0], type='string')

        def output_directory_create(self, attr):
            cmds.rowLayout(nc=3)
            cmds.text(label='Output Directory')
            self.output_dir_text_field = cmds.textField(fileName=cmds.getAttr(attr))
            self.output_dir_button = cmds.button(' Select directory ', c=partial(self.get_file_dir, attr))

        def output_directory_update(self, attr):
            cmds.textField(self.output_dir_text_field, edit=True, fileName=cmds.getAttr(attr))
            cmds.button(self.output_dir_button, edit=True, c=partial(self.get_file_dir, attr))

        def render_layer_create_layout(self, args):
            self.render_layer_layout_widths = [130, 120, 130, 50, 30]
            self.render_layer_label_layout = cmds.rowLayout('render_layer_label_layout', nc=5, cal=[1, 'left'])
            for i, width in enumerate(self.render_layer_layout_widths):
                cmds.rowLayout(self.render_layer_label_layout, e=True, cw=[i + 1, width])
            cmds.text('name')
            cmds.text('entity type')
            cmds.text('pattern')
            cmds.text('order')
            cmds.text(' - ')
            cmds.setParent('..')
            self.render_layer_layout = cmds.columnLayout('render_layer_layout')
            cmds.setParent('..')
            self.populate_render_layer_layout(args)

        def add_render_layer(self, node, refresh=True):
            for i in range(50):
                i += 1

                layer_name = 'render_layer_{0}_name'.format(i)

                if not cmds.attributeQuery(layer_name, exists=True, node=node):
                    for attr in ms_commands.RENDER_LAYER_ATTRS:
                        cmds.addAttr(node, longName='render_layer_{0}_{1}'.format(i, attr[0]), dt="string", k=False, w=False)
                        cmds.setAttr('{0}.render_layer_{1}_{2}'.format(node, i, attr[0]), attr[1], type='string')
                    if refresh:
                        self.populate_render_layer_layout(attr)
                    break

        def remove_render_layer(self, node, number, args):
            for attr in ms_commands.RENDER_LAYER_ATTRS:
                cmds.deleteAttr(n=node, at='render_layer_{0}_{1}'.format(number, attr[0]))
            self.populate_render_layer_layout(node)

        def populate_render_layer_layout(self, attr):
            if self.render_layer_layout is not None:
                node = attr.split('.')[0]
                # delete old ui
                children = cmds.columnLayout(self.render_layer_layout, q=True, childArray=True)
                if children is not None:
                    for name in children:
                        cmds.deleteUI(name)

                for i in range(50):
                    i += 1

                    layer_name = 'render_layer_{0}_name'.format(i)

                    if cmds.attributeQuery(layer_name, exists=True, node=node):
                        cmds.setParent(self.render_layer_layout)
                        current_render_layer_layout = cmds.rowLayout(nc=5)
                        for n, width in enumerate(self.render_layer_layout_widths):
                            cmds.rowLayout(current_render_layer_layout, e=True, cw=[n + 1, width])
                        cmds.textField(cc=partial(self.set_render_layer_name, node, i), text=cmds.getAttr('{0}.render_layer_{1}_name'.format(node, i)))
                        entity_type_menu = cmds.optionMenu(cc=partial(self.set_render_layer_type, node, i))
                        for entity_type in ms_commands.RENDER_LAYER_ENTITY_TYPES:
                            cmds.menuItem(label=entity_type)
                        cmds.optionMenu(entity_type_menu, e=True, v=cmds.getAttr('{0}.render_layer_{1}_type'.format(node, i)))
                        pattern_text_field = cmds.textField(cc=partial(self.set_render_layer_pattern, node, i), text=cmds.getAttr('{0}.render_layer_{1}_pattern'.format(node, i)))
                        cmds.textField(cc=partial(self.set_render_layer_order, i), text=cmds.getAttr('{0}.render_layer_{1}_order'.format(node, i)))
                        cmds.button(' - ', height=20, command=partial(self.remove_render_layer, node, i))

                cmds.setParent(self.render_layer_layout)
                current_render_layer_layout = cmds.rowLayout(nc=2)
                cmds.button(' + ', command=partial(self.add_render_layer, node))

        def camera_select_create(self, attr=None):
            self.camera_select_layout = cmds.rowLayout(nc=3)
            cmds.text('Camera')
            self.camera_select_option_menu = cmds.optionMenu(cc=partial(self.camera_select_set, attr))
            self.camera_select_update(attr)

        def camera_select_update(self, attr):
            if self.camera_select_option_menu is not None:
                items = cmds.optionMenu(self.camera_select_option_menu, q=True, ill=True)
                if items is not None:
                    for item in items:
                        cmds.deleteUI(item)
                cmds.menuItem(label='<none>', p=self.camera_select_option_menu)
                for camera in cmds.ls(type='camera'):
                    if not cmds.getAttr(camera + '.orthographic'):
                        cmds.menuItem(label=camera, p=self.camera_select_option_menu)
                connection = cmds.listConnections(attr, sh=True)
                if connection is None:
                    cmds.optionMenu(self.camera_select_option_menu, e=True, v='<none>')
                else:
                    cmds.optionMenu(self.camera_select_option_menu, e=True, v=connection[0])

        def camera_select_set(self, attr, camera):
            value = cmds.optionMenu(self.camera_select_option_menu, q=True, v=True)
            connection = cmds.listConnections(attr, sh=True)
            if value == '<none>':
                if connection is not None:
                    cmds.disconnectAttr(connection[0] + '.message', attr)
            else:
                if connection is not None:
                    if connection[0] == camera:
                        return
                cmds.connectAttr(camera + '.message', attr, f=True)

        def environment_select_create(self, attr=None):
            self.environment_select_layout = cmds.rowLayout(nc=3)
            cmds.text('Environment')
            self.environment_select_option_menu = cmds.optionMenu(cc=partial(self.environment_select_set, attr))
            if attr is not None:
                self.environment_select_update(attr)

        def environment_select_update(self, attr):
            if self.environment_select_option_menu is not None:
                items = cmds.optionMenu(self.environment_select_option_menu, q=True, ill=True)
                if items is not None:
                    for item in items:
                        cmds.deleteUI(item)
                cmds.menuItem(label='<none>', p=self.environment_select_option_menu)
                for environment in cmds.ls(type='ms_environment') + cmds.ls(type='ms_physical_environment'):
                    cmds.menuItem(label=environment, p=self.environment_select_option_menu)
                connection = cmds.listConnections(attr, sh=True)
                if connection is None:
                    cmds.optionMenu(self.environment_select_option_menu, e=True, v='<none>')
                else:
                    cmds.optionMenu(self.environment_select_option_menu, e=True, v=connection[0])

        def environment_select_set(self, attr, environment):
            value = cmds.optionMenu(self.environment_select_option_menu, q=True, v=True)
            connection = cmds.listConnections(attr, sh=True)
            if value == '<none>':
                if connection is not None:
                    cmds.disconnectAttr(connection[0] + '.message', attr)
            else:
                if connection is not None:
                    if connection[0] == environment:
                        return
                cmds.connectAttr(environment + '.message', attr, f=True)

        def set_render_layer_name(self, node, layer_number, value):
            self.set_render_layer_attr(node, layer_number, 'name', value)

        def set_render_layer_type(self, node, layer_number, value):
            self.set_render_layer_attr(node, layer_number, 'type', value)

        def set_render_layer_pattern(self, node, layer_number, value):
            self.set_render_layer_attr(node, layer_number, 'pattern', value)

        def set_render_layer_order(self, node, layer_number, value):
            self.set_render_layer_attr(node, layer_number, 'order', value)

        def set_render_layer_attr(self, node, layer_number, name, value):
            cmds.setAttr('{0}.render_layer_{1}_{2}'.format(node, layer_number, name), value, type='string')

        def toolbar_create(self, args):
            cmds.button('Export', bgc=[0, 0.7, 1], command=self.render)
            cmds.button('Refresh attribute editor', command=self.refresh_editor)

        def toolbar_edit(self, args):
            pass

        def configuration_settings_sampler_callback(self, node):
            if cmds.getAttr(node + '.sampler') == 0: # adaptive
                cmds.editorTemplate(dimControl=[node, 'adaptive_min_samples', False])
                cmds.editorTemplate(dimControl=[node, 'adaptive_max_samples', False])
                cmds.editorTemplate(dimControl=[node, 'adaptive_quality', False])
                cmds.editorTemplate(dimControl=[node, 'uniform_samples', True])
                cmds.editorTemplate(dimControl=[node, 'uniform_decorrelate_pixels', True])
            else: # uniform
                cmds.editorTemplate(dimControl=[node, 'adaptive_min_samples', True])
                cmds.editorTemplate(dimControl=[node, 'adaptive_max_samples', True])
                cmds.editorTemplate(dimControl=[node, 'adaptive_quality', True])
                cmds.editorTemplate(dimControl=[node, 'uniform_samples', False])
                cmds.editorTemplate(dimControl=[node, 'uniform_decorrelate_pixels', False])

        def refresh_editor(self, args):
            cmds.refreshEditorTemplates()

        def render(self, args):
            node = cmds.ls(sl=True)
            ms_export.export(node[0])

<|endoftext|>