<commit_before>#!/usr/bin/env python
################################################################################
# DATE: 2016/August/10
#
# MODULE: scatter_plot_2D.py
#
# VERSION: 1.1
#
# AUTHOR: Matt Thoburn (mthoburn@ufl.edu), Miguel Ibarra (miguelib@ufl.edu)
#
# DESCRIPTION: This is a standalone executable for graphing 2D scatter plots
# from wide data
#
################################################################################
# Import built-in libraries
import os
import logging
import argparse
from argparse import RawDescriptionHelpFormatter

# Import add-on libraries
import pandas as pd
from matplotlib.backends.backend_pdf import PdfPages

# Import local data libraries
from secimtools.dataManager import logger as sl
from secimtools.dataManager.interface import wideToDesign

# Import local plotting libraries
from secimtools.visualManager import module_scatter as scatter
from secimtools.visualManager.manager_color import colorHandler
from secimtools.visualManager.manager_figure import figureHandler

def getOptions():
    description="Stand alone Scatter Plots 2D tool"
    parser = argparse.ArgumentParser(description=description,
                        formatter_class=RawDescriptionHelpFormatter)
    # Standard input
    standard = parser.add_argument_group(title="Standard input",
                        description='Standard input for SECIM tools.')
    standard.add_argument( "-i","--input", dest="input", action='store',
                        required=True, help="Input dataset in wide format.")
    standard.add_argument("-d" ,"--design",dest="design", action='store',
                        required=False,default=False, help="Design file.")
    standard.add_argument("-id", "--ID",dest="uniqID", action='store',
                        required=True, help="Name of the column with unique "\
                        "identifiers.")
    standard.add_argument("-g", "--group",dest="group", action='store',
                        required=False, default=False, help="Name of the column"\
                        " with groups.")
    # Tool input
    tool = parser.add_argument_group(title="Tool especific input")
    tool.add_argument("-x" ,"--X",dest="x", action='store',
                        required=True, help="Name of column for X values")
    tool.add_argument("-y", "--Y",dest="y", action='store',
                        required=True, help="Name of column for Y values")
    # Tool output
    output = parser.add_argument_group(title="Output")
    output.add_argument("-f","--figure",dest="figure",action="store",
                        required=False, help="Path of figure.")
    # Plot options
    plot = parser.add_argument_group(title='Plot options')
    plot.add_argument("-pal","--palette",dest="palette",action='store',required=False,
                        default="tableau", help="Name of the palette to use.")
    plot.add_argument("-col","--color",dest="color",action="store",required=False,
                        default="Tableau_20", help="Name of a valid color scheme"\
                        " on the selected palette")
    args = parser.parse_args()

    # Standardize paths
    args.input  = os.path.abspath(args.input)
    args.figure = os.path.abspath(args.figure)
    if args.design:
        args.design = os.path.abspath(args.design)
    return(args)

def main(args):
    # Loading design
    if args.design:
        design = pd.DataFrame.from_csv(args.design,sep="\t")
        design.reset_index(inplace=True)
    else:
        design = False

    # Loading wide file
    wide = pd.DataFrame.from_csv(args.input,sep="\t")

    # Create figureHandler object
    fh = figureHandler(proj="2d",figsize=(14,8))

    # If design file with group and the uniqID is "sampleID" then color by group
    if args.group and args.uniqID == "sampleID":
        glist=list(design[args.group])
        colorList, ucGroups = palette.getColorsByGroup(design=design,
                                group=args.group,uGroup=sorted(set(glist)))
    else:
        glist = list()
        colorList = palette.mpl_colors[0]
        ucGroups = dict()

    # Plote scatterplot 2D
    scatter.scatter2D(ax=fh.ax[0], x=list(wide[args.x]), y=list(wide[args.y]),
                    colorList=colorList)

    # Despine axis (spine = tick)
    fh.despine(fh.ax[0])

    # Formating axis
    fh.formatAxis(figTitle=args.x + " vs " + args.y, xTitle=args.x,
                yTitle=args.y, grid=False)

    # If groups are provided create a legend
    if args.group and args.uniqID == "sampleID":
        fh.makeLegend(ax=fh.ax[0],ucGroups=ucGroups,group=args.group)
        fh.shrink()

    # Saving figure to file
    with PdfPages(args.figure) as pdfOut:
        fh.addToPdf(dpi=600, pdfPages=pdfOut)
    logger.info("Script Complete!")

if __name__ == '__main__':
    # Command line options
    args   = getOptions()

    # Set logger
    logger = logging.getLogger()
    sl.setLogger(logger)

    # Stablishing color palette
    palette = colorHandler(pal=args.palette, col=args.color)
    logger.info(u"Using {0} color scheme from {1} palette".format(args.color,
                args.palette))

    # Run everything
    main(args)
<commit_msg>Set up Agg backend for matplotlib, partial cleanup of inconsistent formatting and some typos in scatter_plot_2D<commit_after>#!/usr/bin/env python
################################################################################
# DATE: 2016/August/10
#
# MODULE: scatter_plot_2D.py
#
# VERSION: 1.1
#
# AUTHOR: Matt Thoburn (mthoburn@ufl.edu), Miguel Ibarra (miguelib@ufl.edu)
#
# DESCRIPTION: This is a standalone executable for graphing 2D scatter plots
# from wide data
################################################################################
# Import built-in libraries
import os
import logging
import argparse
from argparse import RawDescriptionHelpFormatter
# Import add-on libraries
import pandas as pd
import matplotlib
matplotlib.use('Agg')
from matplotlib.backends.backend_pdf import PdfPages
# Import local data libraries
from secimtools.dataManager import logger as sl
from secimtools.dataManager.interface import wideToDesign
# Import local plotting libraries
from secimtools.visualManager import module_scatter as scatter
from secimtools.visualManager.manager_color import colorHandler
from secimtools.visualManager.manager_figure import figureHandler

def getOptions():
    description="Stand alone Scatter Plots 2D tool"
    parser = argparse.ArgumentParser(description=description,
                        formatter_class=RawDescriptionHelpFormatter)
    # Standard input
    standard = parser.add_argument_group(title="Standard input",
                        description='Standard input for SECIM tools.')
    standard.add_argument( "-i","--input", dest="input", action='store',
                        required=True, help="Input dataset in wide format.")
    standard.add_argument("-d" ,"--design",dest="design", action='store',
                        required=False,default=False, help="Design file.")
    standard.add_argument("-id", "--ID",dest="uniqID", action='store',
                        required=True, help="Name of the column with unique "\
                        "identifiers.")
    standard.add_argument("-g", "--group",dest="group", action='store',
                        required=False, default=False, help="Name of the column"\
                        " with groups.")
    # Tool input
    tool = parser.add_argument_group(title="Tool especific input")
    tool.add_argument("-x" ,"--X",dest="x", action='store',
                        required=True, help="Name of column for X values")
    tool.add_argument("-y", "--Y",dest="y", action='store',
                        required=True, help="Name of column for Y values")
    # Tool output
    output = parser.add_argument_group(title="Output")
    output.add_argument("-f","--figure",dest="figure",action="store",
                        required=False, help="Path of figure.")
    # Plot options
    plot = parser.add_argument_group(title='Plot options')
    plot.add_argument("-pal","--palette",dest="palette",action='store',required=False,
                        default="tableau", help="Name of the palette to use.")
    plot.add_argument("-col","--color",dest="color",action="store",required=False,
                        default="Tableau_20", help="Name of a valid color scheme"\
                        " on the selected palette")
    args = parser.parse_args()

    # Standardize paths
    args.input  = os.path.abspath(args.input)
    args.figure = os.path.abspath(args.figure)
    if args.design:
        args.design = os.path.abspath(args.design)
    return(args)

def main(args):
    # Loading design
    if args.design:
        design = pd.DataFrame.from_csv(args.design,sep="\t")
        design.reset_index(inplace=True)
    else:
        design = False

    # Loading wide file
    wide = pd.DataFrame.from_csv(args.input,sep="\t")

    # Create figureHandler object
    fh = figureHandler(proj="2d",figsize=(14,8))

    # If design file with group and the uniqID is "sampleID" then color by group
    if args.group and args.uniqID == "sampleID":
        glist=list(design[args.group])
        colorList, ucGroups = palette.getColorsByGroup(design=design,
                                group=args.group,uGroup=sorted(set(glist)))
    else:
        glist = list()
        colorList = palette.mpl_colors[0]
        ucGroups = dict()

    # Plote scatterplot 2D
    scatter.scatter2D(ax=fh.ax[0], x=list(wide[args.x]), y=list(wide[args.y]),
                    colorList=colorList)

    # Despine axis (spine = tick)
    fh.despine(fh.ax[0])

    # Formating axis
    fh.formatAxis(figTitle=args.x + " vs " + args.y, xTitle=args.x,
                yTitle=args.y, grid=False)

    # If groups are provided create a legend
    if args.group and args.uniqID == "sampleID":
        fh.makeLegend(ax=fh.ax[0],ucGroups=ucGroups,group=args.group)
        fh.shrink()

    # Saving figure to file
    with PdfPages(args.figure) as pdfOut:
        fh.addToPdf(dpi=600, pdfPages=pdfOut)
    logger.info("Script Complete!")

if __name__ == '__main__':
    args   = getOptions()
    logger = logging.getLogger()
    sl.setLogger(logger)
    palette = colorHandler(pal=args.palette, col=args.color)
    logger.info(u"Using {0} color scheme from {1} palette".format(args.color,
                args.palette))
    main(args)
<|endoftext|>


<commit_before>'''\
A tool to convert command-line tools into WSGI web applications.

A large number of CLI programs that look like this:

    def main():
        parser = argparse.ArgumentParser(...)
        args = parser.parse_args()
        mycode(args)

ArgParser lets you turn programs like these into web apps by changing a
few lines of code:

    def main():
        parser = argparse.ArgumentParser(...)
        args = argparse.Namespace()
        srv = wsgiref.simple_server.make_server(
            '', 8080, ArgParser(parser, args, mycode))

ArgParser analyzes *parser* and produces an HTML form that exposes
the same parameters.  Once that form is submitted, a copy of *args* will
be filled in and passed to *mycode*.

That's the simplist way to use this, but there are other options.  For
example, you can decide at run-time whether to run as a CLI program or a
web server by added arguments to the parser.  In that case, you will
want to remove those options from the parser before you pass it to
ArgParser.  For example:

    def main():
        parser = argparse.ArgumentParser(...)
        host_action = parser.add_argument(
            '--host', '-H', default='0.0.0.0')
        port_action = parser.add_argument(
            '--port', '-P', default=8080)
        args = parser.parse_args()
        if args.host or args.port:
            parser._remove_action(host_action)
            parser._remove_action(port_action)
            srv = wsgiref.simple_server.make_server(
                args.host, args.port, ArgParser(parser, args, mycode))
        else:
            mycode(args)

There are a few caveats, most stemming from the fact that *mycode* will
be called repeatedly. First, it should not call sys.exit().  (Someday it
will intercept the SystemExit exception, but not today.) Also, it should
clean up after itself, as any resource leaks will eventually cause the
web server to crash.
'''

from datetime import datetime
import os, sys

class WSGIdispatcher(object):
    """
    The main WSGI application. Dispatch the current request to
    the functions from above and store the regular expression
    captures in the WSGI environment as `myapp.url_args` so that
    the functions from above can access the url placeholders.

    As a convenience to developers, static files can be served by
    setting static_path to a directory.  If a matching file name can be
    found there, it is returned.  Limited support for cache control is
    provided via Last-Modified headers, however support is specifically
    excluded for multiple search directories, Etags and other cache
    control headers, and Range requests.

    If nothing matches, call the `not_found` function.
    """
    devfiles = set() if os.name == 'posix' else {
        'CON', 'AUX', 'COM1', 'COM2', 'COM3', 'COM4',
        'LPT1', 'LPT2', 'LPT3', 'PRN', 'NUL'}

    def __init__(self, *dispatch_table, static_path=None):
        import re
        end = '' if hasattr(re, 'fullmatch') else '$'
        self.static_path = static_path
        self.dispatch_table = [
            (re.compile(pattern+end), callback)
            for pattern, callback in dispatch_table
            ]

    def __call__(self, environ, start_response):
        path_info = environ.get('PATH_INFO', '')
        path = path_info.lstrip('/')
        for regex, callback in self.dispatch_table:
            match = regex.fullmatch(path)
            if match is not None:
                environ['myapp.url_args'] = match.groups()
                return callback(environ, start_response)
        if self.static_path:
            from mimetypes import guess_type
            from os.path import join, split, splitext

            head, tail = split(path)
            root, ext = splitext(tail)
            if root.upper() in self.devfiles:
                return self.not_found(environ, start_response)
            path = join(self.static_path, tail)
            try:
                with open(path, 'rb') as myfile:
                    type, encoding = guess_type(myfile.name)
                    headers = []
                    if type:
                        headers.append(('Content-Type', type))
                    if encoding:
                        headers.append(('Content-Encoding ', encoding))
                    fs = os.fstat(myfile.fileno())
                    headers.append(('Content-Length', str(fs.st_size)))
                    if_modified_since = environ.get('HTTP_IF_MODIFIED_SINCE', '')
                    last_modified = datetime.fromtimestamp(fs.st_mtime).strftime("%a, %d %b %Y %H:%M:%S GMT")
                    headers.append(('Last-Modified', last_modified))
                    if if_modified_since == last_modified:
                        start_response('304 Not Modified', headers)
                        return []
                    else:
                        start_response('200 OK', headers)
                        blksz = 65536
                        return [ myfile.read(blksz) ]

                        errors = environ['wsgi.errors']
                        if 'wsgi.file_wrapper' in environ:
##                            print('wsgi.file_wrapper', repr(myfile), file=errors)
                            return environ['wsgi.file_wrapper'](myfile, blksz)
                        else:
##                            print('iter()', repr(myfile), file=errors)
                            return iter(lambda: myfile.read(blksz), '')
            except (FileNotFoundError, IsADirectoryError, OSError):
##                print(
##                    'path = %r\nenviron = %r' % (path, environ),
##                    file=environ['wsgi.errors'])
                return self.not_found(environ, start_response)
        else:
            return self.not_found(environ, start_response)

    def not_found(self, environ, start_response):
        # per notfound.org, consider using an iframe that includes
        # https://d3o9f8o0i654j9.cloudfront.net/404/index.html
        start_response('404 Not Found', as_html)
        return [
            b'<!DOCTYPE html>',
            bytes(Html(Head(), Body(Img(alt="Not Found", src="https://http.cat/404"))))
            ]

from copy import copy
from io import StringIO
import argparse
import cgi

from htmltags import *

singular = set([None, 1, '?'])
optional = set(['?', '*'])

as_html = [('Content-Type', 'text/html')]

def popattr(*args):
    value = getattr(*args)
    try:
        delattr(*args[:2])
    except AttributeError:
        pass
    return value

class ArgParser(object):

    def __init__(self, parser, args, runapp,
                 headers=[('Content-Type', 'text/plain')],
                 skip_groups=set(),
                 submit_actions=(),
                 ):
        self.parser = parser
        self.args = args
        self.runapp = runapp
        self.skip_groups = skip_groups
        self.submit_actions = submit_actions
        self.headers = headers
        self.inputs = []
        self.outputs = []

        my_body = Body()
        my_form = Form(method='post', enctype='multipart/form-data')
        if parser.description:
            my_body += P(parser.description)
        my_body += my_form
        if parser.epilog:
            my_body += P(parser.epilog)

        for action_group in parser._action_groups:
            if not action_group._group_actions:
                continue
            if action_group.title in self.skip_groups:
                continue
            my_form += P(B(action_group.title.title()))
            my_table = Fieldset()
            my_form += my_table
            if action_group.description:
                my_table += P(action_group.description)
            for action in action_group._group_actions:
                try:
                    if submit_actions and isinstance(action, submit_actions):
                        continue
                    elif isinstance(action, argparse._HelpAction):
                        continue
                    elif action.nargs == 0:
                        input_tag = Input(type='checkbox')
                    elif action.choices:
                        input_tag = Select()
                        if action.nargs not in singular:
                            input_tag.setAttribute('multiple', None)
                        if action.nargs not in optional:
                            input_tag.setAttribute('required', None)
                        for option in action.choices:
                            input_tag += Option(option, value=option)
                    elif isinstance(action.type, argparse.FileType):
                        if 'r' not in action.type._mode:
                            self.outputs.append(action)
                            continue
                        self.inputs.append(action)
                        input_tag = Input(type='file')
                    else:  #if issubclass(action.type, basestring):
                        input_tag = Input(type='text')
                except TypeError as err:
                    from traceback import format_exc
                    input_tag = Pre(format_exc())
                input_tag.setAttribute('name', action.dest)
                my_table += Label(action.dest.replace('_', ' ').title(), For=action.dest)
                my_table += input_tag
                if action.help:
                    my_table += P(I(action.help))
        my_form += Input(type="submit")
        for action in submit_actions:
            my_form += Input(type="submit",
                             name=action.dest,
                             value=action.dest.title())
        self.my_doc = Html(
            Head(
                Meta(
                    name="viewport",
                    content="width=device-width, initial-scale=1")
                ),
            my_body)

    def __call__(self, environ, start_response):
        parser = self.parser
        if environ['REQUEST_METHOD'] != 'POST':
            start_response('200 OK', as_html)
            yield b'<!DOCTYPE html>'
            yield bytes(self.my_doc)
            return
        # works in Python 3, untested in Python 2
        form = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ)
        # Did the user click on a help button?
        for action in self.submit_actions:
            if action.dest in form:
                start_response('200 OK', self.headers)
                yield parser.format_help().encode()
                return
        # Only parse values that we are expecting
        new_args = copy(self.args)
        for action in self.outputs:
            setattr(new_args, action.dest, StringIO())
        for action in parser._actions:
            key = action.dest
            if key in form:
                value = form.getvalue(key)
                setattr(new_args, key, value)
        for action in self.inputs:
            input = getattr(new_args, action.dest)
            if not hasattr(input, 'read'):
                if hasattr(input, 'decode'):
                    input = input.decode()
                input = StringIO(input)
                setattr(new_args, action.dest, input)
        status_code, reason_phrase = 500, 'OK'
        try:
            assert len(self.outputs) <= 1, 'too many output files'
            if 'help' in form:
                print('help', file=new_args.output)  # TODO
                sys.exit(0)
            else:
                sys.exit(self.runapp(new_args))
        except SystemExit as err:
            if not err.code:
                start_response('200 OK', self.headers)
                for action in self.outputs:
                    output = getattr(new_args, action.dest)
                    if hasattr(output, 'getvalue'):
                        output = output.getvalue()
                    if hasattr(output, 'encode'):
                        output = output.encode()
                    yield output
                return
            status_code, reason_phrase = 400, 'Bad Request'
            tb = None
        except Exception:
            sstatus_code, reason_phrase = 500, 'Internal Server Error'
            from traceback import format_exc
            tb = format_exc()
            with open('traceback.log', 'w') as log:
                print(tb, file=log)

        start_response('%d %s' % (status_code, reason_phrase), as_html)
        yield b'<!DOCTYPE html>'
        body = Body(Img(alt=reason_phrase,
                        src="https://http.cat/%d" % status_code))
        if tb:
            body += Pre(tb)
        yield bytes(Html(Head(), body))

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Process some integers.')
    parser.add_argument('--i1', type=argparse.FileType('r'))
    parser.add_argument('--i2', type=argparse.FileType('r'))
    parser.add_argument('--output', type=argparse.FileType('w'))
    #parser.add_argument('--o2', type=argparse.FileType('w'))
    args = parser.parse_args()

    def mycode(args):
        import sys
        print('args =', args)
        print('success!', file=args.output)  # TODO
##        raise ZeroDivisionError()
##        sys.exit(1)

    if False:
        from wsgiref.simple_server import make_server
        srv = make_server('', 8080, ArgParser(parser, args, mycode))
        print('listening on %s:%d...' % srv.server_address)
        srv.serve_forever()
    else:
        app = ArgParser(parser, args, mycode)

        print('*** GET ***')
        for item in app({'REQUEST_METHOD': 'GET'}, print):
            print('>', item)

        class FS(dict): getvalue = dict.get
        cgi.FieldStorage = lambda **kwds: FS(i1=b'foo', i2=b'bar')

        print('*** POST ***')
        for item in app({
            'REQUEST_METHOD': 'POST',
            'wsgi.input': None,
            }, print):
            print('>', item)
<commit_msg>allow graphs to run in any direction, not just left-to-right<commit_after>'''\
A tool to convert command-line tools into WSGI web applications.

A large number of CLI programs that look like this:

    def main():
        parser = argparse.ArgumentParser(...)
        args = parser.parse_args()
        mycode(args)

ArgParser lets you turn programs like these into web apps by changing a
few lines of code:

    def main():
        parser = argparse.ArgumentParser(...)
        args = argparse.Namespace()
        srv = wsgiref.simple_server.make_server(
            '', 8080, ArgParser(parser, args, mycode))

ArgParser analyzes *parser* and produces an HTML form that exposes
the same parameters.  Once that form is submitted, a copy of *args* will
be filled in and passed to *mycode*.

That's the simplist way to use this, but there are other options.  For
example, you can decide at run-time whether to run as a CLI program or a
web server by added arguments to the parser.  In that case, you will
want to remove those options from the parser before you pass it to
ArgParser.  For example:

    def main():
        parser = argparse.ArgumentParser(...)
        host_action = parser.add_argument(
            '--host', '-H', default='0.0.0.0')
        port_action = parser.add_argument(
            '--port', '-P', default=8080)
        args = parser.parse_args()
        if args.host or args.port:
            parser._remove_action(host_action)
            parser._remove_action(port_action)
            srv = wsgiref.simple_server.make_server(
                args.host, args.port, ArgParser(parser, args, mycode))
        else:
            mycode(args)

There are a few caveats, most stemming from the fact that *mycode* will
be called repeatedly. First, it should not call sys.exit().  (Someday it
will intercept the SystemExit exception, but not today.) Also, it should
clean up after itself, as any resource leaks will eventually cause the
web server to crash.
'''

from datetime import datetime
import os, sys

class WSGIdispatcher(object):
    """
    The main WSGI application. Dispatch the current request to
    the functions from above and store the regular expression
    captures in the WSGI environment as `myapp.url_args` so that
    the functions from above can access the url placeholders.

    As a convenience to developers, static files can be served by
    setting static_path to a directory.  If a matching file name can be
    found there, it is returned.  Limited support for cache control is
    provided via Last-Modified headers, however support is specifically
    excluded for multiple search directories, Etags and other cache
    control headers, and Range requests.

    If nothing matches, call the `not_found` function.
    """
    devfiles = set() if os.name == 'posix' else {
        'CON', 'AUX', 'COM1', 'COM2', 'COM3', 'COM4',
        'LPT1', 'LPT2', 'LPT3', 'PRN', 'NUL'}

    def __init__(self, *dispatch_table, static_path=None):
        import re
        end = '' if hasattr(re, 'fullmatch') else '$'
        self.static_path = static_path
        self.dispatch_table = [
            (re.compile(pattern+end), callback)
            for pattern, callback in dispatch_table
            ]

    def __call__(self, environ, start_response):
        path_info = environ.get('PATH_INFO', '')
        path = path_info.lstrip('/')
        for regex, callback in self.dispatch_table:
            match = regex.fullmatch(path)
            if match is not None:
                environ['myapp.url_args'] = match.groups()
                return callback(environ, start_response)
        if self.static_path:
            from mimetypes import guess_type
            from os.path import join, split, splitext

            head, tail = split(path)
            root, ext = splitext(tail)
            if root.upper() in self.devfiles:
                return self.not_found(environ, start_response)
            path = join(self.static_path, tail)
            try:
                with open(path, 'rb') as myfile:
                    type, encoding = guess_type(myfile.name)
                    headers = []
                    if type:
                        headers.append(('Content-Type', type))
                    if encoding:
                        headers.append(('Content-Encoding ', encoding))
                    fs = os.fstat(myfile.fileno())
                    headers.append(('Content-Length', str(fs.st_size)))
                    if_modified_since = environ.get('HTTP_IF_MODIFIED_SINCE', '')
                    last_modified = datetime.fromtimestamp(fs.st_mtime).strftime("%a, %d %b %Y %H:%M:%S GMT")
                    headers.append(('Last-Modified', last_modified))
                    if if_modified_since == last_modified:
                        start_response('304 Not Modified', headers)
                        return []
                    else:
                        start_response('200 OK', headers)
                        blksz = 65536
                        return [ myfile.read(blksz) ]

                        errors = environ['wsgi.errors']
                        if 'wsgi.file_wrapper' in environ:
##                            print('wsgi.file_wrapper', repr(myfile), file=errors)
                            return environ['wsgi.file_wrapper'](myfile, blksz)
                        else:
##                            print('iter()', repr(myfile), file=errors)
                            return iter(lambda: myfile.read(blksz), '')
            except (FileNotFoundError, IsADirectoryError, OSError):
##                print(
##                    'path = %r\nenviron = %r' % (path, environ),
##                    file=environ['wsgi.errors'])
                return self.not_found(environ, start_response)
        else:
            return self.not_found(environ, start_response)

    def not_found(self, environ, start_response):
        # per notfound.org, consider using an iframe that includes
        # https://d3o9f8o0i654j9.cloudfront.net/404/index.html
        start_response('404 Not Found', as_html)
        return [
            b'<!DOCTYPE html>',
            bytes(Html(Head(), Body(Img(alt="Not Found", src="https://http.cat/404"))))
            ]

from copy import copy
from io import StringIO
import argparse
import cgi

from htmltags import *

singular = set([None, 1, '?'])
optional = set(['?', '*'])

as_html = [('Content-Type', 'text/html')]

def popattr(*args):
    value = getattr(*args)
    try:
        delattr(*args[:2])
    except AttributeError:
        pass
    return value

class ArgParser(object):

    def __init__(self, parser, args, runapp,
                 headers=[('Content-Type', 'text/plain')],
                 skip_groups=set(),
                 submit_actions=(),
                 ):
        self.parser = parser
        self.args = args
        self.runapp = runapp
        self.skip_groups = skip_groups
        self.submit_actions = submit_actions
        self.headers = headers
        self.inputs = []
        self.outputs = []

        my_body = Body()
        my_form = Form(method='post', enctype='multipart/form-data')
        if parser.description:
            my_body += P(parser.description)
        my_body += my_form
        if parser.epilog:
            my_body += P(parser.epilog)

        for action_group in parser._action_groups:
            if not action_group._group_actions:
                continue
            if action_group.title in self.skip_groups:
                continue
            my_form += P(B(action_group.title.title()))
            my_table = Fieldset()
            my_form += my_table
            if action_group.description:
                my_table += P(action_group.description)
            for action in action_group._group_actions:
                try:
                    if submit_actions and isinstance(action, submit_actions):
                        continue
                    elif isinstance(action, argparse._HelpAction):
                        continue
                    elif action.nargs == 0:
                        input_tag = Input(type='checkbox')
                    elif action.choices:
                        input_tag = Select()
                        if action.nargs not in singular:
                            input_tag.setAttribute('multiple', None)
                        if action.nargs not in optional:
                            input_tag.setAttribute('required', None)
                        for option in action.choices:
                            if option == action.default:
                                input_tag += Option(option, value=option, selected=1)
                            else:
                                input_tag += Option(option, value=option)
                    elif isinstance(action.type, argparse.FileType):
                        if 'r' not in action.type._mode:
                            self.outputs.append(action)
                            continue
                        self.inputs.append(action)
                        input_tag = Input(type='file')
                    else:  #if issubclass(action.type, basestring):
                        input_tag = Input(type='text')
                except TypeError as err:
                    from traceback import format_exc
                    input_tag = Pre(format_exc())
                input_tag.setAttribute('name', action.dest)
                my_table += Label(action.dest.replace('_', ' ').title(), For=action.dest)
                my_table += input_tag
                if action.help:
                    my_table += P(I(action.help))
        my_form += Input(type="submit")
        for action in submit_actions:
            my_form += Input(type="submit",
                             name=action.dest,
                             value=action.dest.title())
        self.my_doc = Html(
            Head(
                Meta(
                    name="viewport",
                    content="width=device-width, initial-scale=1")
                ),
            my_body)

    def __call__(self, environ, start_response):
        parser = self.parser
        if environ['REQUEST_METHOD'] != 'POST':
            start_response('200 OK', as_html)
            yield b'<!DOCTYPE html>'
            yield bytes(self.my_doc)
            return
        # works in Python 3, untested in Python 2
        form = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ)
        # Did the user click on a help button?
        for action in self.submit_actions:
            if action.dest in form:
                start_response('200 OK', self.headers)
                yield parser.format_help().encode()
                return
        # Only parse values that we are expecting
        new_args = copy(self.args)
        for action in self.outputs:
            setattr(new_args, action.dest, StringIO())
        for action in parser._actions:
            key = action.dest
            if key in form:
                value = form.getvalue(key)
                setattr(new_args, key, value)
        for action in self.inputs:
            input = getattr(new_args, action.dest)
            if not hasattr(input, 'read'):
                if hasattr(input, 'decode'):
                    input = input.decode()
                input = StringIO(input)
                setattr(new_args, action.dest, input)
        status_code, reason_phrase = 500, 'OK'
        try:
            assert len(self.outputs) <= 1, 'too many output files'
            if 'help' in form:
                print('help', file=new_args.output)  # TODO
                sys.exit(0)
            else:
                sys.exit(self.runapp(new_args))
        except SystemExit as err:
            if not err.code:
                start_response('200 OK', self.headers)
                for action in self.outputs:
                    output = getattr(new_args, action.dest)
                    if hasattr(output, 'getvalue'):
                        output = output.getvalue()
                    if hasattr(output, 'encode'):
                        output = output.encode()
                    yield output
                return
            status_code, reason_phrase = 400, 'Bad Request'
            tb = None
        except Exception:
            sstatus_code, reason_phrase = 500, 'Internal Server Error'
            from traceback import format_exc
            tb = format_exc()
            with open('traceback.log', 'w') as log:
                print(tb, file=log)

        start_response('%d %s' % (status_code, reason_phrase), as_html)
        yield b'<!DOCTYPE html>'
        body = Body(Img(alt=reason_phrase,
                        src="https://http.cat/%d" % status_code))
        if tb:
            body += Pre(tb)
        yield bytes(Html(Head(), body))

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Process some integers.')
    parser.add_argument('--i1', type=argparse.FileType('r'))
    parser.add_argument('--i2', type=argparse.FileType('r'))
    parser.add_argument('--output', type=argparse.FileType('w'))
    #parser.add_argument('--o2', type=argparse.FileType('w'))
    args = parser.parse_args()

    def mycode(args):
        import sys
        print('args =', args)
        print('success!', file=args.output)  # TODO
##        raise ZeroDivisionError()
##        sys.exit(1)

    if False:
        from wsgiref.simple_server import make_server
        srv = make_server('', 8080, ArgParser(parser, args, mycode))
        print('listening on %s:%d...' % srv.server_address)
        srv.serve_forever()
    else:
        app = ArgParser(parser, args, mycode)

        print('*** GET ***')
        for item in app({'REQUEST_METHOD': 'GET'}, print):
            print('>', item)

        class FS(dict): getvalue = dict.get
        cgi.FieldStorage = lambda **kwds: FS(i1=b'foo', i2=b'bar')

        print('*** POST ***')
        for item in app({
            'REQUEST_METHOD': 'POST',
            'wsgi.input': None,
            }, print):
            print('>', item)
<|endoftext|>


<commit_before># -*- coding: UTF-8 -*-
# Copyright 2016 Luc Saffre
# This file is part of Lino Cosi.
#
# Lino Cosi 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.
#
# Lino Cosi 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 Lino Cosi.  If not, see
# <http://www.gnu.org/licenses/>.

"""

Import legacy data from TIM (including households, ...).
An extension of :mod:`tim2lino <lino_cosi.lib.tim2lino.fitxtures.tim2lino>`.

"""
from __future__ import unicode_literals
import datetime

from lino.utils import mti
from lino.api import dd, rt

from .timloader1 import TimLoader

Person = dd.resolve_model("contacts.Person")
Company = dd.resolve_model("contacts.Company")
RoleType = dd.resolve_model("contacts.RoleType")
Role = dd.resolve_model("contacts.Role")
Household = dd.resolve_model('households.Household')
Product = dd.resolve_model('products.Product')
List = dd.resolve_model('lists.List')
Member = dd.resolve_model('lists.Member')
households_Member = dd.resolve_model('households.Member')
Account = dd.resolve_model('accounts.Account')

clocking = dd.resolve_app('clocking')

User = rt.models.users.User
UserTypes = rt.models.users.UserTypes
Partner = rt.models.contacts.Partner

from lino.utils.instantiator import create

class TimLoader(TimLoader):

    # archived_tables = set('GEN ART VEN VNL JNL FIN FNL'.split())
    # archive_name = 'rumma'
    # has_projects = False
    # languages = 'de fr'

    def __init__(self, *args, **kwargs):
        super(TimLoader, self).__init__(*args, **kwargs)
        self.imported_sessions = set([])

    def par_pk(self, pk):
        if pk.startswith('E'):
            return 1000000 + int(pk[1:])
        elif pk.startswith('S'):
            return 2000000 + int(pk[1:])
        try:
            return int(pk)
        except ValueError:
            return None

    def par_class(self, data):
        prt = data.idprt
        if prt == 'L':  # Lieferant
            return Company
        elif prt == 'K':  # Krankenkasse
            return Company
        elif prt == 'S':  # Sonstige
            return Company
        elif prt == 'W':  # Netzwerkpartner
            return Company
        elif prt == 'R':  # Ärzte
            return Person
        elif prt == 'Z':  # Zahler
            return Company
        elif prt == 'P':  # Personen
            return Person
        elif prt == 'G':  # Lebensgruppen
            return Household
        elif prt == 'T':  # Therapeutische Gruppen
            return List
        #~ dblogger.warning("Unhandled PAR->IdPrt %r",prt)

    def load_par(self, row):
        for obj in super(TimLoader, self).load_par(row):
            if row.idpar.startswith('E'):
                obj.team = self.eupen
            elif row.idpar.startswith('S'):
                obj.team = self.stvith
            # if isinstance(obj, Partner):
            #     obj.isikukood = row['regkood'].strip()
            #     obj.created = row['datcrea']
            #     obj.modified = datetime.datetime.now()
            yield obj

    # def load_pls(self, row, **kw):
    #     kw.update(ref=row.idpls.strip())
    #     kw.update(name=row.name)
    #     return List(**kw)

    def get_user(self, idusr=None):
        try:
            return User.objects.get(username=idusr)
        except User.DoesNotExist:
            return None

    def load_usr(self, row, **kw):
        kw.update(username=row.userid.strip().lower())
        kw.update(first_name=row.name.strip())
        abtlg = row.abtlg.strip()
        if abtlg == 'E':
            kw.update(team=self.eupen)
        elif abtlg == 'S':
            kw.update(team=self.stvith)
        kw.update(profile=UserTypes.admin)
        o = User(**kw)
        o.set_password("1234")
        return o

    def load_mbr(self, row, **kw):

        p1 = self.get_customer(row.idpar)
        if p1 is None:
            dd.logger.debug(
                "Failed to load MBR %s : "
                "No idpar", row)
            return
        p2 = self.get_customer(row.idpar2)

        if p2 is not None:
            contact_role = self.contact_roles.get(row.idpls.strip())
            if contact_role is not None:
                kw = dict()
                p = mti.get_child(p1, Company)
                if p is None:
                    dd.logger.debug(
                        "Failed to load MBR %s : "
                        "idpar is not a company", row)
                    return
                kw.update(company=p)
                p = mti.get_child(p2, Person)
                if p is None:
                    dd.logger.debug(
                        "Failed to load MBR %s : "
                        "idpar2 is not a person", row)
                    return
                kw.update(person=p)
                kw.update(type=contact_role)
                return Role(**kw)

            role = self.household_roles.get(row.idpls.strip())
            if role is not None:
                household = mti.get_child(p1, Household)
                if household is None:
                    dd.logger.debug(
                        "Failed to load MBR %s : "
                        "idpar is not a household", row)
                    return
                person = mti.get_child(p2, Person)
                if person is None:
                    dd.logger.debug(
                        "Failed to load MBR %s : idpar2 is not a person", row)
                    return
                return households_Member(
                    household=household,
                    person=person,
                    role=role)
            dd.logger.debug(
                "Failed to load MBR %s : idpar2 is not empty", row)
            return

        try:
            lst = List.objects.get(ref=row.idpls.strip())
        except List.DoesNotExist:
            dd.logger.debug(
                "Failed to load MBR %s : unknown idpls", row)
            return
        kw.update(list=lst)
        kw.update(remark=row.remarq)
        kw.update(partner=p1)
        return Member(**kw)

    def load_dls(self, row, **kw):
        if not row.iddls.strip():
            return
        # if not row.idpin.strip():
        #     return
        pk = row.iddls.strip()
        idusr = row.idusr.strip()
        if pk.startswith('E'):
            team = self.eupen
            pk = int(pk[1:])
        elif pk.startswith('S'):
            team = self.stvith
            pk = int(pk[1:]) + 1000000

        if pk in self.imported_sessions:
            dd.logger.warning(
                "Cannot import duplicate session %s", pk)
            return
        self.imported_sessions.add(pk)
        u = self.get_user(idusr)
        if u is None:
            dd.logger.warning(
                "Cannot import session %s because there is no user %s",
                pk, idusr)
            return

        if u.team != team:
            u1 = u
            idusr += '@' + str(team.pk)
            try:
                u = User.objects.get(username=idusr)
            except User.DoesNotExist:
                u = create(
                    User, username=idusr, first_name=u1.first_name, team=team,
                    profile=u1.profile)

        kw.update(user=u)
        kw.update(id=pk)
        # if row.idprj.strip():
        #     kw.update(project_id=int(row.idprj))
            # kw.update(partner_id=PRJPAR.get(int(row.idprj),None))
        if row.idpar.strip():
            idpar = self.par_pk(row.idpar.strip())
            try:
                ticket = Partner.objects.get(id=idpar)
                kw.update(ticket=ticket)
            except Partner.DoesNotExist:
                dd.logger.warning(
                    "Cannot import session %s because there is no partner %d",
                    pk, idpar)
                return

        kw.update(summary=row.nb.strip())
        kw.update(start_date=row.date)

        def set_time(kw, fldname, v):
            v = v.strip()
            if not v:
                return
            if v == '24:00':
                v = '0:00'
            kw[fldname] = v

        set_time(kw, 'start_time', row.von)
        set_time(kw, 'end_time', row.bis)
        # set_time(kw, 'break_time', row.pause)
        # kw.update(start_time=row.von.strip())
        # kw.update(end_time=row.bis.strip())
        # kw.update(break_time=row.pause.strip())
        # kw.update(is_private=tim2bool(row.isprivat))
        obj = clocking.Session(**kw)
        # if row.idpar.strip():
            # partner_id = self.par_pk(row.idpar)
            # if obj.project and obj.project.partner \
                # and obj.project.partner.id == partner_id:
                # pass
            # elif obj.ticket and obj.ticket.partner \
                # and obj.ticket.partner.id == partner_id:
                # pass
            # else:
                # ~ dblogger.warning("Lost DLS->IdPar of DLS#%d" % pk)
        yield obj
        # if row.memo.strip():
        #     kw = dict(owner=obj)
        #     kw.update(body=self.dbfmemo(row.memo))
        #     kw.update(user=obj.user)
        #     kw.update(date=obj.start_date)
        #     yield rt.modules.notes.Note(**kw)

    def objects(self):

        Team = rt.modules.teams.Team
        self.eupen = create(Team, name="Eupen")
        yield self.eupen
        self.stvith = create(Team, name="St. Vith")
        yield self.stvith

        yield self.load_dbf('USR')

        MemberRoles = rt.modules.households.MemberRoles

        self.household_roles = {
            'VATER': MemberRoles.head,
            'MUTTER': MemberRoles.spouse,
            'KIND': MemberRoles.child,
            'K': MemberRoles.child,
        }

        self.contact_roles = cr = {}
        cr.update(DIR=RoleType.objects.get(pk=2))
        cr.update(A=RoleType.objects.get(pk=3))
        cr.update(SYSADM=RoleType.objects.get(pk=4))

        obj = RoleType(name="TIM user")
        yield obj
        cr.update(TIM=obj)
        obj = RoleType(name="Lino user")
        yield obj
        cr.update(LINO=obj)
        obj = RoleType(name="Board member")
        yield obj
        cr.update(VMKN=obj)
        obj = RoleType(name="Member")
        yield obj
        cr.update(M=obj)

        # self.PROD_617010 = Product(
        #     name="Edasimüük remondikulud",
        #     id=40)
        # yield self.PROD_617010

        # self.sales_gen2art['617010'] = self.PROD_617010

        yield super(TimLoader, self).objects()

        # yield self.load_dbf('PLS')
        # yield self.load_dbf('MBR')

        # if False:  # and GET_THEM_ALL:
        #     yield self.load_dbf('PIN')
        yield self.load_dbf('DLS')

<commit_msg>spzloader get_user<commit_after># -*- coding: UTF-8 -*-
# Copyright 2016 Luc Saffre
# This file is part of Lino Cosi.
#
# Lino Cosi 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.
#
# Lino Cosi 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 Lino Cosi.  If not, see
# <http://www.gnu.org/licenses/>.

"""

Import legacy data from TIM (including households, ...).
An extension of :mod:`tim2lino <lino_cosi.lib.tim2lino.fitxtures.tim2lino>`.

"""
from __future__ import unicode_literals
import datetime

from lino.utils import mti
from lino.api import dd, rt

from .timloader1 import TimLoader

Person = dd.resolve_model("contacts.Person")
Company = dd.resolve_model("contacts.Company")
RoleType = dd.resolve_model("contacts.RoleType")
Role = dd.resolve_model("contacts.Role")
Household = dd.resolve_model('households.Household')
Product = dd.resolve_model('products.Product')
List = dd.resolve_model('lists.List')
Member = dd.resolve_model('lists.Member')
households_Member = dd.resolve_model('households.Member')
Account = dd.resolve_model('accounts.Account')

clocking = dd.resolve_app('clocking')

User = rt.models.users.User
UserTypes = rt.models.users.UserTypes
Partner = rt.models.contacts.Partner

from lino.utils.instantiator import create

class TimLoader(TimLoader):

    # archived_tables = set('GEN ART VEN VNL JNL FIN FNL'.split())
    # archive_name = 'rumma'
    # has_projects = False
    # languages = 'de fr'

    def __init__(self, *args, **kwargs):
        super(TimLoader, self).__init__(*args, **kwargs)
        self.imported_sessions = set([])

    def par_pk(self, pk):
        if pk.startswith('E'):
            return 1000000 + int(pk[1:])
        elif pk.startswith('S'):
            return 2000000 + int(pk[1:])
        try:
            return int(pk)
        except ValueError:
            return None

    def par_class(self, data):
        prt = data.idprt
        if prt == 'L':  # Lieferant
            return Company
        elif prt == 'K':  # Krankenkasse
            return Company
        elif prt == 'S':  # Sonstige
            return Company
        elif prt == 'W':  # Netzwerkpartner
            return Company
        elif prt == 'R':  # Ärzte
            return Person
        elif prt == 'Z':  # Zahler
            return Company
        elif prt == 'P':  # Personen
            return Person
        elif prt == 'G':  # Lebensgruppen
            return Household
        elif prt == 'T':  # Therapeutische Gruppen
            return List
        #~ dblogger.warning("Unhandled PAR->IdPrt %r",prt)

    def load_par(self, row):
        for obj in super(TimLoader, self).load_par(row):
            if row.idpar.startswith('E'):
                obj.team = self.eupen
            elif row.idpar.startswith('S'):
                obj.team = self.stvith
            # if isinstance(obj, Partner):
            #     obj.isikukood = row['regkood'].strip()
            #     obj.created = row['datcrea']
            #     obj.modified = datetime.datetime.now()
            yield obj

    # def load_pls(self, row, **kw):
    #     kw.update(ref=row.idpls.strip())
    #     kw.update(name=row.name)
    #     return List(**kw)

    def get_user(self, idusr=None):
        try:
            return User.objects.get(username=idusr.strip().lower())
        except User.DoesNotExist:
            return None

    def load_usr(self, row, **kw):
        kw.update(username=row.userid.strip().lower())
        kw.update(first_name=row.name.strip())
        abtlg = row.abtlg.strip()
        if abtlg == 'E':
            kw.update(team=self.eupen)
        elif abtlg == 'S':
            kw.update(team=self.stvith)
        kw.update(profile=UserTypes.admin)
        o = User(**kw)
        o.set_password("1234")
        return o

    def load_mbr(self, row, **kw):

        p1 = self.get_customer(row.idpar)
        if p1 is None:
            dd.logger.debug(
                "Failed to load MBR %s : "
                "No idpar", row)
            return
        p2 = self.get_customer(row.idpar2)

        if p2 is not None:
            contact_role = self.contact_roles.get(row.idpls.strip())
            if contact_role is not None:
                kw = dict()
                p = mti.get_child(p1, Company)
                if p is None:
                    dd.logger.debug(
                        "Failed to load MBR %s : "
                        "idpar is not a company", row)
                    return
                kw.update(company=p)
                p = mti.get_child(p2, Person)
                if p is None:
                    dd.logger.debug(
                        "Failed to load MBR %s : "
                        "idpar2 is not a person", row)
                    return
                kw.update(person=p)
                kw.update(type=contact_role)
                return Role(**kw)

            role = self.household_roles.get(row.idpls.strip())
            if role is not None:
                household = mti.get_child(p1, Household)
                if household is None:
                    dd.logger.debug(
                        "Failed to load MBR %s : "
                        "idpar is not a household", row)
                    return
                person = mti.get_child(p2, Person)
                if person is None:
                    dd.logger.debug(
                        "Failed to load MBR %s : idpar2 is not a person", row)
                    return
                return households_Member(
                    household=household,
                    person=person,
                    role=role)
            dd.logger.debug(
                "Failed to load MBR %s : idpar2 is not empty", row)
            return

        try:
            lst = List.objects.get(ref=row.idpls.strip())
        except List.DoesNotExist:
            dd.logger.debug(
                "Failed to load MBR %s : unknown idpls", row)
            return
        kw.update(list=lst)
        kw.update(remark=row.remarq)
        kw.update(partner=p1)
        return Member(**kw)

    def load_dls(self, row, **kw):
        if not row.iddls.strip():
            return
        # if not row.idpin.strip():
        #     return
        pk = row.iddls.strip()
        idusr = row.idusr.strip()
        if pk.startswith('E'):
            team = self.eupen
            pk = int(pk[1:])
        elif pk.startswith('S'):
            team = self.stvith
            pk = int(pk[1:]) + 1000000

        if pk in self.imported_sessions:
            dd.logger.warning(
                "Cannot import duplicate session %s", pk)
            return
        self.imported_sessions.add(pk)
        u = self.get_user(idusr)
        if u is None:
            dd.logger.warning(
                "Cannot import session %s because there is no user %s",
                pk, idusr)
            return

        if u.team != team:
            u1 = u
            idusr += '@' + str(team.pk)
            try:
                u = User.objects.get(username=idusr)
            except User.DoesNotExist:
                u = create(
                    User, username=idusr, first_name=u1.first_name, team=team,
                    profile=u1.profile)

        kw.update(user=u)
        kw.update(id=pk)
        # if row.idprj.strip():
        #     kw.update(project_id=int(row.idprj))
            # kw.update(partner_id=PRJPAR.get(int(row.idprj),None))
        if row.idpar.strip():
            idpar = self.par_pk(row.idpar.strip())
            try:
                ticket = Partner.objects.get(id=idpar)
                kw.update(ticket=ticket)
            except Partner.DoesNotExist:
                dd.logger.warning(
                    "Cannot import session %s because there is no partner %d",
                    pk, idpar)
                return

        kw.update(summary=row.nb.strip())
        kw.update(start_date=row.date)

        def set_time(kw, fldname, v):
            v = v.strip()
            if not v:
                return
            if v == '24:00':
                v = '0:00'
            kw[fldname] = v

        set_time(kw, 'start_time', row.von)
        set_time(kw, 'end_time', row.bis)
        # set_time(kw, 'break_time', row.pause)
        # kw.update(start_time=row.von.strip())
        # kw.update(end_time=row.bis.strip())
        # kw.update(break_time=row.pause.strip())
        # kw.update(is_private=tim2bool(row.isprivat))
        obj = clocking.Session(**kw)
        # if row.idpar.strip():
            # partner_id = self.par_pk(row.idpar)
            # if obj.project and obj.project.partner \
                # and obj.project.partner.id == partner_id:
                # pass
            # elif obj.ticket and obj.ticket.partner \
                # and obj.ticket.partner.id == partner_id:
                # pass
            # else:
                # ~ dblogger.warning("Lost DLS->IdPar of DLS#%d" % pk)
        yield obj
        # if row.memo.strip():
        #     kw = dict(owner=obj)
        #     kw.update(body=self.dbfmemo(row.memo))
        #     kw.update(user=obj.user)
        #     kw.update(date=obj.start_date)
        #     yield rt.modules.notes.Note(**kw)

    def objects(self):

        Team = rt.modules.teams.Team
        self.eupen = create(Team, name="Eupen")
        yield self.eupen
        self.stvith = create(Team, name="St. Vith")
        yield self.stvith

        yield self.load_dbf('USR')

        MemberRoles = rt.modules.households.MemberRoles

        self.household_roles = {
            'VATER': MemberRoles.head,
            'MUTTER': MemberRoles.spouse,
            'KIND': MemberRoles.child,
            'K': MemberRoles.child,
        }

        self.contact_roles = cr = {}
        cr.update(DIR=RoleType.objects.get(pk=2))
        cr.update(A=RoleType.objects.get(pk=3))
        cr.update(SYSADM=RoleType.objects.get(pk=4))

        obj = RoleType(name="TIM user")
        yield obj
        cr.update(TIM=obj)
        obj = RoleType(name="Lino user")
        yield obj
        cr.update(LINO=obj)
        obj = RoleType(name="Board member")
        yield obj
        cr.update(VMKN=obj)
        obj = RoleType(name="Member")
        yield obj
        cr.update(M=obj)

        # self.PROD_617010 = Product(
        #     name="Edasimüük remondikulud",
        #     id=40)
        # yield self.PROD_617010

        # self.sales_gen2art['617010'] = self.PROD_617010

        yield super(TimLoader, self).objects()

        # yield self.load_dbf('PLS')
        # yield self.load_dbf('MBR')

        # if False:  # and GET_THEM_ALL:
        #     yield self.load_dbf('PIN')
        yield self.load_dbf('DLS')

<|endoftext|>


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

from nmigen import *
from nmigen_cfu import SimpleElaboratable, InstructionBase, TestBase, InstructionTestBase, Cfu, CfuTestBase

import unittest

class StoreInstruction(InstructionBase):
    def __init__(self):
        super().__init__()
        self.max_width = Signal(signed(32))
        self.max_height = Signal(signed(32))

    def elab(self, m):
        with m.If(self.start):
            with m.If(self.in0 == 10):
                m.d.sync += self.max_width.eq(self.in1s)
            with m.Elif(self.in0 == 11):
                m.d.sync += self.max_height.eq(self.in1s)
            m.d.comb += [
                self.done.eq(1),
                self.output.eq(1),
            ]
        return m

class StoreInstructionTest(TestBase):
    def create_dut(self):
        return StoreInstruction()

    def test_start(self):
        DATA = [
            # Only set max_width and max_height when start is 1.
            ((1,10,5),(1,1,0,0)),
            ((1,11,6),(1,1,5,0)),
            # Check that when start is 0, max_width and max_height remains the same.
            ((0,5,7),(0,0,5,6)),
            ((0,1,1),(0,0,5,6)),
            ((1,10,7),(1,1,5,6)),
            ((0,0,0),(0,0,7,6)),
            ((1,11,9),(1,1,7,6)),
            ((0,2,3),(0,0,7,9)),
            ((1,9,19),(1,1,7,9)),
            ((0,4,3),(0,0,7,9)),
            ((1,10,-3),(1,1,7,9)),
            ((0,1,6),(0,0,-3,9)),
            ((1,11,-4),(1,1,-3,9)),
            ((0,1,3),(0,0,-3,-4)),
        ]
        def process():
            for n,(inputs,outputs) in enumerate(DATA):
                start,in0,in1s = inputs
                done,output,width,height = outputs
                yield self.dut.start.eq(start)
                yield self.dut.in0.eq(in0)
                yield self.dut.in1.eq(in1s)
                yield
                self.assertEqual((yield self.dut.done),done)
                self.assertEqual((yield self.dut.output),output)
                self.assertEqual((yield self.dut.max_width),width)
                self.assertEqual((yield self.dut.max_height),height)
        self.run_sim(process, True)

class DoubleCompareInstruction(InstructionBase):
    """The 4 comparisons will be performed in parallel
    """
    def __init__(self):
        super().__init__()
        self.max_width = Signal(signed(32))
        self.max_height = Signal(signed(32))

    def elab(self, m):
        m.d.comb += [
            self.output.eq((self.in0s >= 0) & (self.in0s < self.max_width) & (self.in1s >= 0) & (self.in1s < self.max_height)),
            self.done.eq(1)
        ]

class DoubleCompareInstructionTest(TestBase):
    def create_dut(self):
        return DoubleCompareInstruction()

    def test_double_compare(self):
        DATA = [
            ((0,0,2,2),1),
            ((4,5,4,5),0),
            ((19,20,10,10),0),
            ((11,13,11,12),0),
            ((18,20,19,21),1),
            ((-3,1,5,6),0),
            ((-2,-2,5,6),0),
        ]
        def process():
            for n,(inputs,expected_output) in enumerate(DATA):
                in0,in1,width,height = inputs
                yield self.dut.in0.eq(in0)
                yield self.dut.in1.eq(in1)
                yield self.dut.max_width.eq(width)
                yield self.dut.max_height.eq(height)
                yield
                self.assertEqual((yield self.dut.output),expected_output)
        self.run_sim(process, True)

class DoubleCompareCfu(Cfu):
    def __init__(self):
        self.dc = DoubleCompareInstruction()
        self.store = StoreInstruction()
        super().__init__({
            0: self.dc,
            1: self.store,
        })

    def elab(self,m):
        super().elab(m)
        m.d.comb += [
            self.dc.max_height.eq(self.store.max_height),
            self.dc.max_width.eq(self.store.max_width),
        ]

class DoubleCompareCfuTest(CfuTestBase):
    def create_dut(self):
        return DoubleCompareCfu()

    def test_double_compare_cfu(self):
        DATA = [
            # Set the max_width and max_height values.
            ((1,10,6),None),
            ((1,11,7),None),
            # Start the compare of in_x and in_y.
            ((0,1,1),1),
            ((0,5,6),1),
            ((0,0,0),1),
            ((0,5,7),0),
            ((0,6,7),0),
            ((0,10,10),0),
            # Test that negative values of in_x or in_y are not in range.
            ((0,-7,7),0),
            ((0,-10,-10),0),
            # Set the max_width and max_height values.
            ((1,10,20),None),
            ((1,11,18),None),
            # Start the compare of in_x and in_y.
            ((0,10,12),1),
            ((0,3,10),1),
            ((0,19,17),1),
            ((0,20,20),0),
            ((0,24,25),0),
        ]
        return self.run_ops(DATA)

def make_cfu():
    return DoubleCompareCfu()

if __name__ == '__main__':
    unittest.main()<commit_msg>Read Instruction:<commit_after>#!/bin/env python
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from nmigen import *
from nmigen_cfu import SimpleElaboratable, InstructionBase, TestBase, InstructionTestBase, Cfu, CfuTestBase

import unittest

class StoreInstruction(InstructionBase):
    def __init__(self):
        super().__init__()
        self.max_width = Signal(signed(32))
        self.max_height = Signal(signed(32))

    def elab(self, m):
        with m.If(self.start):
            with m.If(self.in0 == 10):
                m.d.sync += self.max_width.eq(self.in1s)
            with m.Elif(self.in0 == 11):
                m.d.sync += self.max_height.eq(self.in1s)
            m.d.comb += [
                self.done.eq(1),
                self.output.eq(1),
            ]
        return m

class StoreInstructionTest(TestBase):
    def create_dut(self):
        return StoreInstruction()

    def test_start(self):
        DATA = [
            # Only set max_width and max_height when start is 1.
            ((1,10,5),(1,1,0,0)),
            ((1,11,6),(1,1,5,0)),
            # Check that when start is 0, max_width and max_height remains the same.
            ((0,5,7),(0,0,5,6)),
            ((0,1,1),(0,0,5,6)),
            ((1,10,7),(1,1,5,6)),
            ((0,0,0),(0,0,7,6)),
            ((1,11,9),(1,1,7,6)),
            ((0,2,3),(0,0,7,9)),
            ((1,9,19),(1,1,7,9)),
            ((0,4,3),(0,0,7,9)),
            ((1,10,-3),(1,1,7,9)),
            ((0,1,6),(0,0,-3,9)),
            ((1,11,-4),(1,1,-3,9)),
            ((0,1,3),(0,0,-3,-4)),
        ]
        def process():
            for n,(inputs,outputs) in enumerate(DATA):
                start,in0,in1s = inputs
                done,output,width,height = outputs
                yield self.dut.start.eq(start)
                yield self.dut.in0.eq(in0)
                yield self.dut.in1.eq(in1s)
                yield
                self.assertEqual((yield self.dut.done),done)
                self.assertEqual((yield self.dut.output),output)
                self.assertEqual((yield self.dut.max_width),width)
                self.assertEqual((yield self.dut.max_height),height)
        self.run_sim(process, True)

class ReadInstruction(InstructionBase):
    def __init__(self):
        super().__init__()
        self.max_width = Signal(signed(32))
        self.max_height = Signal(signed(32))

    def elab(self, m):
        with m.If(self.in0 == 10):
            m.d.comb += [
                self.output.eq(self.max_width),
                self.done.eq(1)
            ]
        with m.Elif(self.in0 == 11):
            m.d.comb += [
                self.output.eq(self.max_height),
                self.done.eq(1)
            ]
        return m

class ReadInstructionTest(TestBase):
    def create_dut(self):
        return ReadInstruction()

    def test_start(self):
        def process():
            width = 1234
            height = 5678
            yield self.dut.done.eq(1)
            yield self.dut.max_width.eq(width)
            yield self.dut.max_height.eq(height)
            yield self.dut.in0.eq(10)
            yield
            self.assertEqual((yield self.dut.output),width)
            yield self.dut.in0.eq(11)
            yield
            self.assertEqual((yield self.dut.output),height)
        self.run_sim(process, True)

class DoubleCompareInstruction(InstructionBase):
    """The 4 comparisons will be performed in parallel
    """
    def __init__(self):
        super().__init__()
        self.max_width = Signal(signed(32))
        self.max_height = Signal(signed(32))

    def elab(self, m):
        m.d.comb += [
            self.output.eq((self.in0s >= 0) & (self.in0s < self.max_width) & (self.in1s >= 0) & (self.in1s < self.max_height)),
            self.done.eq(1)
        ]

class DoubleCompareInstructionTest(TestBase):
    def create_dut(self):
        return DoubleCompareInstruction()

    def test_double_compare(self):
        DATA = [
            ((0,0,2,2),1),
            ((4,5,4,5),0),
            ((19,20,10,10),0),
            ((11,13,11,12),0),
            ((18,20,19,21),1),
            ((-3,1,5,6),0),
            ((-2,-2,5,6),0),
        ]
        def process():
            for n,(inputs,expected_output) in enumerate(DATA):
                in0,in1,width,height = inputs
                yield self.dut.in0.eq(in0)
                yield self.dut.in1.eq(in1)
                yield self.dut.max_width.eq(width)
                yield self.dut.max_height.eq(height)
                yield
                self.assertEqual((yield self.dut.output),expected_output)
        self.run_sim(process, True)

class DoubleCompareCfu(Cfu):
    def __init__(self):
        self.dc = DoubleCompareInstruction()
        self.store = StoreInstruction()
        super().__init__({
            0: self.dc,
            1: self.store,
        })

    def elab(self,m):
        super().elab(m)
        m.d.comb += [
            self.dc.max_height.eq(self.store.max_height),
            self.dc.max_width.eq(self.store.max_width),
        ]

class DoubleCompareCfuTest(CfuTestBase):
    def create_dut(self):
        return DoubleCompareCfu()

    def test_double_compare_cfu(self):
        DATA = [
            # Set the max_width and max_height values.
            ((1,10,6),None),
            ((1,11,7),None),
            # Start the compare of in_x and in_y.
            ((0,1,1),1),
            ((0,5,6),1),
            ((0,0,0),1),
            ((0,5,7),0),
            ((0,6,7),0),
            ((0,10,10),0),
            # Test that negative values of in_x or in_y are not in range.
            ((0,-7,7),0),
            ((0,-10,-10),0),
            # Set the max_width and max_height values.
            ((1,10,20),None),
            ((1,11,18),None),
            # Start the compare of in_x and in_y.
            ((0,10,12),1),
            ((0,3,10),1),
            ((0,19,17),1),
            ((0,20,20),0),
            ((0,24,25),0),
        ]
        return self.run_ops(DATA)

def make_cfu():
    return DoubleCompareCfu()

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


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

"""
Ansible module to configure .deb packages.
(c) 2014, Brian Coca <briancoca+ansible@gmail.com>

This file is part of Ansible

Ansible 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.

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

DOCUMENTATION = '''
---
module: debconf
short_description: Configure a .deb package
description:
     - Configure a .deb package using debconf-set-selections. Or just query
       existing selections.
version_added: "1.6"
notes:
    - This module requires the command line debconf tools.
    - A number of questions have to be answered (depending on the package).
      Use 'debconf-show <package>' on any Debian or derivative with the package
      installed to see questions/settings available.
    - Some distros will always record tasks involving the setting of passwords as changed. This is due to debconf-get-selections masking passwords.
requirements: [ debconf, debconf-utils ]
options:
  name:
    description:
      - Name of package to configure.
    required: true
    default: null
    aliases: ['pkg']
  question:
    description:
      - A debconf configuration setting
    required: false
    default: null
    aliases: ['setting', 'selection']
  vtype:
    description:
      - The type of the value supplied.
      - C(seen) was added in 2.2.
    required: false
    default: null
    choices: [string, password, boolean, select, multiselect, note, error, title, text, seen]
  value:
    description:
      -  Value to set the configuration to
    required: false
    default: null
    aliases: ['answer']
  unseen:
    description:
      - Do not set 'seen' flag when pre-seeding
    required: false
    default: False
author: "Brian Coca (@bcoca)"

'''

EXAMPLES = '''
# Set default locale to fr_FR.UTF-8
debconf: name=locales question='locales/default_environment_locale' value=fr_FR.UTF-8 vtype='select'

# set to generate locales:
debconf: name=locales question='locales/locales_to_be_generated'  value='en_US.UTF-8 UTF-8, fr_FR.UTF-8 UTF-8' vtype='multiselect'

# Accept oracle license
debconf: name='oracle-java7-installer' question='shared/accepted-oracle-license-v1-1' value='true' vtype='select'

# Specifying package you can register/return the list of questions and current values
debconf: name='tzdata'
'''

def get_selections(module, pkg):
    cmd = [module.get_bin_path('debconf-show', True), pkg]
    rc, out, err = module.run_command(' '.join(cmd))

    if rc != 0:
        module.fail_json(msg=err)

    selections = {}

    for line in out.splitlines():
        (key, value) = line.split(':', 1)
        selections[ key.strip('*').strip() ] = value.strip()

    return selections

def set_selection(module, pkg, question, vtype, value, unseen):

    setsel = module.get_bin_path('debconf-set-selections', True)
    cmd = [setsel]
    if unseen:
        cmd.append('-u')

    data = ' '.join([pkg, question, vtype, value])

    return module.run_command(cmd, data=data)

def main():

    module = AnsibleModule(
        argument_spec = dict(
           name = dict(required=True, aliases=['pkg'], type='str'),
           question = dict(required=False, aliases=['setting', 'selection'], type='str'),
           vtype = dict(required=False, type='str', choices=['string', 'password', 'boolean', 'select',  'multiselect', 'note', 'error', 'title', 'text', 'seen']),
           value= dict(required=False, type='str'),
           unseen = dict(required=False, type='bool'),
        ),
        required_together = ( ['question','vtype', 'value'],),
        supports_check_mode=True,
    )

    #TODO: enable passing array of options and/or debconf file from get-selections dump
    pkg      = module.params["name"]
    question = module.params["question"]
    vtype    = module.params["vtype"]
    value    = module.params["value"]
    unseen   = module.params["unseen"]

    prev = get_selections(module, pkg)

    changed = False
    msg = ""

    if question is not None:
        if vtype is None or value is None:
            module.fail_json(msg="when supplying a question you must supply a valid vtype and value")

        if not question in prev or prev[question] != value:
            changed = True

    if changed:
        if not module.check_mode:
            rc, msg, e = set_selection(module, pkg, question, vtype, value, unseen)
            if rc:
                module.fail_json(msg=e)

        curr = { question: value }
        if question in prev:
            prev = {question: prev[question]}
        else:
            prev[question] = ''

        module.exit_json(changed=changed, msg=msg, current=curr, previous=prev)

    module.exit_json(changed=changed, msg=msg, current=prev)

# import module snippets
from ansible.module_utils.basic import *

main()
<commit_msg>Added 'answer' as an alias of 'value' on debconf module (#2464)<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
Ansible module to configure .deb packages.
(c) 2014, Brian Coca <briancoca+ansible@gmail.com>

This file is part of Ansible

Ansible 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.

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

DOCUMENTATION = '''
---
module: debconf
short_description: Configure a .deb package
description:
     - Configure a .deb package using debconf-set-selections. Or just query
       existing selections.
version_added: "1.6"
notes:
    - This module requires the command line debconf tools.
    - A number of questions have to be answered (depending on the package).
      Use 'debconf-show <package>' on any Debian or derivative with the package
      installed to see questions/settings available.
    - Some distros will always record tasks involving the setting of passwords as changed. This is due to debconf-get-selections masking passwords.
requirements: [ debconf, debconf-utils ]
options:
  name:
    description:
      - Name of package to configure.
    required: true
    default: null
    aliases: ['pkg']
  question:
    description:
      - A debconf configuration setting
    required: false
    default: null
    aliases: ['setting', 'selection']
  vtype:
    description:
      - The type of the value supplied.
      - C(seen) was added in 2.2.
    required: false
    default: null
    choices: [string, password, boolean, select, multiselect, note, error, title, text, seen]
  value:
    description:
      -  Value to set the configuration to
    required: false
    default: null
    aliases: ['answer']
  unseen:
    description:
      - Do not set 'seen' flag when pre-seeding
    required: false
    default: False
author: "Brian Coca (@bcoca)"

'''

EXAMPLES = '''
# Set default locale to fr_FR.UTF-8
debconf: name=locales question='locales/default_environment_locale' value=fr_FR.UTF-8 vtype='select'

# set to generate locales:
debconf: name=locales question='locales/locales_to_be_generated'  value='en_US.UTF-8 UTF-8, fr_FR.UTF-8 UTF-8' vtype='multiselect'

# Accept oracle license
debconf: name='oracle-java7-installer' question='shared/accepted-oracle-license-v1-1' value='true' vtype='select'

# Specifying package you can register/return the list of questions and current values
debconf: name='tzdata'
'''

def get_selections(module, pkg):
    cmd = [module.get_bin_path('debconf-show', True), pkg]
    rc, out, err = module.run_command(' '.join(cmd))

    if rc != 0:
        module.fail_json(msg=err)

    selections = {}

    for line in out.splitlines():
        (key, value) = line.split(':', 1)
        selections[ key.strip('*').strip() ] = value.strip()

    return selections

def set_selection(module, pkg, question, vtype, value, unseen):

    setsel = module.get_bin_path('debconf-set-selections', True)
    cmd = [setsel]
    if unseen:
        cmd.append('-u')

    data = ' '.join([pkg, question, vtype, value])

    return module.run_command(cmd, data=data)

def main():

    module = AnsibleModule(
        argument_spec = dict(
           name = dict(required=True, aliases=['pkg'], type='str'),
           question = dict(required=False, aliases=['setting', 'selection'], type='str'),
           vtype = dict(required=False, type='str', choices=['string', 'password', 'boolean', 'select',  'multiselect', 'note', 'error', 'title', 'text', 'seen']),
           value = dict(required=False, type='str', aliases=['answer']),
           unseen = dict(required=False, type='bool'),
        ),
        required_together = ( ['question','vtype', 'value'],),
        supports_check_mode=True,
    )

    #TODO: enable passing array of options and/or debconf file from get-selections dump
    pkg      = module.params["name"]
    question = module.params["question"]
    vtype    = module.params["vtype"]
    value    = module.params["value"]
    unseen   = module.params["unseen"]

    prev = get_selections(module, pkg)

    changed = False
    msg = ""

    if question is not None:
        if vtype is None or value is None:
            module.fail_json(msg="when supplying a question you must supply a valid vtype and value")

        if not question in prev or prev[question] != value:
            changed = True

    if changed:
        if not module.check_mode:
            rc, msg, e = set_selection(module, pkg, question, vtype, value, unseen)
            if rc:
                module.fail_json(msg=e)

        curr = { question: value }
        if question in prev:
            prev = {question: prev[question]}
        else:
            prev[question] = ''

        module.exit_json(changed=changed, msg=msg, current=curr, previous=prev)

    module.exit_json(changed=changed, msg=msg, current=prev)

# import module snippets
from ansible.module_utils.basic import *

main()
<|endoftext|>


<commit_before># -*- coding: UTF-8 -*-
# Copyright 2015-2018 Rumma & Ko Ltd
# This file is part of Lino Welfare.
#
# Lino Welfare 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.
#
# Lino Welfare 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 Lino Welfare.  If not, see
# <http://www.gnu.org/licenses/>.

from __future__ import unicode_literals

import logging

logger = logging.getLogger(__name__)

from django.db import models
from django.utils.translation import ugettext_lazy as _

from lino.api import dd
from lino import mixins

from lino_welfare.modlib.integ.roles import IntegUser, IntegrationStaff

from lino_welfare.modlib.isip.mixins import (ContractBaseTable,
                                             ContractTypeBase)
from lino_welfare.modlib.jobs.mixins import JobSupplyment

from .choicelists import Subsidizations

from lino_xl.lib.coachings.utils import has_contracts_filter
from lino_xl.lib.clients.choicelists import ClientEvents, ObservedEvent
from lino_welfare.modlib.pcsw.roles import SocialCoordinator

class ClientHasContract(ObservedEvent):
    text = _("Art61 job supplyment")

    def add_filter(self, qs, pv):
        period = (pv.start_date, pv.end_date)
        flt = has_contracts_filter('art61_contract_set_by_client', period)
        qs = qs.filter(flt).distinct()
        return qs

ClientEvents.add_item_instance(ClientHasContract("art61"))

class ContractType(ContractTypeBase, mixins.Referrable):

    preferred_foreignkey_width = 20

    templates_group = 'art61/Contract'

    class Meta:
        verbose_name = _("Art61 job supplyment type")
        verbose_name_plural = _('Art61 job supplyment types')
        ordering = ['name']

class ContractTypes(dd.Table):
    required_roles = dd.login_required(IntegrationStaff)
    model = ContractType
    column_names = 'name ref *'
    detail_layout = """
    id name ref overlap_group
    ContractsByType
    """

class Contract(JobSupplyment):

    class Meta:
        verbose_name = _("Art61 job supplyment")
        verbose_name_plural = _('Art61 job supplyments')

    type = dd.ForeignKey(
        "art61.ContractType",
        verbose_name=_("Type"),
        related_name="%(app_label)s_%(class)s_set_by_type")

    # The following four fields are the same as in `cv.Experience`
    # except that `duration` is `cv_duration` because we have already
    # another field `duration` (number of days) from `JobSupplyment`
    job_title = models.CharField(
        max_length=200, verbose_name=_("Job title"), blank=True)
    status = dd.ForeignKey('cv.Status', blank=True, null=True)
    cv_duration = dd.ForeignKey('cv.Duration', blank=True, null=True)
    regime = dd.ForeignKey(
        'cv.Regime', blank=True, null=True,
        related_name="art61_contracts")

    @classmethod
    def get_certifiable_fields(cls):
        return (
            'client type company contact_person contact_role '
            'applies_from applies_until duration '
            'language job_title status cv_duration regime '
            'reference_person responsibilities '
            'user user_asd exam_policy '
            'date_decided date_issued ')

    def get_subsidizations(self):
        for sub in Subsidizations.items():
            if getattr(self, sub.contract_field_name()):
                yield sub

    def get_excerpt_options(self, ar, **kw):
        # Implements :meth:`lino.printing.Printable.get_excerpt_options`.

        # When printing a contract, there is no recipient.

        kw = super(Contract, self).get_excerpt_options(ar, **kw)
        del kw['company']
        del kw['contact_person']
        del kw['contact_role']
        return kw

# dd.update_field(Contract, 'user', verbose_name=_("responsible (IS)"))
dd.update_field(Contract, 'company', blank=False, null=False)

class ContractDetail(dd.DetailLayout):
    box1 = """
    id:8 client:25 user:15 language:8
    type company contact_person contact_role
    applies_from duration applies_until exam_policy
    job_title status cv_duration regime
    reference_person remark printed
    date_decided date_issued date_ended ending:20
    subsidize_10 subsidize_20 subsidize_30 subsidize_40 subsidize_50
    # signer1 signer2
    responsibilities
    """

    right = """
    cal.EntriesByController
    cal.TasksByController
    """

    main = """
    box1:70 right:30
    """

class Contracts(ContractBaseTable):
    #~ debug_permissions = "20130222"
    required_roles = dd.login_required(IntegUser)
    model = 'art61.Contract'
    column_names = 'id client client__national_id ' \
                   'applies_from date_ended user type *'
    order_by = ['id']
    detail_layout = ContractDetail()
    insert_layout = """
    client
    company
    type
    """

    parameters = dict(
        type=dd.ForeignKey(
            'art61.ContractType', blank=True,
            verbose_name=_("Only job supplies of type")),
        **ContractBaseTable.parameters)

    params_layout = """
    user type start_date end_date observed_event
    company ending_success ending
    """

    @classmethod
    def get_request_queryset(cls, ar):
        qs = super(Contracts, cls).get_request_queryset(ar)
        pv = ar.param_values
        if pv.company:
            qs = qs.filter(company=pv.company)
        return qs

class ContractsByClient(Contracts):
    required_roles = dd.login_required((IntegUser, SocialCoordinator))
    label = _("Art61 job supplyments and activations")
    master_key = 'client'
    auto_fit_column_widths = True
    column_names = 'applies_from applies_until date_ended duration type '\
                   'company contact_person user remark:20 '\
                   'subsidize_10 subsidize_20 subsidize_30 subsidize_40 subsidize_50 *'

class ContractsByProvider(Contracts):
    master_key = 'company'
    column_names = 'client applies_from applies_until user type *'

class ContractsByPolicy(Contracts):
    master_key = 'exam_policy'

class ContractsByType(Contracts):
    master_key = 'type'
    column_names = "applies_from client user *"
    order_by = ["applies_from"]

class ContractsByEnding(Contracts):
    master_key = 'ending'

class MyContracts(Contracts):
    column_names = ("applies_from client type company applies_until "
                    "date_ended ending *")

    @classmethod
    def param_defaults(self, ar, **kw):
        kw = super(MyContracts, self).param_defaults(ar, **kw)
        kw.update(user=ar.get_user())
        return kw

@dd.receiver(dd.pre_analyze)
def inject_subsidization_fields(sender, **kw):
    for sub in Subsidizations.items():
        dd.inject_field(
            'art61.Contract', sub.contract_field_name(),
            models.BooleanField(verbose_name=sub.text, default=False))
<commit_msg>#2886: Add more space to the overlap_group field<commit_after># -*- coding: UTF-8 -*-
# Copyright 2015-2018 Rumma & Ko Ltd
# This file is part of Lino Welfare.
#
# Lino Welfare 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.
#
# Lino Welfare 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 Lino Welfare.  If not, see
# <http://www.gnu.org/licenses/>.

from __future__ import unicode_literals

import logging

logger = logging.getLogger(__name__)

from django.db import models
from django.utils.translation import ugettext_lazy as _

from lino.api import dd
from lino import mixins

from lino_welfare.modlib.integ.roles import IntegUser, IntegrationStaff

from lino_welfare.modlib.isip.mixins import (ContractBaseTable,
                                             ContractTypeBase)
from lino_welfare.modlib.jobs.mixins import JobSupplyment

from .choicelists import Subsidizations

from lino_xl.lib.coachings.utils import has_contracts_filter
from lino_xl.lib.clients.choicelists import ClientEvents, ObservedEvent
from lino_welfare.modlib.pcsw.roles import SocialCoordinator

class ClientHasContract(ObservedEvent):
    text = _("Art61 job supplyment")

    def add_filter(self, qs, pv):
        period = (pv.start_date, pv.end_date)
        flt = has_contracts_filter('art61_contract_set_by_client', period)
        qs = qs.filter(flt).distinct()
        return qs

ClientEvents.add_item_instance(ClientHasContract("art61"))

class ContractType(ContractTypeBase, mixins.Referrable):

    preferred_foreignkey_width = 20

    templates_group = 'art61/Contract'

    class Meta:
        verbose_name = _("Art61 job supplyment type")
        verbose_name_plural = _('Art61 job supplyment types')
        ordering = ['name']

class ContractTypes(dd.Table):
    required_roles = dd.login_required(IntegrationStaff)
    model = ContractType
    column_names = 'name ref *'
    detail_layout = """
    id name ref overlap_group:20
    ContractsByType
    """

class Contract(JobSupplyment):

    class Meta:
        verbose_name = _("Art61 job supplyment")
        verbose_name_plural = _('Art61 job supplyments')

    type = dd.ForeignKey(
        "art61.ContractType",
        verbose_name=_("Type"),
        related_name="%(app_label)s_%(class)s_set_by_type")

    # The following four fields are the same as in `cv.Experience`
    # except that `duration` is `cv_duration` because we have already
    # another field `duration` (number of days) from `JobSupplyment`
    job_title = models.CharField(
        max_length=200, verbose_name=_("Job title"), blank=True)
    status = dd.ForeignKey('cv.Status', blank=True, null=True)
    cv_duration = dd.ForeignKey('cv.Duration', blank=True, null=True)
    regime = dd.ForeignKey(
        'cv.Regime', blank=True, null=True,
        related_name="art61_contracts")

    @classmethod
    def get_certifiable_fields(cls):
        return (
            'client type company contact_person contact_role '
            'applies_from applies_until duration '
            'language job_title status cv_duration regime '
            'reference_person responsibilities '
            'user user_asd exam_policy '
            'date_decided date_issued ')

    def get_subsidizations(self):
        for sub in Subsidizations.items():
            if getattr(self, sub.contract_field_name()):
                yield sub

    def get_excerpt_options(self, ar, **kw):
        # Implements :meth:`lino.printing.Printable.get_excerpt_options`.

        # When printing a contract, there is no recipient.

        kw = super(Contract, self).get_excerpt_options(ar, **kw)
        del kw['company']
        del kw['contact_person']
        del kw['contact_role']
        return kw

# dd.update_field(Contract, 'user', verbose_name=_("responsible (IS)"))
dd.update_field(Contract, 'company', blank=False, null=False)

class ContractDetail(dd.DetailLayout):
    box1 = """
    id:8 client:25 user:15 language:8
    type company contact_person contact_role
    applies_from duration applies_until exam_policy
    job_title status cv_duration regime
    reference_person remark printed
    date_decided date_issued date_ended ending:20
    subsidize_10 subsidize_20 subsidize_30 subsidize_40 subsidize_50
    # signer1 signer2
    responsibilities
    """

    right = """
    cal.EntriesByController
    cal.TasksByController
    """

    main = """
    box1:70 right:30
    """

class Contracts(ContractBaseTable):
    #~ debug_permissions = "20130222"
    required_roles = dd.login_required(IntegUser)
    model = 'art61.Contract'
    column_names = 'id client client__national_id ' \
                   'applies_from date_ended user type *'
    order_by = ['id']
    detail_layout = ContractDetail()
    insert_layout = """
    client
    company
    type
    """

    parameters = dict(
        type=dd.ForeignKey(
            'art61.ContractType', blank=True,
            verbose_name=_("Only job supplies of type")),
        **ContractBaseTable.parameters)

    params_layout = """
    user type start_date end_date observed_event
    company ending_success ending
    """

    @classmethod
    def get_request_queryset(cls, ar):
        qs = super(Contracts, cls).get_request_queryset(ar)
        pv = ar.param_values
        if pv.company:
            qs = qs.filter(company=pv.company)
        return qs

class ContractsByClient(Contracts):
    required_roles = dd.login_required((IntegUser, SocialCoordinator))
    label = _("Art61 job supplyments and activations")
    master_key = 'client'
    auto_fit_column_widths = True
    column_names = 'applies_from applies_until date_ended duration type '\
                   'company contact_person user remark:20 '\
                   'subsidize_10 subsidize_20 subsidize_30 subsidize_40 subsidize_50 *'

class ContractsByProvider(Contracts):
    master_key = 'company'
    column_names = 'client applies_from applies_until user type *'

class ContractsByPolicy(Contracts):
    master_key = 'exam_policy'

class ContractsByType(Contracts):
    master_key = 'type'
    column_names = "applies_from client user *"
    order_by = ["applies_from"]

class ContractsByEnding(Contracts):
    master_key = 'ending'

class MyContracts(Contracts):
    column_names = ("applies_from client type company applies_until "
                    "date_ended ending *")

    @classmethod
    def param_defaults(self, ar, **kw):
        kw = super(MyContracts, self).param_defaults(ar, **kw)
        kw.update(user=ar.get_user())
        return kw

@dd.receiver(dd.pre_analyze)
def inject_subsidization_fields(sender, **kw):
    for sub in Subsidizations.items():
        dd.inject_field(
            'art61.Contract', sub.contract_field_name(),
            models.BooleanField(verbose_name=sub.text, default=False))
<|endoftext|>