<commit_before>#!/usr/bin/env python

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

#import time
import subprocess
import errno
import os
import time
import signal
from ARC import logger
from ARC import exceptions

class AssemblyRunner:
    """
    This class represents assembly jobs and handles running assemblies.
    required params:
        assembler, sample, target, PE1 and PE2 and/or SE, target_dir
    """
    def __init__(self, params):
        self.params = params

    def queue(self, ref_q):
        self.ref_q = ref_q

    def to_dict(self):
        return {'runner': self,
                'message': 'Assmelber for Sample: %s Target: %s' % (self.params['sample'], self.params['target']),
                'params': self.params}

    def start(self):
        if not('assembler' in self.params):
            raise exceptions.FatalException("assembler not defined in params")
        if self.params['map_against_reads'] and self.params['iteration'] == 1:
            #print "ASSEMBLER: %s %s MAP AGAINST READS" % (self.params['sample'], self.params['target'])
            self.RunMapAgainstReads()
        elif self.params['assembler'] == 'newbler':
            #logger.info("Running Newbler for sample: %s target: %s" % (self.params['sample'], self.params['target']))
            self.RunNewbler()
        elif self.params['assembler'] == 'spades':
            #logger.info("Running Spades for sample: %s target: %s" % (self.params['sample'], self.params['target']))
            self.RunSpades()
        else:
            raise exceptions.FatalException("Assembler %s isn't recognized." % self.params['assembler'])

    def RunMapAgainstReads(self):
        """
        A pseudo-assembler for cases where we don't actually assemble reads and instead just write them out as contigs.
        """
        #print "Creating finished file: " + os.path.join(self.params['target_dir'], 'finished')
        outf = open(os.path.join(self.params['target_dir'], 'finished'), 'w')
        outf.write("map_against_reads")
        outf.close()

    def kill_process_children(self, pid):
        """
            Base on code from:
            http://stackoverflow.com/questions/1191374/subprocess-with-timeout
            http://stackoverflow.com/questions/6553423/multiple-subprocesses-with-timeouts
        """
        p = subprocess.Popen('ps --no-headers -o pid --ppid %d' % pid, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout, stderr = p.communicate()
        pids = [pid]
        pids.extend([int(q) for q in stdout.split()])
        print "Process had", len(pids), "children."
        try:
            for pid in pids:
                os.kill(pid, signal.SIGKILL)
                print "--->KILLED", pid
        except OSError:
            print "--->OSERROR"
            pass

    def RunNewbler(self):
        #Code for running newbler
        """
        Expects params keys:
            PE1 and PE2 and/or SE
            target_dir
            -urt
        """
        #Check for necessary params:
        if not (('assembly_PE1' in self.params and 'assembly_PE2' in self.params) or 'assembly_SE' in self.params):
            raise exceptions.FatalException('Missing self.params in RunNewbler.')

        #Check for necessary files:
        if 'assembly_PE1' in self.params and 'assembly_PE2' in self.params and not(os.path.exists(self.params['assembly_PE1']) or not(os.path.exists(self.params['assembly_PE2']))):
            raise exceptions.FatalException('Missing PE files in RunNewbler.')

        if 'assembly_SE' in self.params and not(os.path.exists(self.params['assembly_SE'])):
            raise exceptions.FatalException('Missing SE file in RunNewbler.')

        sample = self.params['sample']
        target = self.params['target']

        #Building the args
        #args = ['/bio/local/bin/runAssembly']
        args = ['runAssembly']
        args += ['-nobig', '-force', '-cpu', '1']
        if self.params['urt'] and self.params['iteration'] < self.params['numcycles']:
            #only run with the -urt switch when it isn't the final assembly
            args += ['-urt']
        args += ['-o', os.path.join(self.params['target_dir'], 'assembly')]
        if 'assembly_PE1' in self.params and 'assembly_PE2' in self.params:
            args += [self.params['assembly_PE1'], self.params['assembly_PE2']]
        if 'assembly_SE' in self.params:
            args += [self.params['assembly_SE']]
        if self.params['verbose']:
            out = open(os.path.join(self.params['target_dir'], "assembly.log"), 'w')
        else:
            out = open(os.devnull, 'w')

        logger.info("Calling newbler for sample: %s target %s" % (sample, target))
        logger.info(" ".join(args))
        killed = False
        failed = False
        try:
            #ret = subprocess.call(args, stdout=out, stderr=out)
            start = time.time()
            ret = subprocess.Popen(args, stdout=out, stderr=out)
            print "Assembly called"
            pid = ret.pid  # http://stackoverflow.com/questions/1191374/subprocess-with-timeout
            print "pid is", pid
            i = 0
            while ret.poll() is None:
                print "Assembly wait:", i
                i += 1
                time.sleep(.2)
                if time.time() - start > self.params['assemblytimeout']:
                    logger.warn("Sample: %s target: %s Killing assembly after %s seconds" % (sample, target, time.time() - start))
                    #print "os.waitpid..."
                    #vals = os.waitpid(pid, 0)
                    #print "os.waitpid returned", vals
                    print "Calling kill"
                    ret.kill()  # Newbler doesn't seem to actually respond to kill all that reliably
                    time.sleep(2)
                    print "Calling kill_process_children"
                    self.kill_process_children(pid)
                    killed = True
                    break
        except Exception as exc:
            txt = ("Sample: %s, Target: %s: Unhandeled error running Newbler assembly" % (self.params['sample'], self.params['target']))
            txt += '\n\t' + str(exc)
            logger.warn(txt)
            failed = True
            pass
        finally:
            out.close()

        #if ret != 0:
            #raise exceptions.RerunnableError("Newbler assembly failed.")
        if not killed and ret.poll() != 0:
            #raise exceptions.RerunnableError("Newbler assembly failed.")
            failed = True

        if failed:
            outf = open(os.path.join(self.params['target_dir'], "finished"), 'w')
            outf.write("assembly_failed")
            outf.close()
        if killed:
            outf = open(os.path.join(self.params['target_dir'], "finished"), 'w')
            outf.write("assembly_killed")
            outf.close()
        else:
            #Run finished without error
            logger.info("Sample: %s target: %s Assembly finished in %s seconds" % (sample, target, time.time() - start))
            outf = open(os.path.join(self.params['target_dir'], "finished"), 'w')
            outf.write("assembly_complete")
            outf.close()

    def RunSpades(self):
        """
        Several arguments can be passed to spades.py: -1 [PE1], -2 [PE2], -s [SE], and -o [target_dir]
        """
        #Check that required params are available
        if not (('assembly_PE1' in self.params and 'assembly_PE2' in self.params) or ('assembly_SE' in self.params)):
            raise exceptions.FatalException('Missing self.params in RunSpades.')

        #Check that the files actually exist
        if 'assembly_PE1' in self.params and 'assembly_PE2' in self.params and not(os.path.exists(self.params['assembly_PE1']) or not(os.path.exists(self.params['assembly_PE2']))):
            raise exceptions.FatalException('Missing PE files in RunSpades.')
        if 'assembly_SE' in self.params and not(os.path.exists(self.params['assembly_SE'])):
            raise exceptions.FatalException('Missing SE file in RunSpades.')

        sample = self.params['sample']
        target = self.params['target']

        #Build args for assembler call
        args = ['spades.py', '-t', '1']
        if self.params['format'] == 'fasta':
            args.append('--only-assembler')  # spades errors on read correction if the input isn't fastq
        if 'assembly_PE1' in self.params and 'assembly_PE2' in self.params:
            args += ['-1', self.params['assembly_PE1'], '-2', self.params['assembly_PE2']]
        if 'assembly_SE' in self.params:
            args += ['-s', self.params['assembly_SE']]
        args += ['-o', os.path.join(self.params['target_dir'], 'assembly')]
        if self.params['verbose']:
            out = open(os.path.join(self.params['target_dir'], "assembly.log"), 'w')
        else:
            out = open(os.devnull, 'w')

        logger.info("Sample: %s target: %s Running spades assembler." % (sample, target))
        logger.info(" ".join(args))
        killed = False
        failed = False
        start = time.time()
        try:
            #ret = subprocess.call(args, stderr=out, stdout=out)
            ret = subprocess.Popen(args, stdout=out, stderr=out)
            while ret.poll() is None:
                time.sleep(.1)
                if time.time() - start > self.params['assemblytimeout']:
                    ret.kill()
                    killed = True
                    logger.warn("Sample: %s target: %s Assembly killed after %s seconds." % (sample, target, time.time() - start))
                    break
        except Exception as exc:
            txt = ("Sample: %s, Target: %s: Unhandeled error running Spades assembly" % (sample, target))
            txt += '\n\t' + str(exc)
            logger.warn(txt)
            failed = True
            pass
        finally:
            out.close()

        if not killed and ret.poll() != 0:
            failed = True
        if failed:
            outf = open(os.path.join(self.params['target_dir'], "finished"), 'w')
            outf.write("assembly_failed")
            outf.close()
        if killed:
            outf = open(os.path.join(self.params['target_dir'], "finished"), 'w')
            outf.write("assembly_killed")
            outf.close()
        else:
            #Run finished without error
            logger.info("Sample: %s target: %s Assembly finished in %s seconds" % (sample, target, time.time() - start))
            outf = open(os.path.join(self.params['target_dir'], "finished"), 'w')
            outf.write("assembly_complete")
            outf.close()
<commit_msg>handle Newbler problems.. newAssembly/addRun/runProject<commit_after>#!/usr/bin/env python

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

#import time
import subprocess
import errno
import os
import time
import signal
from ARC import logger
from ARC import exceptions

class AssemblyRunner:
    """
    This class represents assembly jobs and handles running assemblies.
    required params:
        assembler, sample, target, PE1 and PE2 and/or SE, target_dir
    """
    def __init__(self, params):
        self.params = params

    def queue(self, ref_q):
        self.ref_q = ref_q

    def to_dict(self):
        return {'runner': self,
                'message': 'Assmelber for Sample: %s Target: %s' % (self.params['sample'], self.params['target']),
                'params': self.params}

    def start(self):
        if not('assembler' in self.params):
            raise exceptions.FatalException("assembler not defined in params")
        if self.params['map_against_reads'] and self.params['iteration'] == 1:
            #print "ASSEMBLER: %s %s MAP AGAINST READS" % (self.params['sample'], self.params['target'])
            self.RunMapAgainstReads()
        elif self.params['assembler'] == 'newbler':
            #logger.info("Running Newbler for sample: %s target: %s" % (self.params['sample'], self.params['target']))
            self.RunNewbler()
        elif self.params['assembler'] == 'spades':
            #logger.info("Running Spades for sample: %s target: %s" % (self.params['sample'], self.params['target']))
            self.RunSpades()
        else:
            raise exceptions.FatalException("Assembler %s isn't recognized." % self.params['assembler'])

    def RunMapAgainstReads(self):
        """
        A pseudo-assembler for cases where we don't actually assemble reads and instead just write them out as contigs.
        """
        #print "Creating finished file: " + os.path.join(self.params['target_dir'], 'finished')
        outf = open(os.path.join(self.params['target_dir'], 'finished'), 'w')
        outf.write("map_against_reads")
        outf.close()

    def kill_process_children(self, pid):
        """
            Base on code from:
            http://stackoverflow.com/questions/1191374/subprocess-with-timeout
            http://stackoverflow.com/questions/6553423/multiple-subprocesses-with-timeouts
        """
        p = subprocess.Popen('ps --no-headers -o pid --ppid %d' % pid, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout, stderr = p.communicate()
        pids = [pid]
        pids.extend([int(q) for q in stdout.split()])
        print "Process had", len(pids), "children."
        try:
            for pid in pids:
                os.kill(pid, signal.SIGKILL)
                print "--->KILLED", pid
        except OSError:
            print "--->OSERROR"
            pass

    def RunNewbler(self):
        #Code for running newbler
        """
        Expects params keys:
            PE1 and PE2 and/or SE
            target_dir
            -urt
        """
        #Check for necessary params:
        if not (('assembly_PE1' in self.params and 'assembly_PE2' in self.params) or 'assembly_SE' in self.params):
            raise exceptions.FatalException('Missing self.params in RunNewbler.')

        #Check for necessary files:
        if 'assembly_PE1' in self.params and 'assembly_PE2' in self.params and not(os.path.exists(self.params['assembly_PE1']) or not(os.path.exists(self.params['assembly_PE2']))):
            raise exceptions.FatalException('Missing PE files in RunNewbler.')

        if 'assembly_SE' in self.params and not(os.path.exists(self.params['assembly_SE'])):
            raise exceptions.FatalException('Missing SE file in RunNewbler.')

        sample = self.params['sample']
        target = self.params['target']
        killed = False
        failed = False

        #determine whether to pipe output to a file or /dev/null
        if self.params['verbose']:
            out = open(os.path.join(self.params['target_dir'], "assembly.log"), 'w')
        else:
            out = open(os.devnull, 'w')

        #Build args for newAssembly:
        args = ['newAssembly', '-force', os.path.join(self.params['target_dir'], 'assembly')]
        logger.info("Calling newAssembly for sample: %s target %s" % (sample, target))
        logger.info(" ".join(args))
        ret = subprocess.call(args, stdout=out, stderr=out)
        #Build args for addRun:
        if 'assembly_PE1' in self.params and 'assembly_PE2' in self.params:
            args = ['addRun', os.path.join(self.params['target_dir'], 'assembly')]
            args += [self.params['assembly_PE1']]
            logger.info("Calling addRun for sample: %s target %s" % (sample, target))
            logger.info(" ".join(args))
            ret = subprocess.call(args, stdout=out, stderr=out)

            args = ['addRun', os.path.join(self.params['target_dir'], 'assembly')]
            args += [self.params['assembly_PE2']]
            logger.info("Calling addRun for sample: %s target %s" % (sample, target))
            logger.info(" ".join(args))
            ret = subprocess.call(args, stdout=out, stderr=out)
        if 'assembly_SE' in self.params:
            args = ['addRun', os.path.join(self.params['target_dir'], 'assembly')]
            args += [self.params['assembly_SE']]
            logger.info("Calling addRun for sample: %s target %s" % (sample, target))
            logger.info(" ".join(args))
            ret = subprocess.call(args, stdout=out, stderr=out)

        #Build args for runProject
        args = ['runProject']
        args += ['-nobig', '-cpu', '1']
        if self.params['urt'] and self.params['iteration'] < self.params['numcycles']:
            #only run with the -urt switch when it isn't the final assembly
            args += ['-urt']
        args += [os.path.join(self.params['target_dir'], 'assembly')]
        try:
            start = time.time()
            logger.info("Calling runProject for sample: %s target %s" % (sample, target))
            logger.info(" ".join(args))
            ret = subprocess.Popen(args, stdout=out, stderr=out)
            while ret.poll() is None:
                if time.time() - start > self.params['assemblytimeout']:
                    logger.warn("Sample: %s target: %s Killing assembly after %s seconds" % (sample, target, time.time() - start))
                    ret.kill()  # Newbler doesn't seem to actually respond to kill all that reliably
                    #time.sleep(2)
                    #print "Calling kill_process_children"
                    #self.kill_process_children(pid)
                    killed = True
                    break
                time.sleep(.1)
        except Exception as exc:
            txt = ("Sample: %s, Target: %s: Unhandeled error running Newbler assembly" % (self.params['sample'], self.params['target']))
            txt += '\n\t' + str(exc)
            logger.warn(txt)
            failed = True
            pass
        finally:
            out.close()

        # #Building the args
        # #args = ['/bio/local/bin/runAssembly']
        # args = ['runAssembly']
        # args += ['-nobig', '-force', '-cpu', '1']
        # if self.params['urt'] and self.params['iteration'] < self.params['numcycles']:
        #     #only run with the -urt switch when it isn't the final assembly
        #     args += ['-urt']
        # args += ['-o', os.path.join(self.params['target_dir'], 'assembly')]
        # if 'assembly_PE1' in self.params and 'assembly_PE2' in self.params:
        #     args += [self.params['assembly_PE1'], self.params['assembly_PE2']]
        # if 'assembly_SE' in self.params:
        #     args += [self.params['assembly_SE']]

        # logger.info("Calling newbler for sample: %s target %s" % (sample, target))
        # logger.info(" ".join(args))
        # killed = False
        # failed = False
        # try:
        #     #ret = subprocess.call(args, stdout=out, stderr=out)
        #     start = time.time()
        #     ret = subprocess.Popen(args, stdout=out, stderr=out)
        #     print "Assembly called"
        #     pid = ret.pid  # http://stackoverflow.com/questions/1191374/subprocess-with-timeout
        #     print "pid is", pid
        #     i = 0
        #     while ret.poll() is None:
        #         print "Assembly wait:", i
        #         i += 1
        #         time.sleep(.2)
        #         if time.time() - start > self.params['assemblytimeout']:
        #             logger.warn("Sample: %s target: %s Killing assembly after %s seconds" % (sample, target, time.time() - start))
        #             #print "os.waitpid..."
        #             #vals = os.waitpid(pid, 0)
        #             #print "os.waitpid returned", vals
        #             print "Calling kill"
        #             ret.kill()  # Newbler doesn't seem to actually respond to kill all that reliably
        #             time.sleep(2)
        #             print "Calling kill_process_children"
        #             self.kill_process_children(pid)
        #             killed = True
        #             break
        # except Exception as exc:
        #     txt = ("Sample: %s, Target: %s: Unhandeled error running Newbler assembly" % (self.params['sample'], self.params['target']))
        #     txt += '\n\t' + str(exc)
        #     logger.warn(txt)
        #     failed = True
        #     pass
        # finally:
        #     out.close()

        #if ret != 0:
            #raise exceptions.RerunnableError("Newbler assembly failed.")

        if not killed and ret.poll() != 0:
            #raise exceptions.RerunnableError("Newbler assembly failed.")
            failed = True

        if failed:
            outf = open(os.path.join(self.params['target_dir'], "finished"), 'w')
            outf.write("assembly_failed")
            outf.close()
        if killed:
            outf = open(os.path.join(self.params['target_dir'], "finished"), 'w')
            outf.write("assembly_killed")
            outf.close()
        else:
            #Run finished without error
            logger.info("Sample: %s target: %s Assembly finished in %s seconds" % (sample, target, time.time() - start))
            outf = open(os.path.join(self.params['target_dir'], "finished"), 'w')
            outf.write("assembly_complete")
            outf.close()

    def RunSpades(self):
        """
        Several arguments can be passed to spades.py: -1 [PE1], -2 [PE2], -s [SE], and -o [target_dir]
        """
        #Check that required params are available
        if not (('assembly_PE1' in self.params and 'assembly_PE2' in self.params) or ('assembly_SE' in self.params)):
            raise exceptions.FatalException('Missing self.params in RunSpades.')

        #Check that the files actually exist
        if 'assembly_PE1' in self.params and 'assembly_PE2' in self.params and not(os.path.exists(self.params['assembly_PE1']) or not(os.path.exists(self.params['assembly_PE2']))):
            raise exceptions.FatalException('Missing PE files in RunSpades.')
        if 'assembly_SE' in self.params and not(os.path.exists(self.params['assembly_SE'])):
            raise exceptions.FatalException('Missing SE file in RunSpades.')

        sample = self.params['sample']
        target = self.params['target']

        #Build args for assembler call
        args = ['spades.py', '-t', '1']
        if self.params['format'] == 'fasta':
            args.append('--only-assembler')  # spades errors on read correction if the input isn't fastq
        if 'assembly_PE1' in self.params and 'assembly_PE2' in self.params:
            args += ['-1', self.params['assembly_PE1'], '-2', self.params['assembly_PE2']]
        if 'assembly_SE' in self.params:
            args += ['-s', self.params['assembly_SE']]
        args += ['-o', os.path.join(self.params['target_dir'], 'assembly')]
        if self.params['verbose']:
            out = open(os.path.join(self.params['target_dir'], "assembly.log"), 'w')
        else:
            out = open(os.devnull, 'w')

        logger.info("Sample: %s target: %s Running spades assembler." % (sample, target))
        logger.info(" ".join(args))
        killed = False
        failed = False
        start = time.time()
        try:
            #ret = subprocess.call(args, stderr=out, stdout=out)
            ret = subprocess.Popen(args, stdout=out, stderr=out)
            while ret.poll() is None:
                time.sleep(.1)
                if time.time() - start > self.params['assemblytimeout']:
                    ret.kill()
                    killed = True
                    logger.warn("Sample: %s target: %s Assembly killed after %s seconds." % (sample, target, time.time() - start))
                    break
        except Exception as exc:
            txt = ("Sample: %s, Target: %s: Unhandeled error running Spades assembly" % (sample, target))
            txt += '\n\t' + str(exc)
            logger.warn(txt)
            failed = True
            pass
        finally:
            out.close()

        if not killed and ret.poll() != 0:
            failed = True
        if failed:
            outf = open(os.path.join(self.params['target_dir'], "finished"), 'w')
            outf.write("assembly_failed")
            outf.close()
        if killed:
            outf = open(os.path.join(self.params['target_dir'], "finished"), 'w')
            outf.write("assembly_killed")
            outf.close()
        else:
            #Run finished without error
            logger.info("Sample: %s target: %s Assembly finished in %s seconds" % (sample, target, time.time() - start))
            outf = open(os.path.join(self.params['target_dir'], "finished"), 'w')
            outf.write("assembly_complete")
            outf.close()
<|endoftext|>


<commit_before>"""Methods used to GET/POST data from/to an Apple TV."""

import re
import logging

from copy import copy

from pyatv import exceptions
from pyatv.const import MediaType, DeviceState
from pyatv.dmap import parser
from .tag_definitions import lookup_tag

_LOGGER = logging.getLogger(__name__)

_DMAP_HEADERS = {
    "Accept": "*/*",
    "Accept-Encoding": "gzip",
    "Client-DAAP-Version": "3.13",
    "Client-ATV-Sharing-Version": "1.2",
    "Client-iTunes-Sharing-Version": "3.15",
    "User-Agent": "Remote/1021",
    "Viewer-Only-Client": "1",
}

DEFAULT_TIMEOUT = 10.0  # Seconds

def media_kind(kind):
    """Convert iTunes media kind to API representation."""
    if kind in [1, 32770]:
        return MediaType.Unknown
    if kind in [3, 7, 11, 12, 13, 18, 32]:
        return MediaType.Video
    if kind in [2, 4, 10, 14, 17, 21, 36]:
        return MediaType.Music
    if kind in [8, 64]:
        return MediaType.TV

    raise exceptions.UnknownMediaKindError("Unknown media kind: " + str(kind))

def playstate(state):
    """Convert iTunes playstate to API representation."""
    # pylint: disable=too-many-return-statements
    if state == 0 or state is None:
        return DeviceState.Idle
    if state == 1:
        return DeviceState.Loading
    if state == 2:
        return DeviceState.Stopped
    if state == 3:
        return DeviceState.Paused
    if state == 4:
        return DeviceState.Playing
    if state in (5, 6):
        return DeviceState.Seeking

    raise exceptions.UnknownPlayStateError("Unknown playstate: " + str(state))

def ms_to_s(time):
    """Convert time in ms to seconds."""
    if time is None:
        return 0

    # Happens in some special cases, just return 0
    if time >= (2 ** 32 - 1):
        return 0
    return round(time / 1000.0)

class DaapRequester:
    """Helper class that makes it easy to perform DAAP requests.

    It will automatically do login and other necessary book-keeping.
    """

    def __init__(self, http, login_id):
        """Initialize a new DaapRequester."""
        self.http = http
        self._login_id = login_id
        self._session_id = 0

    async def login(self):
        """Login to Apple TV using specified login id."""
        # Do not use session.get_data(...) in login as that would end up in
        # an infinite loop.
        def _login_request():
            return self.http.get_data(
                self._mkurl("login?[AUTH]&hasFP=1", session=False, login_id=True),
                headers=_DMAP_HEADERS,
            )

        resp = await self._do(_login_request, is_login=True)
        self._session_id = parser.first(resp, "mlog", "mlid")

        _LOGGER.info("Logged in and got session id %s", self._session_id)
        return self._session_id

    async def get(self, cmd, daap_data=True, timeout=None, **args):
        """Perform a DAAP GET command."""

        def _get_request():
            return self.http.get_data(
                self._mkurl(cmd, *args), headers=_DMAP_HEADERS, timeout=timeout
            )

        await self._assure_logged_in()
        return await self._do(_get_request, is_daap=daap_data)

    async def post(self, cmd, data=None, timeout=None, **args):
        """Perform DAAP POST command with optional data."""

        def _post_request():
            headers = copy(_DMAP_HEADERS)
            headers["Content-Type"] = "application/x-www-form-urlencoded"
            return self.http.post_data(
                self._mkurl(cmd, *args), data=data, headers=headers, timeout=timeout
            )

        await self._assure_logged_in()
        return await self._do(_post_request)

    async def _do(self, action, retry=True, is_login=False, is_daap=True):
        resp, status = await action()
        if is_daap:
            resp = parser.parse(resp, lookup_tag)

        self._log_response(str(action.__name__) + ": %s", resp, is_daap)
        if 200 <= status < 300:
            return resp

        # Seems to be the case?
        if status == 500:
            raise exceptions.NotSupportedError(f"command not supported at this stage")

        if not is_login:
            # If a request fails, try to login again before retrying
            _LOGGER.info("implicitly logged out, logging in again")
            await self.login()

        # Retry once if we got a bad response, otherwise bail out
        if retry:
            return await self._do(action, False, is_login=is_login, is_daap=is_daap)

        raise exceptions.AuthenticationError("failed to login: " + str(status))

    def _mkurl(self, cmd, *args, session=True, login_id=False):
        url = "{}".format(cmd.format(*args))
        parameters = []
        if login_id:
            if re.match(r"0x[0-9A-Fa-f]{16}", self._login_id):
                parameters.append("pairing-guid={}".format(self._login_id))
            elif re.match(
                r"[0-9A-Fa-f]{8}-([0-9A-Fa-f]{4}-){3}[0-9A-Fa-f]{12}", self._login_id
            ):
                parameters.append("hsgid={}".format(self._login_id))
            else:
                raise exceptions.InvalidCredentialsError(
                    "invalid credentials: " + self._login_id
                )
        if session:
            parameters.insert(0, "session-id={}".format(self._session_id))
        return url.replace("[AUTH]", "&".join(parameters))

    async def _assure_logged_in(self):
        if self._session_id != 0:
            _LOGGER.debug("Already logged in, re-using seasion id %d", self._session_id)
        else:
            await self.login()

    @staticmethod
    def _log_response(text, data, is_daap):
        if _LOGGER.isEnabledFor(logging.INFO):
            formatted = data
            if is_daap:
                formatted = parser.pprint(data, lookup_tag)
            _LOGGER.debug(text, formatted)
<commit_msg>dmap: Minor log improvements to DAAP<commit_after>"""Methods used to GET/POST data from/to an Apple TV."""

import re
import logging

from copy import copy

from pyatv import exceptions
from pyatv.const import MediaType, DeviceState
from pyatv.dmap import parser
from pyatv.support import log_binary
from .tag_definitions import lookup_tag

_LOGGER = logging.getLogger(__name__)

_DMAP_HEADERS = {
    "Accept": "*/*",
    "Accept-Encoding": "gzip",
    "Client-DAAP-Version": "3.13",
    "Client-ATV-Sharing-Version": "1.2",
    "Client-iTunes-Sharing-Version": "3.15",
    "User-Agent": "Remote/1021",
    "Viewer-Only-Client": "1",
}

DEFAULT_TIMEOUT = 10.0  # Seconds

def media_kind(kind):
    """Convert iTunes media kind to API representation."""
    if kind in [1, 32770]:
        return MediaType.Unknown
    if kind in [3, 7, 11, 12, 13, 18, 32]:
        return MediaType.Video
    if kind in [2, 4, 10, 14, 17, 21, 36]:
        return MediaType.Music
    if kind in [8, 64]:
        return MediaType.TV

    raise exceptions.UnknownMediaKindError("Unknown media kind: " + str(kind))

def playstate(state):
    """Convert iTunes playstate to API representation."""
    # pylint: disable=too-many-return-statements
    if state == 0 or state is None:
        return DeviceState.Idle
    if state == 1:
        return DeviceState.Loading
    if state == 2:
        return DeviceState.Stopped
    if state == 3:
        return DeviceState.Paused
    if state == 4:
        return DeviceState.Playing
    if state in (5, 6):
        return DeviceState.Seeking

    raise exceptions.UnknownPlayStateError("Unknown playstate: " + str(state))

def ms_to_s(time):
    """Convert time in ms to seconds."""
    if time is None:
        return 0

    # Happens in some special cases, just return 0
    if time >= (2 ** 32 - 1):
        return 0
    return round(time / 1000.0)

class DaapRequester:
    """Helper class that makes it easy to perform DAAP requests.

    It will automatically do login and other necessary book-keeping.
    """

    def __init__(self, http, login_id):
        """Initialize a new DaapRequester."""
        self.http = http
        self._login_id = login_id
        self._session_id = 0

    async def login(self):
        """Login to Apple TV using specified login id."""
        # Do not use session.get_data(...) in login as that would end up in
        # an infinite loop.
        def _login_request():
            url = self._mkurl("login?[AUTH]&hasFP=1", session=False, login_id=True)
            _login_request.log_text = "Login request: " + url
            return self.http.get_data(url, headers=_DMAP_HEADERS,)

        resp = await self._do(_login_request, is_login=True)
        self._session_id = parser.first(resp, "mlog", "mlid")

        _LOGGER.info("Logged in and got session id %s", self._session_id)
        return self._session_id

    async def get(self, cmd, daap_data=True, timeout=None, **args):
        """Perform a DAAP GET command."""

        def _get_request():
            url = self._mkurl(cmd, *args)
            _get_request.log_text = "GET request: " + url
            return self.http.get_data(url, headers=_DMAP_HEADERS, timeout=timeout)

        await self._assure_logged_in()
        return await self._do(_get_request, is_daap=daap_data)

    async def post(self, cmd, data=None, timeout=None, **args):
        """Perform DAAP POST command with optional data."""

        def _post_request():
            url = self._mkurl(cmd, *args)
            _post_request.log_text = "POST request: " + url
            headers = copy(_DMAP_HEADERS)
            headers["Content-Type"] = "application/x-www-form-urlencoded"
            return self.http.post_data(url, data=data, headers=headers, timeout=timeout)

        await self._assure_logged_in()
        return await self._do(_post_request)

    async def _do(self, action, retry=True, is_login=False, is_daap=True):
        resp, status = await action()
        if is_daap:
            resp = parser.parse(resp, lookup_tag)

        self._log_response(action.log_text, resp, is_daap)
        if 200 <= status < 300:
            return resp

        # Seems to be the case?
        if status == 500:
            raise exceptions.NotSupportedError(f"command not supported at this stage")

        if not is_login:
            # If a request fails, try to login again before retrying
            _LOGGER.info("implicitly logged out, logging in again")
            await self.login()

        # Retry once if we got a bad response, otherwise bail out
        if retry:
            return await self._do(action, False, is_login=is_login, is_daap=is_daap)

        raise exceptions.AuthenticationError("failed to login: " + str(status))

    def _mkurl(self, cmd, *args, session=True, login_id=False):
        url = "{}".format(cmd.format(*args))
        parameters = []
        if login_id:
            if re.match(r"0x[0-9A-Fa-f]{16}", self._login_id):
                parameters.append("pairing-guid={}".format(self._login_id))
            elif re.match(
                r"[0-9A-Fa-f]{8}-([0-9A-Fa-f]{4}-){3}[0-9A-Fa-f]{12}", self._login_id
            ):
                parameters.append("hsgid={}".format(self._login_id))
            else:
                raise exceptions.InvalidCredentialsError(
                    "invalid credentials: " + self._login_id
                )
        if session:
            parameters.insert(0, "session-id={}".format(self._session_id))
        return url.replace("[AUTH]", "&".join(parameters))

    async def _assure_logged_in(self):
        if self._session_id != 0:
            _LOGGER.debug("Already logged in, re-using seasion id %d", self._session_id)
        else:
            await self.login()

    @staticmethod
    def _log_response(text, data, is_daap):
        if _LOGGER.isEnabledFor(logging.INFO):
            if is_daap:
                _LOGGER.debug(parser.pprint(data, lookup_tag))
            else:
                log_binary(_LOGGER, text, Data=data)
<|endoftext|>


<commit_before>"""
    This module contain pybooru object class.
"""

#urllib2 imports
from urllib import urlencode
from urllib2 import urlopen
from urllib2 import URLError
from urllib2 import HTTPError

#urlparse imports
from urlparse import urlparse

try:
    #simplejson imports
    from simplejson import loads
except ImportError:
    try:
        #Python 2.6 and up
        from json import loads
    except ImportError:
        raise Exception('Pybooru requires the simplejson library to work')

#pyborru imports
from .exceptions import PybooruError
#pybooru resources imports
from .resources import api_base_url
from .resources import site_list

class Pybooru(object):
    """Pybooru class.

    init Parameters:
        siteName: The site name in site_list.
        siteURL: URL of based Danbooru site.

    Attributes:
        siteName: Return site name.
        siteURL: Return URL of based danbooru site.
    """

    def __init__(self, siteName=None, siteURL=None):
        self.siteName = siteName
        self.siteURL = siteURL

        if (siteURL is not None) or (siteName is not None):
            if type(siteName) is str:
                self._site_name(siteName.lower())
            elif type(siteURL) is str:
                self._url_validator(siteURL.lower())
            else:
                raise PybooruError('Expected type str for siteName and siteURL')
        else:
            raise PybooruError('siteName and siteURL are None')

    def _site_name(self, siteName):
        """Function for checking name site and get URL.

        Parameters:
          siteName: The name of a based Danbooru site. You can get list of sites
                    in the resources module.
        """

        if siteName in site_list.keys():
            self.siteURL = site_list[siteName]
        else:
            raise PybooruError(
                        'The site name is not valid, use siteURL parameter'
                        )

    def _url_validator(self, url):
        """URL validator for siteURL parameter of Pybooru.

        Parameters:
            url: The URL to validate.
        """

        #urlparse() from urlparse module
        parse = urlparse(url)

        if parse.scheme not in ('http', 'https'):
            if parse.scheme == '':
                url = 'http://' + parse.path
            else:
                url = 'http://' + parse.netloc

        self.siteURL = url

    def _json_load(self, api_name, params=None):
        """Function for reading and returning JSON response.

        Parameters:
            api_name: The NAME of the API function.
            params: The parameters of the API function.
        """

        url = self.siteURL + api_base_url[api_name]

        try:
            #urlopen() from module urllib2
            #urlencode() from module urllib
            openURL = urlopen(url, urlencode(params))
            reading = openURL.read()
            #loads() is a function of simplejson module
            response = loads(reading)
            return response
        except (URLError, HTTPError) as err:
            if hasattr(err, 'code'):
                raise PybooruError('in _json_load', err.code, url)
            else:
                raise PybooruError('in _json_load %s' % (err.reason), url)
        except ValueError as err:
            raise PybooruError('JSON Error: %s in line %s column %s' % (
                               err.msg, err.lineno, err.colno))

    def posts_list(self, tags=None, limit=100, page=1):
        """Get a list of posts.

        Parameters:
            tags: The tags of the posts (Default: None).
            limit: Limit of posts. Limit of 100 posts per request
                   (Default: 100).
            page: The page number (Default: 1).
        """

        params = {'limit': limit, 'page': page}

        if tags is not None:
            params['tags'] = tags

        return self._json_load('posts_list', params)

    def tags_list(self, name=None, id_=None, limit=0, page=1, order='name',
                  after_id=None):
        """Get a list of tags.

        Parameters:
            name: The exact name of the tag.
            id_: The id number of the tag.
            limit: How many tags to retrieve. Setting this to 0 will return
                   every tag (Default value: 0).
            page: The page number.
            order: Can be 'date', 'name' or 'count' (Default: name).
            after_id: Return all tags that have an id number greater than this.
        """

        params = {'limit': limit, 'page': page, 'order': order}

        if id_ is not None:
            params['id'] = id_
        elif name is not None:
            params['name'] = name
        elif after_id is not None:
            params['after_id'] = after_id

        return self._json_load('tags_list', params)

    def tags_related(self, tags, type_=None):
        """Get a list of related tags.

        Parameters:
            tags: The tag names to query.
            type_: Restrict results to this tag type. Can be general, artist,
                   copyright, or character (Default value: None).
        """

        params = {'tags': tags}

        if type_ is not None:
            params['type'] = type_

        return self._json_load('tags_related', params)

    def artists_list(self, name=None, order=None, page=1):
        """Get a list of artists.

        Parameters:
            name: The name (or a fragment of the name) of the artist.
            order: Can be date or name (Default value: None).
            page: The page number.
        """

        params = {'page': page}

        if name is not None:
            params['name'] = name
        if order is not None:
            params['order'] = order

        return self._json_load('artists_list', params)

    def comments_show(self, id_=None):
        """Get a specific comment.

        Parameters:
            id_: The id number of the comment to retrieve.
        """

        if id_ is not None:
            params = {'id': id_}
            return self._json_load('comments_show', params)
        else:
            raise PybooruError('id_ attribute is required')

    def wiki_list(self, query=None, order='title', limit=100, page=1):
        """This function retrieves a list of every wiki page.

        Parameters:
            query: A word or phrase to search for (Default: None).
            order: Can be: title, date (Default: title).
            limit: The number of pages to retrieve (Default: 100).
            page: The page number.
        """

        params = {'order': order, 'limit': limit, 'page': page}

        if query is not None:
            params['query'] = query

        return self._json_load('wiki_list', params)

    def wiki_show(self, title=None, version=None):
        """Get a specific wiki page.

        Parameters:
            title: The title of the wiki page to retrieve.
            version: The version of the page to retrieve.
        """

        if title is not None:
            params = {'title': title}

            if version is not None:
                params['version'] = version

            return self._json_load('wiki_show', params)
        else:
            raise PybooruError('title attribute is required')

    def wiki_history(self, title=None):
        """Get history of specific wiki page.

        Parameters:
            title: The title of the wiki page to retrieve versions for.
        """

        if title is not None:
            params = {'title': title}
            return self._json_load('wiki_history', params)
        else:
            raise PybooruError('title atribute is required')

    def notes_list(self, post_id=None):
        """Get note list

        Parameters:
            post_id: The post id number to retrieve notes for (Default: None).
        """

        if post_id is not None:
            params = {'post_id': post_id}
            return self._json_load('notes_list', params)
        else:
            return self._json_load('notes_list')

    def notes_search(self, query=None):
        """Search specific note.

        Parameters:
            query: A word or phrase to search for.
        """

        if query is not None:
            params = {'query': query}
            return self._json_load('notes_search', params)
        else:
            raise PybooruError('query attribute is required')

    def notes_history(self, post_id=None, id_=None, limit=10, page=1):
        """Get history of notes.

        Parameters:
            post_id: The post id number to retrieve note versions for.
            id_: The note id number to retrieve versions for.
            limit: How many versions to retrieve (Default: 10).
            page: The note id number to retrieve versions for.
        """

        params = {'limit': limit, 'page': page}

        if post_id is not None:
            params['post_id'] = post_id
        elif id_ is not None:
            params['id'] = id_

        return self._json_load('notes_history', params)

    def users_search(self, name=None, id_=None):
        """Search users. If you don't specify any parameters you'll
           get a listing of all users.

        Parameters:
            name: The name of the user.
            id_: The id number of the user.
        """

        if name is not None:
            params = {'name': name}
            return self._json_load()('users_search', params)
        elif id_ is not None:
            params = {'id': id_}
            return self._json_load('users_search', params)
        else:
            return self._json_load('users_search')

    def forum_list(self, parent_id=None):
        """Get forum posts. If you don't specify any parameters you'll get
           a listing of all users.

        Parameters:
            parent_id: The parent ID number. You'll return all the responses to
                       that forum post.
        """

        if parent_id is not None:
            params = {'parent_id': parent_id}
            return self._json_load('forum_list', params)
        else:
            return self._json_load('forum_list')

    def pools_list(self, query=None, page=1):
        """Get pools. If you don't specify any parameters you'll get a
           list of all pools.

        Parameters:
            query: The title.
            page: The page.
        """

        params = {'page': page}

        if query is not None:
            params['query': query]

        return self._json_load('pools_list', params)

    def pools_posts(self, id_=None, page=1):
        """Get pools posts. If you don't specify any parameters you'll get a
           list of all pools.

        Parameters:
            id_: The pool id number.
            page: The page.
        """

        params = {'page': page}

        if id_ is not None:
            params['id'] = id_

        return self._json_load('pools_posts', params)

    def favorites_list_users(self, id_=None):
        """Return a list with all users who have added to favorites a specific
           post.

        Parameters:
            id_: The post id.
        """

        if id_ is not None:
            params = {'id': id_}
            response = self._json_load('favorites_list_users', params)
            #Return list with users
            return response['favorited_users'].split(',')
        else:
            raise PybooruError('id_ attribute is required')
<commit_msg>Added a comment<commit_after>"""
    This module contain pybooru object class.
"""

#urllib2 imports
from urllib import urlencode
from urllib2 import urlopen
from urllib2 import URLError
from urllib2 import HTTPError

#urlparse imports
from urlparse import urlparse

try:
    #simplejson imports
    from simplejson import loads
except ImportError:
    try:
        #Python 2.6 and up
        from json import loads
    except ImportError:
        raise Exception('Pybooru requires the simplejson library to work')

#pyborru exceptions imports
from .exceptions import PybooruError
#pybooru resources imports
from .resources import api_base_url
from .resources import site_list

class Pybooru(object):
    """Pybooru class.

    init Parameters:
        siteName: The site name in site_list.
        siteURL: URL of based Danbooru site.

    Attributes:
        siteName: Return site name.
        siteURL: Return URL of based danbooru site.
    """

    def __init__(self, siteName=None, siteURL=None):
        self.siteName = siteName
        self.siteURL = siteURL

        if (siteURL is not None) or (siteName is not None):
            if type(siteName) is str:
                self._site_name(siteName.lower())
            elif type(siteURL) is str:
                self._url_validator(siteURL.lower())
            else:
                raise PybooruError('Expected type str for siteName and siteURL')
        else:
            raise PybooruError('siteName and siteURL are None')

    def _site_name(self, siteName):
        """Function for checking name site and get URL.

        Parameters:
          siteName: The name of a based Danbooru site. You can get list of sites
                    in the resources module.
        """

        if siteName in site_list.keys():
            self.siteURL = site_list[siteName]
        else:
            raise PybooruError(
                        'The site name is not valid, use siteURL parameter'
                        )

    def _url_validator(self, url):
        """URL validator for siteURL parameter of Pybooru.

        Parameters:
            url: The URL to validate.
        """

        #urlparse() from urlparse module
        parse = urlparse(url)

        if parse.scheme not in ('http', 'https'):
            if parse.scheme == '':
                url = 'http://' + parse.path
            else:
                url = 'http://' + parse.netloc

        self.siteURL = url

    def _json_load(self, api_name, params=None):
        """Function for reading and returning JSON response.

        Parameters:
            api_name: The NAME of the API function.
            params: The parameters of the API function.
        """

        url = self.siteURL + api_base_url[api_name]

        try:
            #urlopen() from module urllib2
            #urlencode() from module urllib
            openURL = urlopen(url, urlencode(params))
            reading = openURL.read()
            #loads() is a function of simplejson module
            response = loads(reading)
            return response
        except (URLError, HTTPError) as err:
            if hasattr(err, 'code'):
                raise PybooruError('in _json_load', err.code, url)
            else:
                raise PybooruError('in _json_load %s' % (err.reason), url)
        except ValueError as err:
            raise PybooruError('JSON Error: %s in line %s column %s' % (
                               err.msg, err.lineno, err.colno))

    def posts_list(self, tags=None, limit=100, page=1):
        """Get a list of posts.

        Parameters:
            tags: The tags of the posts (Default: None).
            limit: Limit of posts. Limit of 100 posts per request
                   (Default: 100).
            page: The page number (Default: 1).
        """

        params = {'limit': limit, 'page': page}

        if tags is not None:
            params['tags'] = tags

        return self._json_load('posts_list', params)

    def tags_list(self, name=None, id_=None, limit=0, page=1, order='name',
                  after_id=None):
        """Get a list of tags.

        Parameters:
            name: The exact name of the tag.
            id_: The id number of the tag.
            limit: How many tags to retrieve. Setting this to 0 will return
                   every tag (Default value: 0).
            page: The page number.
            order: Can be 'date', 'name' or 'count' (Default: name).
            after_id: Return all tags that have an id number greater than this.
        """

        params = {'limit': limit, 'page': page, 'order': order}

        if id_ is not None:
            params['id'] = id_
        elif name is not None:
            params['name'] = name
        elif after_id is not None:
            params['after_id'] = after_id

        return self._json_load('tags_list', params)

    def tags_related(self, tags, type_=None):
        """Get a list of related tags.

        Parameters:
            tags: The tag names to query.
            type_: Restrict results to this tag type. Can be general, artist,
                   copyright, or character (Default value: None).
        """

        params = {'tags': tags}

        if type_ is not None:
            params['type'] = type_

        return self._json_load('tags_related', params)

    def artists_list(self, name=None, order=None, page=1):
        """Get a list of artists.

        Parameters:
            name: The name (or a fragment of the name) of the artist.
            order: Can be date or name (Default value: None).
            page: The page number.
        """

        params = {'page': page}

        if name is not None:
            params['name'] = name
        if order is not None:
            params['order'] = order

        return self._json_load('artists_list', params)

    def comments_show(self, id_=None):
        """Get a specific comment.

        Parameters:
            id_: The id number of the comment to retrieve.
        """

        if id_ is not None:
            params = {'id': id_}
            return self._json_load('comments_show', params)
        else:
            raise PybooruError('id_ attribute is required')

    def wiki_list(self, query=None, order='title', limit=100, page=1):
        """This function retrieves a list of every wiki page.

        Parameters:
            query: A word or phrase to search for (Default: None).
            order: Can be: title, date (Default: title).
            limit: The number of pages to retrieve (Default: 100).
            page: The page number.
        """

        params = {'order': order, 'limit': limit, 'page': page}

        if query is not None:
            params['query'] = query

        return self._json_load('wiki_list', params)

    def wiki_show(self, title=None, version=None):
        """Get a specific wiki page.

        Parameters:
            title: The title of the wiki page to retrieve.
            version: The version of the page to retrieve.
        """

        if title is not None:
            params = {'title': title}

            if version is not None:
                params['version'] = version

            return self._json_load('wiki_show', params)
        else:
            raise PybooruError('title attribute is required')

    def wiki_history(self, title=None):
        """Get history of specific wiki page.

        Parameters:
            title: The title of the wiki page to retrieve versions for.
        """

        if title is not None:
            params = {'title': title}
            return self._json_load('wiki_history', params)
        else:
            raise PybooruError('title atribute is required')

    def notes_list(self, post_id=None):
        """Get note list

        Parameters:
            post_id: The post id number to retrieve notes for (Default: None).
        """

        if post_id is not None:
            params = {'post_id': post_id}
            return self._json_load('notes_list', params)
        else:
            return self._json_load('notes_list')

    def notes_search(self, query=None):
        """Search specific note.

        Parameters:
            query: A word or phrase to search for.
        """

        if query is not None:
            params = {'query': query}
            return self._json_load('notes_search', params)
        else:
            raise PybooruError('query attribute is required')

    def notes_history(self, post_id=None, id_=None, limit=10, page=1):
        """Get history of notes.

        Parameters:
            post_id: The post id number to retrieve note versions for.
            id_: The note id number to retrieve versions for.
            limit: How many versions to retrieve (Default: 10).
            page: The note id number to retrieve versions for.
        """

        params = {'limit': limit, 'page': page}

        if post_id is not None:
            params['post_id'] = post_id
        elif id_ is not None:
            params['id'] = id_

        return self._json_load('notes_history', params)

    def users_search(self, name=None, id_=None):
        """Search users. If you don't specify any parameters you'll
           get a listing of all users.

        Parameters:
            name: The name of the user.
            id_: The id number of the user.
        """

        if name is not None:
            params = {'name': name}
            return self._json_load()('users_search', params)
        elif id_ is not None:
            params = {'id': id_}
            return self._json_load('users_search', params)
        else:
            return self._json_load('users_search')

    def forum_list(self, parent_id=None):
        """Get forum posts. If you don't specify any parameters you'll get
           a listing of all users.

        Parameters:
            parent_id: The parent ID number. You'll return all the responses to
                       that forum post.
        """

        if parent_id is not None:
            params = {'parent_id': parent_id}
            return self._json_load('forum_list', params)
        else:
            return self._json_load('forum_list')

    def pools_list(self, query=None, page=1):
        """Get pools. If you don't specify any parameters you'll get a
           list of all pools.

        Parameters:
            query: The title.
            page: The page.
        """

        params = {'page': page}

        if query is not None:
            params['query': query]

        return self._json_load('pools_list', params)

    def pools_posts(self, id_=None, page=1):
        """Get pools posts. If you don't specify any parameters you'll get a
           list of all pools.

        Parameters:
            id_: The pool id number.
            page: The page.
        """

        params = {'page': page}

        if id_ is not None:
            params['id'] = id_

        return self._json_load('pools_posts', params)

    def favorites_list_users(self, id_=None):
        """Return a list with all users who have added to favorites a specific
           post.

        Parameters:
            id_: The post id.
        """

        if id_ is not None:
            params = {'id': id_}
            response = self._json_load('favorites_list_users', params)
            #Return list with users
            return response['favorited_users'].split(',')
        else:
            raise PybooruError('id_ attribute is required')
<|endoftext|>


<commit_before>#!/usr/bin/env Python
#encoding: utf-8

"""
    Pybooru is a library for Python for access to API Danbooru based sites.

    Under a MIT License
"""

__author__ = 'Daniel Luque <danielluque14 at gmail.com>'
__version__ = '1.4.9'

#urllib2 imports
from urllib2 import urlopen
from urllib2 import URLError
from urllib2 import HTTPError

#urlparse imports
from urlparse import urlparse

try:
    #simplejson imports
    from simplejson import loads
except ImportError:
    try:
        #Python 2.6 and up
        from json import loads
    except ImportError:
        raise Exception('Pybooru requires the simplejson library to work')

#pyborru resources imports
from resources import http_status_codes
from resources import site_list

class PybooruError(Exception):
    """Class for return error message

    init Parameters:
        msg: The error message
        http_code: The HTTP status code
        url: The URL

    Attributes:
        msg: Return the error message
        http_code: Return the HTTP status code
        url: return the URL
    """

    def __init__(self, msg, http_code=None, url=None):
        self.msg = msg
        self.http_code = http_code
        self.url = url

        if (http_code is not None) and (http_code in http_status_codes) and (
            url is not None):
            self.msg = '%i: %s, %s -- %s -- URL: %s' % (http_code,
                        http_status_codes[http_code][0],
                        http_status_codes[http_code][1], self.msg, url)

    def __str__(self):
        """This function return self.msg"""

        return repr(self.msg)

class Pybooru(object):
    """Pybooru class

    init Parameters:
        siteName: The site name in site_list
        siteURL: URL of based Danbooru site

    Attributes:
        siteName: Return site name
        siteURL: Return URL of based danbooru site
    """

    def __init__(self, siteName=None, siteURL=None):
        self.siteName = siteName
        self.siteURL = siteURL

        if (self.siteURL is not None) or (self.siteName is not None):
            if self.siteName is not None:
                self._site_name(self.siteName.lower())
            elif self.siteURL is not None:
                self._url_validator(self.siteURL.lower())
        else:
            raise PybooruError('siteURL and siteName are None')

    def _site_name(self, siteName):
        """Function for check name site and get URL

        Parameters:
          siteName: The name of a based Danbooru site. You can get list of sites
                    in the resources module.
        """

        if siteName in site_list.keys():
            self.siteURL = site_list[siteName]
        else:
            raise PybooruError(
                        'The site name is not valid, use siteURL parameter'
                        )

    def _url_validator(self, url):
        """URL validator for siteURL parameter of Pybooru

        Parameters:
            url: The URL to validate
        """

        #urlparse() from urlparse module
        parse = urlparse(url)

        if parse.scheme not in ('http', 'https'):
            if parse.scheme == '':
                url = 'http://' + parse.path
            else:
                url = 'http://' + parse.netloc

        self.siteURL = url

    def _build_url(self, api_url, params=None):
        """Builder url for _json_load

        Parameters:
            api_url: The URL of the API function
            params: The parameters of the API function
        """

        if params is not None:
            url_request = self.siteURL + api_url + params
            url_request = self._json_load(url_request)
            return url_request
        else:
            url_request = self.siteURL + api_url
            url_request = self._json_load(url_request)
            return url_request

    def _json_load(self, url):
        """Function for read and return JSON response

        Parameters:
            url: The url for JSON request
        """

        try:
            #urlopen() from module urllib2
            openURL = urlopen(url)
            reading = openURL.read()
            #loads() is a function of simplejson module
            response = loads(reading)
            return response
        except (URLError, HTTPError) as err:
            if hasattr(err, 'code'):
                raise PybooruError('in _json_load', err.code, url)
            else:
                raise PybooruError('in _json_load %s' % (err.reason), url)
        except ValueError as err:
            raise PybooruError('JSON Error: %s in line %s column %s' % (
                               err.msg, err.lineno, err.colno))

    def posts(self, tags=None, limit=10, page=1):
        self.posts_url = '/post/index.json?'
        self.params = 'limit=%i&page=%i' % (limit, page)

        if tags is not None:
            self.tags = str(tags)
            self.params += '&tags=%s' % (tags)
            return self._build_url(self.posts_url, self.params)
        else:
            return self._build_url(self.posts_url, self.params)

    def tags(self, name=None, id_=None, limit=100, page=1, order='name',
                                                            after_id=0):
        self.tags_url = '/tag/index.json?'

        if id_ is not None:
            self.params = 'id=%i' % (id_)
            return self._build_url(self.tags_url, self.params)
        if name is not None:
            self.name = str(name)
            self.params = "name=%s" % (self.name)
            return self._build_url(self.tags_url, self.params)
        else:
            self.params = "limit=%i&page=%i&order=%s&after_id=%i" % (limit,
                                                    page, order, after_id)
            return self._build_url(self.tags_url, self.params)

    def artists(self, name=None, id_=None, limit=20, order='name', page=1):
        self.artists_url = '/artist/index.json?'
        self.params = 'limit=%i&page%i&order=%s' % (limit, page, order)

        if name is not None:
            self.name = str(name)
            self.params += '&name=%s' % (self.name)
            return self._build_url(self.artists_url, self.params)
        elif id_ is not None:
            self.params = 'id=%i' % (id_)
            return self._build_url(self.artists_url, self.params)
        else:
            return self._build_url(self.artists_url, self.params)

    def comments(self, id_=None):
        self.comments_url = '/comment/show.json?'

        if id_ is not None:
            self.params = 'id=%i' % (id_)
            return self._build_url(self.comments_url, self.params)
        else:
            raise PybooruError('id_ attribute is empty')

    def wiki(self, query=None, order='title', limit=20, page=1):
        self.wiki_url = '/wiki/index.json?'
        self.params = 'order=%s&limit=%i&page=%i' % (order, limit, page)

        if query is not None:
            self.query = str(query)
            self.params += '&query=%s' % (self.query)
            return self._build_url(self.wiki_url, self.params)
        else:
            return self._build_url(self.wiki_url, self.params)

    def wiki_history(self, title=None):
        self.wiki_history_url = '/wiki/history.json?'

        if title is not None:
            self.title = str(title)
            self.params = 'title=%s' % (self.title)
            return self._build_url(self.wiki_history_url, self.params)
        else:
            raise PybooruError('title atribute is required')

    def notes(self, id_=None):
        self.notes_url = '/note/index.json?'

        if id_ is not None:
            self.params = 'post_id=%i' % (id_)
            return self._build_url(self.notes_url, self.params)
        else:
            return self._build_url(self.notes_url)

    def search_notes(self, query=None):
        self.search_notes_url = '/note/search.json?'

        if query is not None:
            self.query = str(query)
            self.params = 'query=%s' % (self.query)
            return self._build_url(self.search_notes_url, self.params)
        else:
            raise PybooruError('query attribute is empty')

    def history_notes(self, post_id=None, id_=None, limit=10, page=1):
        self.history_notes_url = '/note/history.json?'

        if post_id is not None:
            self.params = 'post_id=%i' % (post_id)
            return self._build_url(self.history_notes_url, self.params)
        elif id_ is not None:
            self.params = 'id=%i' % (post_id)
            return self._build_url(self.history_notes_url, self.params)
        else:
            self.params = 'limit=%i&page=%i' % (limit, page)
            return self._build_url(self.history_notes_url, self.params)

    def users(self, name=None, id_=None):
        self.users_url = '/user/index.json?'

        if name is not None:
            self.name = str(name)
            self.params = 'name=%s' % (self.name)
            return self._build_url(self.users_url, self.params)
        elif id_ is not None:
            self.params = 'id=%i' % (self.id_)
            return self._build_url(self.users_url, self.params)
        else:
            return self._build_url(self.users_url)

    def forum(self, id_=None):
        self.forum_url = '/forum/index.json?'

        if id_ is not None:
            self.params = 'parent_id%i' % (id_)
            return self._build_url(self.forum_url, self.params)
        else:
            return self._build_url(self.forum_url)

    def pools(self, query=None, page=1):
        self.pools_url = '/pool/index.json?'

        if query is not None:
            self.query = str(query)
            self.params = 'query=%s' % (self.query)
            return self._build_url(self.pools_url, self.params)
        else:
            self.params = 'page=%i' % (page)
            return self._build_url(self.pools_url, self.params)

    def pools_posts(self, id_=None, page=1):
        self.pools_posts_url = '/pool/show.json?'

        if id_ is not None:
            self.params = 'id=%i&page=%i' % (id_, page)
            return self._build_url(self.pools_posts_url, self.params)
        else:
            raise PybooruError('id_ attribute is empty')

    def favorites(self, id_=None):
        self.favorites = '/favorite/list_users.json?'

        if id_ is not None:
            self.params = 'id=%i' % (id_)
            return self._build_url(self.favorites, self.params)
        else:
            raise PybooruError('id_ attribute is empty')

    def tag_history(self, post_id=None, user_id=None, user_name=None):
        self.tag_history_url = '/post_tag_history/index.json?'

        if post_id is not None:
            self.params = 'post_id=%i' % (post_id)
            return self._build_url(self.tag_history_url, self.params)
        if user_id is not None:
            self.params = 'user_id=%i' % (user_id)
            return self._build_url(self.tag_history_url, self.params)
        if user_name is not None:
            self.user_name = str(user_name)
            self.params = 'user_name=%s' % (self.user_name)
            return self._build_url(self.tag_history_url, self.params)

if __name__ == '__main__':
    raise PybooruError('Import this module into your project to use')
<commit_msg>More changes in __init__<commit_after>#!/usr/bin/env Python
#encoding: utf-8

"""
    Pybooru is a library for Python for access to API Danbooru based sites.

    Under a MIT License
"""

__author__ = 'Daniel Luque <danielluque14 at gmail.com>'
__version__ = '1.4.9'

#urllib2 imports
from urllib2 import urlopen
from urllib2 import URLError
from urllib2 import HTTPError

#urlparse imports
from urlparse import urlparse

try:
    #simplejson imports
    from simplejson import loads
except ImportError:
    try:
        #Python 2.6 and up
        from json import loads
    except ImportError:
        raise Exception('Pybooru requires the simplejson library to work')

#pyborru resources imports
from resources import http_status_codes
from resources import site_list

class PybooruError(Exception):
    """Class for return error message

    init Parameters:
        msg: The error message
        http_code: The HTTP status code
        url: The URL

    Attributes:
        msg: Return the error message
        http_code: Return the HTTP status code
        url: return the URL
    """

    def __init__(self, msg, http_code=None, url=None):
        self.msg = msg
        self.http_code = http_code
        self.url = url

        if (http_code is not None) and (http_code in http_status_codes) and (
            url is not None):
            self.msg = '%i: %s, %s -- %s -- URL: %s' % (http_code,
                        http_status_codes[http_code][0],
                        http_status_codes[http_code][1], self.msg, url)

    def __str__(self):
        """This function return self.msg"""

        return repr(self.msg)

class Pybooru(object):
    """Pybooru class

    init Parameters:
        siteName: The site name in site_list
        siteURL: URL of based Danbooru site

    Attributes:
        siteName: Return site name
        siteURL: Return URL of based danbooru site
    """

    def __init__(self, siteName=None, siteURL=None):
        self.siteName = siteName
        self.siteURL = siteURL

        if (siteURL is not None) or (siteName is not None):
            if type(siteName) is str:
                self._site_name(siteName.lower())
            elif type(siteURL) is str:
                self._url_validator(siteURL.lower())
            else:
                raise PybooruError('Expected type str for siteName and siteURL')
        else:
            raise PybooruError('siteName and siteURL are None')

    def _site_name(self, siteName):
        """Function for check name site and get URL

        Parameters:
          siteName: The name of a based Danbooru site. You can get list of sites
                    in the resources module.
        """

        if siteName in site_list.keys():
            self.siteURL = site_list[siteName]
        else:
            raise PybooruError(
                        'The site name is not valid, use siteURL parameter'
                        )

    def _url_validator(self, url):
        """URL validator for siteURL parameter of Pybooru

        Parameters:
            url: The URL to validate
        """

        #urlparse() from urlparse module
        parse = urlparse(url)

        if parse.scheme not in ('http', 'https'):
            if parse.scheme == '':
                url = 'http://' + parse.path
            else:
                url = 'http://' + parse.netloc

        self.siteURL = url

    def _build_url(self, api_url, params=None):
        """Builder url for _json_load

        Parameters:
            api_url: The URL of the API function
            params: The parameters of the API function
        """

        if params is not None:
            url_request = self.siteURL + api_url + params
            url_request = self._json_load(url_request)
            return url_request
        else:
            url_request = self.siteURL + api_url
            url_request = self._json_load(url_request)
            return url_request

    def _json_load(self, url):
        """Function for read and return JSON response

        Parameters:
            url: The url for JSON request
        """

        try:
            #urlopen() from module urllib2
            openURL = urlopen(url)
            reading = openURL.read()
            #loads() is a function of simplejson module
            response = loads(reading)
            return response
        except (URLError, HTTPError) as err:
            if hasattr(err, 'code'):
                raise PybooruError('in _json_load', err.code, url)
            else:
                raise PybooruError('in _json_load %s' % (err.reason), url)
        except ValueError as err:
            raise PybooruError('JSON Error: %s in line %s column %s' % (
                               err.msg, err.lineno, err.colno))

    def posts(self, tags=None, limit=10, page=1):
        self.posts_url = '/post/index.json?'
        self.params = 'limit=%i&page=%i' % (limit, page)

        if tags is not None:
            self.tags = str(tags)
            self.params += '&tags=%s' % (tags)
            return self._build_url(self.posts_url, self.params)
        else:
            return self._build_url(self.posts_url, self.params)

    def tags(self, name=None, id_=None, limit=100, page=1, order='name',
                                                            after_id=0):
        self.tags_url = '/tag/index.json?'

        if id_ is not None:
            self.params = 'id=%i' % (id_)
            return self._build_url(self.tags_url, self.params)
        if name is not None:
            self.name = str(name)
            self.params = "name=%s" % (self.name)
            return self._build_url(self.tags_url, self.params)
        else:
            self.params = "limit=%i&page=%i&order=%s&after_id=%i" % (limit,
                                                    page, order, after_id)
            return self._build_url(self.tags_url, self.params)

    def artists(self, name=None, id_=None, limit=20, order='name', page=1):
        self.artists_url = '/artist/index.json?'
        self.params = 'limit=%i&page%i&order=%s' % (limit, page, order)

        if name is not None:
            self.name = str(name)
            self.params += '&name=%s' % (self.name)
            return self._build_url(self.artists_url, self.params)
        elif id_ is not None:
            self.params = 'id=%i' % (id_)
            return self._build_url(self.artists_url, self.params)
        else:
            return self._build_url(self.artists_url, self.params)

    def comments(self, id_=None):
        self.comments_url = '/comment/show.json?'

        if id_ is not None:
            self.params = 'id=%i' % (id_)
            return self._build_url(self.comments_url, self.params)
        else:
            raise PybooruError('id_ attribute is empty')

    def wiki(self, query=None, order='title', limit=20, page=1):
        self.wiki_url = '/wiki/index.json?'
        self.params = 'order=%s&limit=%i&page=%i' % (order, limit, page)

        if query is not None:
            self.query = str(query)
            self.params += '&query=%s' % (self.query)
            return self._build_url(self.wiki_url, self.params)
        else:
            return self._build_url(self.wiki_url, self.params)

    def wiki_history(self, title=None):
        self.wiki_history_url = '/wiki/history.json?'

        if title is not None:
            self.title = str(title)
            self.params = 'title=%s' % (self.title)
            return self._build_url(self.wiki_history_url, self.params)
        else:
            raise PybooruError('title atribute is required')

    def notes(self, id_=None):
        self.notes_url = '/note/index.json?'

        if id_ is not None:
            self.params = 'post_id=%i' % (id_)
            return self._build_url(self.notes_url, self.params)
        else:
            return self._build_url(self.notes_url)

    def search_notes(self, query=None):
        self.search_notes_url = '/note/search.json?'

        if query is not None:
            self.query = str(query)
            self.params = 'query=%s' % (self.query)
            return self._build_url(self.search_notes_url, self.params)
        else:
            raise PybooruError('query attribute is empty')

    def history_notes(self, post_id=None, id_=None, limit=10, page=1):
        self.history_notes_url = '/note/history.json?'

        if post_id is not None:
            self.params = 'post_id=%i' % (post_id)
            return self._build_url(self.history_notes_url, self.params)
        elif id_ is not None:
            self.params = 'id=%i' % (post_id)
            return self._build_url(self.history_notes_url, self.params)
        else:
            self.params = 'limit=%i&page=%i' % (limit, page)
            return self._build_url(self.history_notes_url, self.params)

    def users(self, name=None, id_=None):
        self.users_url = '/user/index.json?'

        if name is not None:
            self.name = str(name)
            self.params = 'name=%s' % (self.name)
            return self._build_url(self.users_url, self.params)
        elif id_ is not None:
            self.params = 'id=%i' % (self.id_)
            return self._build_url(self.users_url, self.params)
        else:
            return self._build_url(self.users_url)

    def forum(self, id_=None):
        self.forum_url = '/forum/index.json?'

        if id_ is not None:
            self.params = 'parent_id%i' % (id_)
            return self._build_url(self.forum_url, self.params)
        else:
            return self._build_url(self.forum_url)

    def pools(self, query=None, page=1):
        self.pools_url = '/pool/index.json?'

        if query is not None:
            self.query = str(query)
            self.params = 'query=%s' % (self.query)
            return self._build_url(self.pools_url, self.params)
        else:
            self.params = 'page=%i' % (page)
            return self._build_url(self.pools_url, self.params)

    def pools_posts(self, id_=None, page=1):
        self.pools_posts_url = '/pool/show.json?'

        if id_ is not None:
            self.params = 'id=%i&page=%i' % (id_, page)
            return self._build_url(self.pools_posts_url, self.params)
        else:
            raise PybooruError('id_ attribute is empty')

    def favorites(self, id_=None):
        self.favorites = '/favorite/list_users.json?'

        if id_ is not None:
            self.params = 'id=%i' % (id_)
            return self._build_url(self.favorites, self.params)
        else:
            raise PybooruError('id_ attribute is empty')

    def tag_history(self, post_id=None, user_id=None, user_name=None):
        self.tag_history_url = '/post_tag_history/index.json?'

        if post_id is not None:
            self.params = 'post_id=%i' % (post_id)
            return self._build_url(self.tag_history_url, self.params)
        if user_id is not None:
            self.params = 'user_id=%i' % (user_id)
            return self._build_url(self.tag_history_url, self.params)
        if user_name is not None:
            self.user_name = str(user_name)
            self.params = 'user_name=%s' % (self.user_name)
            return self._build_url(self.tag_history_url, self.params)

if __name__ == '__main__':
    raise PybooruError('Import this module into your project to use')
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# ZERO 1/0 © 2016
from flask_restful import Resource
from flask import request, g
from AoL.Utils.Exception import ExceptionRest
from AoL.Utils.Utils import processing_rest_exception, processing_rest_success, \
    type_of_insert_rest, type_of_update_rest
from AoL.Utils.Validate import validate_rest

class WishR:
    _table = 'wishes'
    _fields = {
        'name': {'required': True, 'typeof': 'str', 'length': {'min': 3}},
        'priority': {'typeof': 'int'},
        'due_date_at': {'typeof': 'date'},
        'completed_at': {'typeof': 'date'},
    }

    def __init__(self):
        pass

class WishList(Resource, WishR):
    def get(self):
        try:
            _qrg = """
                SELECT array_to_json(array_agg(row_to_json(t) )) as collection
                FROM ( SELECT id, name, priority, due_date_at, completed_at FROM %s WHERE deleted_at is null and create_id=%s )t;
                """ % (self._table, g.user.id,)
            g.db_conn.execute(_qrg)
            if g.db_conn.count() > 0:
                _collection = g.db_conn.one()[0]
                if _collection:
                    _data = {self._table: _collection}
                    _get = processing_rest_success(data=_data)
                else:
                    raise ExceptionRest(status_code=404, message="No se han encontrado resultados")
            else:
                raise ExceptionRest(status_code=404, message="No se han encontrado resultados")
        except (Exception, ExceptionRest), e:
            _get = processing_rest_exception(e)
        return _get

    def post(self):
        _request = request.json
        try:
            _errors = validate_rest(fields=self._fields, request=_request)
            if not _errors:
                _col, _val = type_of_insert_rest(self._fields, _request)
                _qrp = """
                    INSERT INTO %s (create_id , %s ) VALUES (%s, %s)
                    RETURNING (select row_to_json(collection) FROM (VALUES(id)) collection(id));
                """ % (self._table, _col, g.user.id, _val)
                g.db_conn.execute(_qrp)
                if g.db_conn.count() > 0:
                    _data = {self._table: g.db_conn.one()}
                    _post = processing_rest_success(data=_data, message='Fue creado correctamente',
                                                    status_code=201)
                else:
                    raise ExceptionRest(status_code=500, message='No se ha podido registrar')
            else:
                raise ExceptionRest(status_code=400, errors=_errors)
        except (Exception, ExceptionRest), e:
            _post = processing_rest_exception(e)
        return _post

class Wish(Resource, WishR):
    def get(self, id):
        try:
            _qrg = """
                    SELECT array_to_json(array_agg(row_to_json(t) )) as collection
                    FROM ( SELECT id, name,  priority ,due_date_at,completed_at
                    FROM %s WHERE deleted_at is null and create_id=%s and id = %s)t;
                """ % (self._table, g.user.id, id,)
            g.db_conn.execute(_qrg)
            if g.db_conn.count() > 0:
                _collection = g.db_conn.one()[0]
                if _collection:
                    _data = {self._table: _collection}
                    _get = processing_rest_success(data=_data)
                else:
                    raise ExceptionRest(status_code=404, message="No se han encontrado resultados")
            else:
                raise ExceptionRest(status_code=404, message="No se han encontrado resultados")
        except (Exception, ExceptionRest), e:
            _get = processing_rest_exception(e)
        return _get

    def put(self, id):
        _request = request.json
        try:
            _errors = validate_rest(fields=self._fields, request=_request, method='put')
            if not _errors:
                _val = type_of_update_rest(self._fields, _request)
                _qrp = "UPDATE %s SET %s WHERE id=%s;" % (self._table, _val, id,)
                g.db_conn.execute(_qrp)
                if g.db_conn.count() > 0:
                    _put = processing_rest_success(status_code=201, message="El registro fue actualizado correctamente")
                else:
                    raise ExceptionRest(status_code=404,
                                        message="No se ha podido encontrar el registro, para actualizar.")
            else:
                raise ExceptionRest(status_code=400, errors=_errors)
        except (Exception, ExceptionRest), e:
            _put = processing_rest_exception(e)
        return _put

    def delete(self, id):
        try:
            _qrd = "UPDATE %s SET deleted_at=current_timestamp WHERE id=%s;" % (self._table, id,)
            g.db_conn.execute(_qrd)
            if g.db_conn.count() > 0:
                _delete = processing_rest_success(status_code=201, message="El registro fue eliminado correctamente")
            else:
                raise ExceptionRest(status_code=404,
                                    message="No se ha podido encontrar el registro, para eliminar.")
        except (Exception, ExceptionRest), e:
            _delete = processing_rest_exception(e)
        return _delete
<commit_msg>[REF] Rest service wish not show completed<commit_after># -*- coding: utf-8 -*-
# ZERO 1/0 © 2016
from flask_restful import Resource
from flask import request, g
from AoL.Utils.Exception import ExceptionRest
from AoL.Utils.Utils import processing_rest_exception, processing_rest_success, \
    type_of_insert_rest, type_of_update_rest
from AoL.Utils.Validate import validate_rest

class WishR:
    _table = 'wishes'
    _fields = {
        'name': {'required': True, 'typeof': 'str', 'length': {'min': 3}},
        'priority': {'typeof': 'int'},
        'due_date_at': {'typeof': 'date'},
        'completed_at': {'typeof': 'date'},
    }

    def __init__(self):
        pass

class WishList(Resource, WishR):
    def get(self):
        try:
            _qrg = """
                SELECT array_to_json(array_agg(row_to_json(t) )) as collection
                FROM ( SELECT id, name, priority, due_date_at, completed_at FROM %s WHERE deleted_at is null
                and completed_at is NULL and create_id=%s )t;
                """ % (self._table, g.user.id,)
            g.db_conn.execute(_qrg)
            if g.db_conn.count() > 0:
                _collection = g.db_conn.one()[0]
                if _collection:
                    _data = {self._table: _collection}
                    _get = processing_rest_success(data=_data)
                else:
                    raise ExceptionRest(status_code=404, message="No se han encontrado resultados")
            else:
                raise ExceptionRest(status_code=404, message="No se han encontrado resultados")
        except (Exception, ExceptionRest), e:
            _get = processing_rest_exception(e)
        return _get

    def post(self):
        _request = request.json
        try:
            _errors = validate_rest(fields=self._fields, request=_request)
            if not _errors:
                _col, _val = type_of_insert_rest(self._fields, _request)
                _qrp = """
                    INSERT INTO %s (create_id , %s ) VALUES (%s, %s)
                    RETURNING (select row_to_json(collection) FROM (VALUES(id)) collection(id));
                """ % (self._table, _col, g.user.id, _val)
                g.db_conn.execute(_qrp)
                if g.db_conn.count() > 0:
                    _data = {self._table: g.db_conn.one()}
                    _post = processing_rest_success(data=_data, message='Fue creado correctamente',
                                                    status_code=201)
                else:
                    raise ExceptionRest(status_code=500, message='No se ha podido registrar')
            else:
                raise ExceptionRest(status_code=400, errors=_errors)
        except (Exception, ExceptionRest), e:
            _post = processing_rest_exception(e)
        return _post

class Wish(Resource, WishR):
    def get(self, id):
        try:
            _qrg = """
                    SELECT array_to_json(array_agg(row_to_json(t) )) as collection
                    FROM ( SELECT id, name,  priority ,due_date_at,completed_at
                    FROM %s WHERE deleted_at is null and completed_at is NULL and create_id=%s and id = %s)t;
                """ % (self._table, g.user.id, id,)
            g.db_conn.execute(_qrg)
            if g.db_conn.count() > 0:
                _collection = g.db_conn.one()[0]
                if _collection:
                    _data = {self._table: _collection}
                    _get = processing_rest_success(data=_data)
                else:
                    raise ExceptionRest(status_code=404, message="No se han encontrado resultados")
            else:
                raise ExceptionRest(status_code=404, message="No se han encontrado resultados")
        except (Exception, ExceptionRest), e:
            _get = processing_rest_exception(e)
        return _get

    def put(self, id):
        _request = request.json
        try:
            _errors = validate_rest(fields=self._fields, request=_request, method='put')
            if not _errors:
                _val = type_of_update_rest(self._fields, _request)
                _qrp = "UPDATE %s SET %s WHERE id=%s;" % (self._table, _val, id,)
                g.db_conn.execute(_qrp)
                if g.db_conn.count() > 0:
                    _put = processing_rest_success(status_code=201, message="El registro fue actualizado correctamente")
                else:
                    raise ExceptionRest(status_code=404,
                                        message="No se ha podido encontrar el registro, para actualizar.")
            else:
                raise ExceptionRest(status_code=400, errors=_errors)
        except (Exception, ExceptionRest), e:
            _put = processing_rest_exception(e)
        return _put

    def delete(self, id):
        try:
            _qrd = "UPDATE %s SET deleted_at=current_timestamp WHERE id=%s;" % (self._table, id,)
            g.db_conn.execute(_qrd)
            if g.db_conn.count() > 0:
                _delete = processing_rest_success(status_code=201, message="El registro fue eliminado correctamente")
            else:
                raise ExceptionRest(status_code=404,
                                    message="No se ha podido encontrar el registro, para eliminar.")
        except (Exception, ExceptionRest), e:
            _delete = processing_rest_exception(e)
        return _delete
<|endoftext|>