<commit_before>"""Add more informations on ADS

Revision ID: 59e5faf237f8
Revises: 27df69f29c56
Create Date: 2015-04-08 16:34:22.387152

"""

# revision identifiers, used by Alembic.
revision = '59e5faf237f8'
down_revision = '27df69f29c56'

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

def upgrade():
    vehicle_type = postgresql.ENUM('sedan', 'mpv', 'station_wagon', 'normal',
            name='vehicle_type')
    op.add_column('ADS', sa.Column('AC_vehicle', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('amex_accepted', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('baby_seat', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('bank_check_accepted', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('bike_accepted', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('color', sa.String(length=255), nullable=True))
    op.add_column('ADS', sa.Column('conventionne', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('credit_card_accepted', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('dvd_player', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('every_destination', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('fresh_drink', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('gps', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('luxary', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('nfc_cc_accepted', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('pet_accepted', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('snv', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('telepeage', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('type_', vehicle_type, nullable=True))
    op.add_column('ADS', sa.Column('wifi', sa.Boolean(), nullable=True))

def downgrade():
    op.drop_column('ADS', 'wifi')
    op.drop_column('ADS', 'type_')
    op.drop_column('ADS', 'telepeage')
    op.drop_column('ADS', 'snv')
    op.drop_column('ADS', 'pet_accepted')
    op.drop_column('ADS', 'nfc_cc_accepted')
    op.drop_column('ADS', 'luxary')
    op.drop_column('ADS', 'gps')
    op.drop_column('ADS', 'fresh_drink')
    op.drop_column('ADS', 'every_destination')
    op.drop_column('ADS', 'dvd_player')
    op.drop_column('ADS', 'credit_card_accepted')
    op.drop_column('ADS', 'conventionne')
    op.drop_column('ADS', 'color')
    op.drop_column('ADS', 'bike_accepted')
    op.drop_column('ADS', 'bank_check_accepted')
    op.drop_column('ADS', 'baby_seat')
    op.drop_column('ADS', 'amex_accepted')
    op.drop_column('ADS', 'AC_vehicle')
<commit_msg>fix the creation of the vehicle_type enum by alembic<commit_after>"""Add more informations on ADS

Revision ID: 59e5faf237f8
Revises: 27df69f29c56
Create Date: 2015-04-08 16:34:22.387152

"""

# revision identifiers, used by Alembic.
revision = '59e5faf237f8'
down_revision = '27df69f29c56'

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

def upgrade():

    # enum are not automatically created, so we create it
    # workaround from: https://bitbucket.org/zzzeek/alembic/issue/89/opadd_column-and-opdrop_column-should
    vehicle_type = postgresql.ENUM('sedan', 'mpv', 'station_wagon', 'normal',
            name='vehicle_type')
    bind = op.get_bind()
    impl = vehicle_type.dialect_impl(bind.dialect)
    impl.create(bind, checkfirst=True)

    op.add_column('ADS', sa.Column('AC_vehicle', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('amex_accepted', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('baby_seat', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('bank_check_accepted', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('bike_accepted', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('color', sa.String(length=255), nullable=True))
    op.add_column('ADS', sa.Column('conventionne', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('credit_card_accepted', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('dvd_player', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('every_destination', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('fresh_drink', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('gps', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('luxary', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('nfc_cc_accepted', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('pet_accepted', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('snv', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('telepeage', sa.Boolean(), nullable=True))
    op.add_column('ADS', sa.Column('type_', vehicle_type, nullable=True))
    op.add_column('ADS', sa.Column('wifi', sa.Boolean(), nullable=True))

def downgrade():
    op.drop_column('ADS', 'wifi')
    op.drop_column('ADS', 'type_')
    op.drop_column('ADS', 'telepeage')
    op.drop_column('ADS', 'snv')
    op.drop_column('ADS', 'pet_accepted')
    op.drop_column('ADS', 'nfc_cc_accepted')
    op.drop_column('ADS', 'luxary')
    op.drop_column('ADS', 'gps')
    op.drop_column('ADS', 'fresh_drink')
    op.drop_column('ADS', 'every_destination')
    op.drop_column('ADS', 'dvd_player')
    op.drop_column('ADS', 'credit_card_accepted')
    op.drop_column('ADS', 'conventionne')
    op.drop_column('ADS', 'color')
    op.drop_column('ADS', 'bike_accepted')
    op.drop_column('ADS', 'bank_check_accepted')
    op.drop_column('ADS', 'baby_seat')
    op.drop_column('ADS', 'amex_accepted')
    op.drop_column('ADS', 'AC_vehicle')
<|endoftext|>


<commit_before># coding=utf-8
import os
import platform
import sys
from typing import Optional, Dict, Any, List

from dbt.logger import GLOBAL_LOGGER as logger
import dbt.clients.system
import dbt.exceptions
from dbt.adapters.factory import get_adapter, register_adapter
from dbt.config import Project, Profile, PROFILES_DIR
from dbt.config.renderer import DbtProjectYamlRenderer, ProfileRenderer
from dbt.config.utils import parse_cli_vars
from dbt.context.base import generate_base_context
from dbt.context.target import generate_target_context
from dbt.clients.yaml_helper import load_yaml_text
from dbt.links import ProfileConfigDocs
from dbt.ui import green, red
from dbt.version import get_installed_version

from dbt.task.base import BaseTask, get_nearest_project_dir

PROFILE_DIR_MESSAGE = """To view your profiles.yml file, run:

{open_cmd} {profiles_dir}"""

ONLY_PROFILE_MESSAGE = '''
A `dbt_project.yml` file was not found in this directory.
Using the only profile `{}`.
'''.lstrip()

MULTIPLE_PROFILE_MESSAGE = '''
A `dbt_project.yml` file was not found in this directory.
dbt found the following profiles:
{}

To debug one of these profiles, run:
dbt debug --profile [profile-name]
'''.lstrip()

COULD_NOT_CONNECT_MESSAGE = '''
dbt was unable to connect to the specified database.
The database returned the following error:

  >{err}

Check your database credentials and try again. For more information, visit:
{url}
'''.lstrip()

MISSING_PROFILE_MESSAGE = '''
dbt looked for a profiles.yml file in {path}, but did
not find one. For more information on configuring your profile, consult the
documentation:

{url}
'''.lstrip()

FILE_NOT_FOUND = 'file not found'

class QueryCommentedProfile(Profile):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.query_comment = None

class DebugTask(BaseTask):
    def __init__(self, args, config):
        super().__init__(args, config)
        self.profiles_dir = getattr(self.args, 'profiles_dir', PROFILES_DIR)
        self.profile_path = os.path.join(self.profiles_dir, 'profiles.yml')
        try:
            self.project_dir = get_nearest_project_dir(self.args)
        except dbt.exceptions.Exception:
            # we probably couldn't find a project directory. Set project dir
            # to whatever was given, or default to the current directory.
            if args.project_dir:
                self.project_dir = args.project_dir
            else:
                self.project_dir = os.getcwd()
        self.project_path = os.path.join(self.project_dir, 'dbt_project.yml')
        self.cli_vars = parse_cli_vars(getattr(self.args, 'vars', '{}'))

        # set by _load_*
        self.profile: Optional[Profile] = None
        self.profile_fail_details = ''
        self.raw_profile_data: Optional[Dict[str, Any]] = None
        self.profile_name: Optional[str] = None
        self.project: Optional[Project] = None
        self.project_fail_details = ''
        self.any_failure = False
        self.messages: List[str] = []

    @property
    def project_profile(self):
        if self.project is None:
            return None
        return self.project.profile_name

    def path_info(self):
        open_cmd = dbt.clients.system.open_dir_cmd()

        message = PROFILE_DIR_MESSAGE.format(
            open_cmd=open_cmd,
            profiles_dir=self.profiles_dir
        )

        logger.info(message)

    def run(self):
        if self.args.config_dir:
            self.path_info()
            return True

        version = get_installed_version().to_version_string(skip_matcher=True)
        print('dbt version: {}'.format(version))
        print('python version: {}'.format(sys.version.split()[0]))
        print('python path: {}'.format(sys.executable))
        print('os info: {}'.format(platform.platform()))
        print('Using profiles.yml file at {}'.format(self.profile_path))
        print('Using dbt_project.yml file at {}'.format(self.project_path))
        print('')
        self.test_configuration()
        self.test_dependencies()
        self.test_connection()

        for message in self.messages:
            print(message)
            print('')

        return not self.any_failure

    def interpret_results(self, results):
        return results

    def _load_project(self):
        if not os.path.exists(self.project_path):
            self.project_fail_details = FILE_NOT_FOUND
            return red('ERROR not found')

        if self.profile is None:
            ctx = generate_base_context(self.cli_vars)
        else:
            ctx = generate_target_context(self.profile, self.cli_vars)

        renderer = DbtProjectYamlRenderer(ctx)

        try:
            self.project = Project.from_project_root(
                self.project_dir,
                renderer,
                verify_version=getattr(self.args, 'version_check', False),
            )
        except dbt.exceptions.DbtConfigError as exc:
            self.project_fail_details = str(exc)
            return red('ERROR invalid')

        return green('OK found and valid')

    def _profile_found(self):
        if not self.raw_profile_data:
            return red('ERROR not found')
        assert self.raw_profile_data is not None
        if self.profile_name in self.raw_profile_data:
            return green('OK found')
        else:
            return red('ERROR not found')

    def _target_found(self):
        requirements = (self.raw_profile_data and self.profile_name and
                        self.target_name)
        if not requirements:
            return red('ERROR not found')
        # mypy appeasement, we checked just above
        assert self.raw_profile_data is not None
        assert self.profile_name is not None
        assert self.target_name is not None
        if self.profile_name not in self.raw_profile_data:
            return red('ERROR not found')
        profiles = self.raw_profile_data[self.profile_name]['outputs']
        if self.target_name not in profiles:
            return red('ERROR not found')
        return green('OK found')

    def _choose_profile_names(self) -> Optional[List[str]]:
        project_profile: Optional[str] = None
        if os.path.exists(self.project_path):
            try:
                partial = Project.partial_load(
                    os.path.dirname(self.project_path),
                    verify_version=getattr(self.args, 'version_check', False),
                )
                renderer = DbtProjectYamlRenderer(
                    generate_base_context(self.cli_vars)
                )
                project_profile = partial.render_profile_name(renderer)
            except dbt.exceptions.DbtProjectError:
                pass

        args_profile: Optional[str] = getattr(self.args, 'profile', None)

        try:
            return [Profile.pick_profile_name(args_profile, project_profile)]
        except dbt.exceptions.DbtConfigError:
            pass
        # try to guess

        profiles = []
        if self.raw_profile_data:
            profiles = [k for k in self.raw_profile_data if k != 'config']
            if project_profile is None:
                self.messages.append('Could not load dbt_project.yml')
            elif len(profiles) == 0:
                self.messages.append('The profiles.yml has no profiles')
            elif len(profiles) == 1:
                self.messages.append(ONLY_PROFILE_MESSAGE.format(profiles[0]))
            else:
                self.messages.append(MULTIPLE_PROFILE_MESSAGE.format(
                    '\n'.join(' - {}'.format(o) for o in profiles)
                ))
        return profiles

    def _choose_target_name(self, profile_name: str):
        has_raw_profile = (
            self.raw_profile_data is not None and
            profile_name in self.raw_profile_data
        )

        if not has_raw_profile:
            return None

        # mypy appeasement, we checked just above
        assert self.raw_profile_data is not None
        raw_profile = self.raw_profile_data[profile_name]

        renderer = ProfileRenderer(generate_base_context(self.cli_vars))

        target_name, _ = Profile.render_profile(
            raw_profile=raw_profile,
            profile_name=profile_name,
            target_override=getattr(self.args, 'target', None),
            renderer=renderer
        )
        return target_name

    def _load_profile(self):
        if not os.path.exists(self.profile_path):
            self.profile_fail_details = FILE_NOT_FOUND
            self.messages.append(MISSING_PROFILE_MESSAGE.format(
                path=self.profile_path, url=ProfileConfigDocs
            ))
            self.any_failure = True
            return red('ERROR not found')

        try:
            raw_profile_data = load_yaml_text(
                dbt.clients.system.load_file_contents(self.profile_path)
            )
        except Exception:
            pass  # we'll report this when we try to load the profile for real
        else:
            if isinstance(raw_profile_data, dict):
                self.raw_profile_data = raw_profile_data

        profile_errors = []
        profile_names = self._choose_profile_names()
        renderer = ProfileRenderer(generate_base_context(self.cli_vars))
        for profile_name in profile_names:
            try:
                profile: Profile = QueryCommentedProfile.render_from_args(
                    self.args, renderer, profile_name
                )
            except dbt.exceptions.DbtConfigError as exc:
                profile_errors.append(str(exc))
            else:
                if len(profile_names) == 1:
                    # if a profile was specified, set it on the task
                    self.target_name = self._choose_target_name(profile_name)
                    self.profile = profile

        if profile_errors:
            self.profile_fail_details = '\n\n'.join(profile_errors)
            return red('ERROR invalid')
        return green('OK found and valid')

    def test_git(self):
        try:
            dbt.clients.system.run_cmd(os.getcwd(), ['git', '--help'])
        except dbt.exceptions.ExecutableError as exc:
            self.messages.append('Error from git --help: {!s}'.format(exc))
            self.any_failure = True
            return red('ERROR')
        return green('OK found')

    def test_dependencies(self):
        print('Required dependencies:')
        print(' - git [{}]'.format(self.test_git()))
        print('')

    def test_configuration(self):
        profile_status = self._load_profile()
        project_status = self._load_project()
        print('Configuration:')
        print('  profiles.yml file [{}]'.format(profile_status))
        print('  dbt_project.yml file [{}]'.format(project_status))
        # skip profile stuff if we can't find a profile name
        if self.profile_name is not None:
            print('  profile: {} [{}]'.format(self.profile_name,
                                              self._profile_found()))
            print('  target: {} [{}]'.format(self.target_name,
                                             self._target_found()))
        print('')
        self._log_project_fail()
        self._log_profile_fail()

    def _log_project_fail(self):
        if not self.project_fail_details:
            return

        self.any_failure = True
        if self.project_fail_details == FILE_NOT_FOUND:
            return
        print('Project loading failed for the following reason:')
        print(self.project_fail_details)
        print('')

    def _log_profile_fail(self):
        if not self.profile_fail_details:
            return

        self.any_failure = True
        if self.profile_fail_details == FILE_NOT_FOUND:
            return
        print('Profile loading failed for the following reason:')
        print(self.profile_fail_details)
        print('')

    @staticmethod
    def attempt_connection(profile):
        """Return a string containing the error message, or None if there was
        no error.
        """
        register_adapter(profile)
        adapter = get_adapter(profile)
        try:
            with adapter.connection_named('debug'):
                adapter.debug_query()
        except Exception as exc:
            return COULD_NOT_CONNECT_MESSAGE.format(
                err=str(exc),
                url=ProfileConfigDocs,
            )

        return None

    def _connection_result(self):
        result = self.attempt_connection(self.profile)
        if result is not None:
            self.messages.append(result)
            self.any_failure = True
            return red('ERROR')
        return green('OK connection ok')

    def test_connection(self):
        if not self.profile:
            return
        print('Connection:')
        for k, v in self.profile.credentials.connection_info():
            print('  {}: {}'.format(k, v))
        print('  Connection test: {}'.format(self._connection_result()))
        print('')

    @classmethod
    def validate_connection(cls, target_dict):
        """Validate a connection dictionary. On error, raises a DbtConfigError.
        """
        target_name = 'test'
        # make a fake profile that we can parse
        profile_data = {
            'outputs': {
                target_name: target_dict,
            },
        }
        # this will raise a DbtConfigError on failure
        profile = Profile.from_raw_profile_info(
            raw_profile=profile_data,
            profile_name='',
            target_override=target_name,
            renderer=ProfileRenderer(generate_base_context({})),
        )
        result = cls.attempt_connection(profile)
        if result is not None:
            raise dbt.exceptions.DbtProfileError(
                result,
                result_type='connection_failure'
            )
<commit_msg>use ExitCodes enum for exit code<commit_after># coding=utf-8
import os
import platform
import sys
from typing import Optional, Dict, Any, List

from dbt.logger import GLOBAL_LOGGER as logger
import dbt.clients.system
import dbt.exceptions
from dbt.adapters.factory import get_adapter, register_adapter
from dbt.config import Project, Profile, PROFILES_DIR
from dbt.config.renderer import DbtProjectYamlRenderer, ProfileRenderer
from dbt.config.utils import parse_cli_vars
from dbt.context.base import generate_base_context
from dbt.context.target import generate_target_context
from dbt.clients.yaml_helper import load_yaml_text
from dbt.links import ProfileConfigDocs
from dbt.ui import green, red
from dbt.version import get_installed_version
from dbt.utils import ExitCodes

from dbt.task.base import BaseTask, get_nearest_project_dir

PROFILE_DIR_MESSAGE = """To view your profiles.yml file, run:

{open_cmd} {profiles_dir}"""

ONLY_PROFILE_MESSAGE = '''
A `dbt_project.yml` file was not found in this directory.
Using the only profile `{}`.
'''.lstrip()

MULTIPLE_PROFILE_MESSAGE = '''
A `dbt_project.yml` file was not found in this directory.
dbt found the following profiles:
{}

To debug one of these profiles, run:
dbt debug --profile [profile-name]
'''.lstrip()

COULD_NOT_CONNECT_MESSAGE = '''
dbt was unable to connect to the specified database.
The database returned the following error:

  >{err}

Check your database credentials and try again. For more information, visit:
{url}
'''.lstrip()

MISSING_PROFILE_MESSAGE = '''
dbt looked for a profiles.yml file in {path}, but did
not find one. For more information on configuring your profile, consult the
documentation:

{url}
'''.lstrip()

FILE_NOT_FOUND = 'file not found'

class QueryCommentedProfile(Profile):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.query_comment = None

class DebugTask(BaseTask):
    def __init__(self, args, config):
        super().__init__(args, config)
        self.profiles_dir = getattr(self.args, 'profiles_dir', PROFILES_DIR)
        self.profile_path = os.path.join(self.profiles_dir, 'profiles.yml')
        try:
            self.project_dir = get_nearest_project_dir(self.args)
        except dbt.exceptions.Exception:
            # we probably couldn't find a project directory. Set project dir
            # to whatever was given, or default to the current directory.
            if args.project_dir:
                self.project_dir = args.project_dir
            else:
                self.project_dir = os.getcwd()
        self.project_path = os.path.join(self.project_dir, 'dbt_project.yml')
        self.cli_vars = parse_cli_vars(getattr(self.args, 'vars', '{}'))

        # set by _load_*
        self.profile: Optional[Profile] = None
        self.profile_fail_details = ''
        self.raw_profile_data: Optional[Dict[str, Any]] = None
        self.profile_name: Optional[str] = None
        self.project: Optional[Project] = None
        self.project_fail_details = ''
        self.any_failure = False
        self.messages: List[str] = []

    @property
    def project_profile(self):
        if self.project is None:
            return None
        return self.project.profile_name

    def path_info(self):
        open_cmd = dbt.clients.system.open_dir_cmd()

        message = PROFILE_DIR_MESSAGE.format(
            open_cmd=open_cmd,
            profiles_dir=self.profiles_dir
        )

        logger.info(message)

    def run(self):
        if self.args.config_dir:
            self.path_info()
            return True

        version = get_installed_version().to_version_string(skip_matcher=True)
        print('dbt version: {}'.format(version))
        print('python version: {}'.format(sys.version.split()[0]))
        print('python path: {}'.format(sys.executable))
        print('os info: {}'.format(platform.platform()))
        print('Using profiles.yml file at {}'.format(self.profile_path))
        print('Using dbt_project.yml file at {}'.format(self.project_path))
        print('')
        self.test_configuration()
        self.test_dependencies()
        self.test_connection()

        for message in self.messages:
            print(message)
            print('')

        return not self.any_failure

    def interpret_results(self, results):
        if results:
            return ExitCodes.Success
        return ExitCodes.ModelError

    def _load_project(self):
        if not os.path.exists(self.project_path):
            self.project_fail_details = FILE_NOT_FOUND
            return red('ERROR not found')

        if self.profile is None:
            ctx = generate_base_context(self.cli_vars)
        else:
            ctx = generate_target_context(self.profile, self.cli_vars)

        renderer = DbtProjectYamlRenderer(ctx)

        try:
            self.project = Project.from_project_root(
                self.project_dir,
                renderer,
                verify_version=getattr(self.args, 'version_check', False),
            )
        except dbt.exceptions.DbtConfigError as exc:
            self.project_fail_details = str(exc)
            return red('ERROR invalid')

        return green('OK found and valid')

    def _profile_found(self):
        if not self.raw_profile_data:
            return red('ERROR not found')
        assert self.raw_profile_data is not None
        if self.profile_name in self.raw_profile_data:
            return green('OK found')
        else:
            return red('ERROR not found')

    def _target_found(self):
        requirements = (self.raw_profile_data and self.profile_name and
                        self.target_name)
        if not requirements:
            return red('ERROR not found')
        # mypy appeasement, we checked just above
        assert self.raw_profile_data is not None
        assert self.profile_name is not None
        assert self.target_name is not None
        if self.profile_name not in self.raw_profile_data:
            return red('ERROR not found')
        profiles = self.raw_profile_data[self.profile_name]['outputs']
        if self.target_name not in profiles:
            return red('ERROR not found')
        return green('OK found')

    def _choose_profile_names(self) -> Optional[List[str]]:
        project_profile: Optional[str] = None
        if os.path.exists(self.project_path):
            try:
                partial = Project.partial_load(
                    os.path.dirname(self.project_path),
                    verify_version=getattr(self.args, 'version_check', False),
                )
                renderer = DbtProjectYamlRenderer(
                    generate_base_context(self.cli_vars)
                )
                project_profile = partial.render_profile_name(renderer)
            except dbt.exceptions.DbtProjectError:
                pass

        args_profile: Optional[str] = getattr(self.args, 'profile', None)

        try:
            return [Profile.pick_profile_name(args_profile, project_profile)]
        except dbt.exceptions.DbtConfigError:
            pass
        # try to guess

        profiles = []
        if self.raw_profile_data:
            profiles = [k for k in self.raw_profile_data if k != 'config']
            if project_profile is None:
                self.messages.append('Could not load dbt_project.yml')
            elif len(profiles) == 0:
                self.messages.append('The profiles.yml has no profiles')
            elif len(profiles) == 1:
                self.messages.append(ONLY_PROFILE_MESSAGE.format(profiles[0]))
            else:
                self.messages.append(MULTIPLE_PROFILE_MESSAGE.format(
                    '\n'.join(' - {}'.format(o) for o in profiles)
                ))
        return profiles

    def _choose_target_name(self, profile_name: str):
        has_raw_profile = (
            self.raw_profile_data is not None and
            profile_name in self.raw_profile_data
        )

        if not has_raw_profile:
            return None

        # mypy appeasement, we checked just above
        assert self.raw_profile_data is not None
        raw_profile = self.raw_profile_data[profile_name]

        renderer = ProfileRenderer(generate_base_context(self.cli_vars))

        target_name, _ = Profile.render_profile(
            raw_profile=raw_profile,
            profile_name=profile_name,
            target_override=getattr(self.args, 'target', None),
            renderer=renderer
        )
        return target_name

    def _load_profile(self):
        if not os.path.exists(self.profile_path):
            self.profile_fail_details = FILE_NOT_FOUND
            self.messages.append(MISSING_PROFILE_MESSAGE.format(
                path=self.profile_path, url=ProfileConfigDocs
            ))
            self.any_failure = True
            return red('ERROR not found')

        try:
            raw_profile_data = load_yaml_text(
                dbt.clients.system.load_file_contents(self.profile_path)
            )
        except Exception:
            pass  # we'll report this when we try to load the profile for real
        else:
            if isinstance(raw_profile_data, dict):
                self.raw_profile_data = raw_profile_data

        profile_errors = []
        profile_names = self._choose_profile_names()
        renderer = ProfileRenderer(generate_base_context(self.cli_vars))
        for profile_name in profile_names:
            try:
                profile: Profile = QueryCommentedProfile.render_from_args(
                    self.args, renderer, profile_name
                )
            except dbt.exceptions.DbtConfigError as exc:
                profile_errors.append(str(exc))
            else:
                if len(profile_names) == 1:
                    # if a profile was specified, set it on the task
                    self.target_name = self._choose_target_name(profile_name)
                    self.profile = profile

        if profile_errors:
            self.profile_fail_details = '\n\n'.join(profile_errors)
            return red('ERROR invalid')
        return green('OK found and valid')

    def test_git(self):
        try:
            dbt.clients.system.run_cmd(os.getcwd(), ['git', '--help'])
        except dbt.exceptions.ExecutableError as exc:
            self.messages.append('Error from git --help: {!s}'.format(exc))
            self.any_failure = True
            return red('ERROR')
        return green('OK found')

    def test_dependencies(self):
        print('Required dependencies:')
        print(' - git [{}]'.format(self.test_git()))
        print('')

    def test_configuration(self):
        profile_status = self._load_profile()
        project_status = self._load_project()
        print('Configuration:')
        print('  profiles.yml file [{}]'.format(profile_status))
        print('  dbt_project.yml file [{}]'.format(project_status))
        # skip profile stuff if we can't find a profile name
        if self.profile_name is not None:
            print('  profile: {} [{}]'.format(self.profile_name,
                                              self._profile_found()))
            print('  target: {} [{}]'.format(self.target_name,
                                             self._target_found()))
        print('')
        self._log_project_fail()
        self._log_profile_fail()

    def _log_project_fail(self):
        if not self.project_fail_details:
            return

        self.any_failure = True
        if self.project_fail_details == FILE_NOT_FOUND:
            return
        print('Project loading failed for the following reason:')
        print(self.project_fail_details)
        print('')

    def _log_profile_fail(self):
        if not self.profile_fail_details:
            return

        self.any_failure = True
        if self.profile_fail_details == FILE_NOT_FOUND:
            return
        print('Profile loading failed for the following reason:')
        print(self.profile_fail_details)
        print('')

    @staticmethod
    def attempt_connection(profile):
        """Return a string containing the error message, or None if there was
        no error.
        """
        register_adapter(profile)
        adapter = get_adapter(profile)
        try:
            with adapter.connection_named('debug'):
                adapter.debug_query()
        except Exception as exc:
            return COULD_NOT_CONNECT_MESSAGE.format(
                err=str(exc),
                url=ProfileConfigDocs,
            )

        return None

    def _connection_result(self):
        result = self.attempt_connection(self.profile)
        if result is not None:
            self.messages.append(result)
            self.any_failure = True
            return red('ERROR')
        return green('OK connection ok')

    def test_connection(self):
        if not self.profile:
            return
        print('Connection:')
        for k, v in self.profile.credentials.connection_info():
            print('  {}: {}'.format(k, v))
        print('  Connection test: {}'.format(self._connection_result()))
        print('')

    @classmethod
    def validate_connection(cls, target_dict):
        """Validate a connection dictionary. On error, raises a DbtConfigError.
        """
        target_name = 'test'
        # make a fake profile that we can parse
        profile_data = {
            'outputs': {
                target_name: target_dict,
            },
        }
        # this will raise a DbtConfigError on failure
        profile = Profile.from_raw_profile_info(
            raw_profile=profile_data,
            profile_name='',
            target_override=target_name,
            renderer=ProfileRenderer(generate_base_context({})),
        )
        result = cls.attempt_connection(profile)
        if result is not None:
            raise dbt.exceptions.DbtProfileError(
                result,
                result_type='connection_failure'
            )
<|endoftext|>


<commit_before>import json
from base64 import b64decode, b64encode

from django.conf import settings

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad as crypto_pad
from Crypto.Util.Padding import unpad as crypto_unpad
from Crypto.Util.py3compat import bord

AES_BLOCK_SIZE = 16
AES_KEY_MAX_LEN = 32  # AES key must be either 16, 24, or 32 bytes long
PAD_CHAR = b' '

def simple_pad(bytestring, block_size, char=PAD_CHAR):
    """
    Pad `bytestring` to a multiple of `block_size` in length by appending
    `char`. `char` defaults to space.

    >>> padded = simple_pad(b'xyzzy', 8, b'*')
    >>> padded == b'xyzzy***'
    True

    """
    assert isinstance(bytestring, bytes)
    padding = ((block_size - len(bytestring)) % block_size) * char
    return bytestring + padding

def b64_aes_encrypt(message):
    """
    AES-encrypt and base64-encode `message`.

    Uses Django SECRET_KEY as AES key.

    >>> settings.SECRET_KEY = 'xyzzy'
    >>> encrypted = b64_aes_encrypt('Around you is a forest.')
    >>> encrypted == 'Vh2Tmlnr5+out2PQDefkudZ2frfze5onsAlUGTLv3Oc='
    True

    """
    if isinstance(settings.SECRET_KEY, bytes):
        secret_key_bytes = settings.SECRET_KEY
    else:
        secret_key_bytes = settings.SECRET_KEY.encode('ascii')
    aes_key = simple_pad(secret_key_bytes, AES_BLOCK_SIZE)[:AES_KEY_MAX_LEN]
    # We never need to unpad the key, so simple_pad() is fine (and
    # allows us to decrypt old values).
    aes = AES.new(aes_key, AES.MODE_ECB)

    message_bytes = message if isinstance(message, bytes) else message.encode('utf8')
    plaintext_bytes = crypto_pad(message_bytes, AES_BLOCK_SIZE, style='iso7816')
    ciphertext_bytes = aes.encrypt(plaintext_bytes)
    b64ciphertext_bytes = b64encode(ciphertext_bytes)
    return b64ciphertext_bytes.decode('ascii')

def b64_aes_decrypt(message):
    """
    Base64-decode and AES-decrypt ASCII `message`.

    Uses Django SECRET_KEY as AES key.

    >>> settings.SECRET_KEY = 'xyzzy'
    >>> decrypted = b64_aes_decrypt('Vh2Tmlnr5+out2PQDefkuS9+9GtIsiEX8YBA0T/V87I=')
    >>> decrypted == 'Around you is a forest.'
    True

    """
    if isinstance(settings.SECRET_KEY, bytes):
        secret_key_bytes = settings.SECRET_KEY
    else:
        secret_key_bytes = settings.SECRET_KEY.encode('ascii')
    aes_key = simple_pad(secret_key_bytes, AES_BLOCK_SIZE)[:AES_KEY_MAX_LEN]
    aes = AES.new(aes_key, AES.MODE_ECB)

    ciphertext_bytes = b64decode(message)
    padded_plaintext_bytes = aes.decrypt(ciphertext_bytes)
    plaintext_bytes = unpad(padded_plaintext_bytes)
    return plaintext_bytes.decode('utf8')

def unpad(bytestring):
    """
    Unpad will remove padding from the right of a string that has been
    padded by ``simple_pad()`` or by ``crypto_pad()``.

    ``crypto_pad()`` uses `ISO 7816-4 <iso7816>`_, which will result in
    the string ending in a byte with a decimal value of either 0 or 128
    (hex 0x00 or 0x80).

     ``simple_pad()`` pads with PAD_CHAR (an ASCII space character) if
     the original length is not a multiple of AES_BLOCK_SIZE, otherwise
     it does not pad.

     If ``bytestring`` ends in 0x00 or 0x80, it could have been padded
     with ``crypto_pad()``, or it could padded with ``simple_pad()``
     and whose last character is multi-byte non-ASCII UTF-8 character
     whose last byte is 0x00 or 0x80 (e.g. b'0xC3\0x80', "À" (capital
     A-grave)). Because the second possibility is far less likely than
     the first, ``unpad()`` uses ``crypto_unpad()`` in this case.

    .. _iso7816: https://en.wikipedia.org/wiki/Padding_(cryptography)#ISO/IEC_7816-4
    """
    if bord(bytestring[-1]) in (0, 128):
        return crypto_unpad(bytestring, AES_BLOCK_SIZE, style='iso7816')
    return bytestring.rstrip(PAD_CHAR)

def pformat_json(data):
    """
    Pretty-formats `data` for readability, or returns the original
    value if it can't be parsed as JSON.

    :return: A 2-space-indented string with sorted keys.
    """
    if data is None:
        return ''
    try:
        json_data = json.loads(data) if isinstance(data, str) else data
        return json.dumps(json_data, indent=2, sort_keys=True)
    except ValueError:
        return data
<commit_msg>Support loading bytestring data<commit_after>import json
from base64 import b64decode, b64encode

from django.conf import settings

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad as crypto_pad
from Crypto.Util.Padding import unpad as crypto_unpad
from Crypto.Util.py3compat import bord

AES_BLOCK_SIZE = 16
AES_KEY_MAX_LEN = 32  # AES key must be either 16, 24, or 32 bytes long
PAD_CHAR = b' '

def simple_pad(bytestring, block_size, char=PAD_CHAR):
    """
    Pad `bytestring` to a multiple of `block_size` in length by appending
    `char`. `char` defaults to space.

    >>> padded = simple_pad(b'xyzzy', 8, b'*')
    >>> padded == b'xyzzy***'
    True

    """
    assert isinstance(bytestring, bytes)
    padding = ((block_size - len(bytestring)) % block_size) * char
    return bytestring + padding

def b64_aes_encrypt(message):
    """
    AES-encrypt and base64-encode `message`.

    Uses Django SECRET_KEY as AES key.

    >>> settings.SECRET_KEY = 'xyzzy'
    >>> encrypted = b64_aes_encrypt('Around you is a forest.')
    >>> encrypted == 'Vh2Tmlnr5+out2PQDefkudZ2frfze5onsAlUGTLv3Oc='
    True

    """
    if isinstance(settings.SECRET_KEY, bytes):
        secret_key_bytes = settings.SECRET_KEY
    else:
        secret_key_bytes = settings.SECRET_KEY.encode('ascii')
    aes_key = simple_pad(secret_key_bytes, AES_BLOCK_SIZE)[:AES_KEY_MAX_LEN]
    # We never need to unpad the key, so simple_pad() is fine (and
    # allows us to decrypt old values).
    aes = AES.new(aes_key, AES.MODE_ECB)

    message_bytes = message if isinstance(message, bytes) else message.encode('utf8')
    plaintext_bytes = crypto_pad(message_bytes, AES_BLOCK_SIZE, style='iso7816')
    ciphertext_bytes = aes.encrypt(plaintext_bytes)
    b64ciphertext_bytes = b64encode(ciphertext_bytes)
    return b64ciphertext_bytes.decode('ascii')

def b64_aes_decrypt(message):
    """
    Base64-decode and AES-decrypt ASCII `message`.

    Uses Django SECRET_KEY as AES key.

    >>> settings.SECRET_KEY = 'xyzzy'
    >>> decrypted = b64_aes_decrypt('Vh2Tmlnr5+out2PQDefkuS9+9GtIsiEX8YBA0T/V87I=')
    >>> decrypted == 'Around you is a forest.'
    True

    """
    if isinstance(settings.SECRET_KEY, bytes):
        secret_key_bytes = settings.SECRET_KEY
    else:
        secret_key_bytes = settings.SECRET_KEY.encode('ascii')
    aes_key = simple_pad(secret_key_bytes, AES_BLOCK_SIZE)[:AES_KEY_MAX_LEN]
    aes = AES.new(aes_key, AES.MODE_ECB)

    ciphertext_bytes = b64decode(message)
    padded_plaintext_bytes = aes.decrypt(ciphertext_bytes)
    plaintext_bytes = unpad(padded_plaintext_bytes)
    return plaintext_bytes.decode('utf8')

def unpad(bytestring):
    """
    Unpad will remove padding from the right of a string that has been
    padded by ``simple_pad()`` or by ``crypto_pad()``.

    ``crypto_pad()`` uses `ISO 7816-4 <iso7816>`_, which will result in
    the string ending in a byte with a decimal value of either 0 or 128
    (hex 0x00 or 0x80).

     ``simple_pad()`` pads with PAD_CHAR (an ASCII space character) if
     the original length is not a multiple of AES_BLOCK_SIZE, otherwise
     it does not pad.

     If ``bytestring`` ends in 0x00 or 0x80, it could have been padded
     with ``crypto_pad()``, or it could padded with ``simple_pad()``
     and whose last character is multi-byte non-ASCII UTF-8 character
     whose last byte is 0x00 or 0x80 (e.g. b'0xC3\0x80', "À" (capital
     A-grave)). Because the second possibility is far less likely than
     the first, ``unpad()`` uses ``crypto_unpad()`` in this case.

    .. _iso7816: https://en.wikipedia.org/wiki/Padding_(cryptography)#ISO/IEC_7816-4
    """
    if bord(bytestring[-1]) in (0, 128):
        return crypto_unpad(bytestring, AES_BLOCK_SIZE, style='iso7816')
    return bytestring.rstrip(PAD_CHAR)

def pformat_json(data):
    """
    Pretty-formats `data` for readability, or returns the original
    value if it can't be parsed as JSON.

    :return: A 2-space-indented string with sorted keys.
    """
    if data is None:
        return ''
    try:
        json_data = json.loads(data) if isinstance(data, (str, bytes)) else data
        return json.dumps(json_data, indent=2, sort_keys=True)
    except (TypeError, ValueError):
        return data
<|endoftext|>


<commit_before>"""
exttargets.py - Implements extended targets like $account:xyz, $oper, etc.
"""

from pylinkirc import world
from pylinkirc.log import log

def bind(func):
    """
    Binds an exttarget with the given name.
    """
    world.exttarget_handlers[func.__name__] = func
    return func

@bind
def account(irc, host, uid):
    """
    $account exttarget handler. The following forms are supported, with groups separated by a
    literal colon. Account matching is case insensitive, while network name matching IS case
    sensitive.

    $account -> Returns True (a match) if the target is registered.
    $account:accountname -> Returns True if the target's account name matches the one given, and the
    target is connected to the local network..
    $account:accountname:netname -> Returns True if both the target's account name and origin
    network name match the ones given.
    $account:*:netname -> Matches all logged in users on the given network.
    """
    userobj = irc.users[uid]
    homenet = irc.name
    if hasattr(userobj, 'remote'):
        # User is a PyLink Relay pseudoclient. Use their real services account on their
        # origin network.
        homenet, realuid = userobj.remote
        log.debug('(%s) exttargets.account: Changing UID of relay client %s to %s/%s', irc.name,
                  uid, homenet, realuid)
        try:
            userobj = world.networkobjects[homenet].users[realuid]
        except KeyError:  # User lookup failed. Bail and return False.
            log.exception('(%s) exttargets.account: KeyError finding %s/%s:', irc.name,
                          homenet, realuid)
            return False

    slogin = irc.toLower(userobj.services_account)

    # Split the given exttarget host into parts, so we know how many to look for.
    groups = list(map(irc.toLower, host.split(':')))
    log.debug('(%s) exttargets.account: groups to match: %s', irc.name, groups)

    if len(groups) == 1:
        # First scenario. Return True if user is logged in.
        return bool(slogin)
    elif len(groups) == 2:
        # Second scenario. Return True if the user's account matches the one given.
        return slogin == groups[1] and homenet == irc.name
    else:
        # Third or fourth scenario. If there are more than 3 groups, the rest are ignored.
        # In other words: Return True if the user is logged in, the query matches either '*' or the
        # user's login, and the user is connected on the network requested.
        return slogin and (groups[1] in ('*', slogin)) and (homenet == groups[2])

@bind
def ircop(irc, host, uid):
    """
    $ircop exttarget handler. The following forms are supported, with groups separated by a
    literal colon. Oper types are matched case insensitively.

    $ircop -> Returns True (a match) if the target is opered.
    $ircop:*admin* -> Returns True if the target's is opered and their opertype matches the glob
    given.
    """
    groups = host.split(':')
    log.debug('(%s) exttargets.ircop: groups to match: %s', irc.name, groups)

    if len(groups) == 1:
        # 1st scenario.
        return irc.isOper(uid, allowAuthed=False)
    else:
        # 2nd scenario. Use matchHost (ircmatch) to match the opertype glob to the opertype.
        return irc.matchHost(groups[1], irc.users[uid].opertype)

@bind
def server(irc, host, uid):
    """
    $server exttarget handler. The following forms are supported, with groups separated by a
    literal colon. Server names are matched case insensitively, but SIDs ARE case sensitive.

    $server:server.name -> Returns True (a match) if the target is connected on the given server.
    $server:server.glob -> Returns True (a match) if the target is connected on a server matching the glob.
    $server:1XY -> Returns True if the target's is connected on the server with the given SID.
    """
    groups = host.split(':')
    log.debug('(%s) exttargets.server: groups to match: %s', irc.name, groups)

    if len(groups) >= 2:
        sid = irc.getServer(uid)
        query = groups[1]
        # Return True if the SID matches the query or the server's name glob matches it.
        return sid == query or irc.matchHost(query, irc.getFriendlyName(sid))
    # $server alone is invalid. Don't match anything.
    return False

@bind
def channel(irc, host, uid):
    """
    $channel exttarget handler. The following forms are supported, with groups separated by a
    literal colon. Channel names are matched case insensitively.

    $channel:#channel -> Returns True if the target is in the given channel.
    $channel:#channel:op -> Returns True if the target is in the given channel, and is opped.
    Any other supported prefix (owner, admin, op, halfop, voice) can be given, but only one at a
    time.
    """
    groups = host.split(':')
    log.debug('(%s) exttargets.channel: groups to match: %s', irc.name, groups)
    try:
        channel = groups[1]
    except IndexError:  # No channel given, abort.
        return False

    if len(groups) == 2:
        # Just #channel was given as query
        return uid in irc.channels[channel].users
    elif len(groups) >= 3:
        # For things like #channel:op, check if the query is in the user's prefix modes.
        return groups[2].lower() in irc.channels[channel].getPrefixModes(uid)

@bind
def pylinkacc(irc, host, uid):
    """
    $pylinkacc (PyLink account) exttarget handler. The following forms are supported, with groups
    separated by a literal colon. Account matching is case insensitive.

    $pylinkacc -> Returns True if the target is logged in to PyLink.
    $pylinkacc:accountname -> Returns True if the target's PyLink login matches the one given.
    """
    login = irc.toLower(irc.users[uid].identified)
    groups = list(map(irc.toLower, host.split(':')))
    log.debug('(%s) exttargets.pylinkacc: groups to match: %s', irc.name, groups)

    if len(groups) == 1:
        # First scenario. Return True if user is logged in.
        return bool(login)
    elif len(groups) == 2:
        # Second scenario. Return True if the user's login matches the one given.
        return login == groups[1]
<commit_msg>exttargets: verify target is in channel before calling getPrefixModes<commit_after>"""
exttargets.py - Implements extended targets like $account:xyz, $oper, etc.
"""

from pylinkirc import world
from pylinkirc.log import log

def bind(func):
    """
    Binds an exttarget with the given name.
    """
    world.exttarget_handlers[func.__name__] = func
    return func

@bind
def account(irc, host, uid):
    """
    $account exttarget handler. The following forms are supported, with groups separated by a
    literal colon. Account matching is case insensitive, while network name matching IS case
    sensitive.

    $account -> Returns True (a match) if the target is registered.
    $account:accountname -> Returns True if the target's account name matches the one given, and the
    target is connected to the local network..
    $account:accountname:netname -> Returns True if both the target's account name and origin
    network name match the ones given.
    $account:*:netname -> Matches all logged in users on the given network.
    """
    userobj = irc.users[uid]
    homenet = irc.name
    if hasattr(userobj, 'remote'):
        # User is a PyLink Relay pseudoclient. Use their real services account on their
        # origin network.
        homenet, realuid = userobj.remote
        log.debug('(%s) exttargets.account: Changing UID of relay client %s to %s/%s', irc.name,
                  uid, homenet, realuid)
        try:
            userobj = world.networkobjects[homenet].users[realuid]
        except KeyError:  # User lookup failed. Bail and return False.
            log.exception('(%s) exttargets.account: KeyError finding %s/%s:', irc.name,
                          homenet, realuid)
            return False

    slogin = irc.toLower(userobj.services_account)

    # Split the given exttarget host into parts, so we know how many to look for.
    groups = list(map(irc.toLower, host.split(':')))
    log.debug('(%s) exttargets.account: groups to match: %s', irc.name, groups)

    if len(groups) == 1:
        # First scenario. Return True if user is logged in.
        return bool(slogin)
    elif len(groups) == 2:
        # Second scenario. Return True if the user's account matches the one given.
        return slogin == groups[1] and homenet == irc.name
    else:
        # Third or fourth scenario. If there are more than 3 groups, the rest are ignored.
        # In other words: Return True if the user is logged in, the query matches either '*' or the
        # user's login, and the user is connected on the network requested.
        return slogin and (groups[1] in ('*', slogin)) and (homenet == groups[2])

@bind
def ircop(irc, host, uid):
    """
    $ircop exttarget handler. The following forms are supported, with groups separated by a
    literal colon. Oper types are matched case insensitively.

    $ircop -> Returns True (a match) if the target is opered.
    $ircop:*admin* -> Returns True if the target's is opered and their opertype matches the glob
    given.
    """
    groups = host.split(':')
    log.debug('(%s) exttargets.ircop: groups to match: %s', irc.name, groups)

    if len(groups) == 1:
        # 1st scenario.
        return irc.isOper(uid, allowAuthed=False)
    else:
        # 2nd scenario. Use matchHost (ircmatch) to match the opertype glob to the opertype.
        return irc.matchHost(groups[1], irc.users[uid].opertype)

@bind
def server(irc, host, uid):
    """
    $server exttarget handler. The following forms are supported, with groups separated by a
    literal colon. Server names are matched case insensitively, but SIDs ARE case sensitive.

    $server:server.name -> Returns True (a match) if the target is connected on the given server.
    $server:server.glob -> Returns True (a match) if the target is connected on a server matching the glob.
    $server:1XY -> Returns True if the target's is connected on the server with the given SID.
    """
    groups = host.split(':')
    log.debug('(%s) exttargets.server: groups to match: %s', irc.name, groups)

    if len(groups) >= 2:
        sid = irc.getServer(uid)
        query = groups[1]
        # Return True if the SID matches the query or the server's name glob matches it.
        return sid == query or irc.matchHost(query, irc.getFriendlyName(sid))
    # $server alone is invalid. Don't match anything.
    return False

@bind
def channel(irc, host, uid):
    """
    $channel exttarget handler. The following forms are supported, with groups separated by a
    literal colon. Channel names are matched case insensitively.

    $channel:#channel -> Returns True if the target is in the given channel.
    $channel:#channel:op -> Returns True if the target is in the given channel, and is opped.
    Any other supported prefix (owner, admin, op, halfop, voice) can be given, but only one at a
    time.
    """
    groups = host.split(':')
    log.debug('(%s) exttargets.channel: groups to match: %s', irc.name, groups)
    try:
        channel = groups[1]
    except IndexError:  # No channel given, abort.
        return False

    if len(groups) == 2:
        # Just #channel was given as query
        return uid in irc.channels[channel].users
    elif len(groups) >= 3:
        # For things like #channel:op, check if the query is in the user's prefix modes.
        return (uid in irc.channels[channel].users) and (groups[2].lower() in irc.channels[channel].getPrefixModes(uid))

@bind
def pylinkacc(irc, host, uid):
    """
    $pylinkacc (PyLink account) exttarget handler. The following forms are supported, with groups
    separated by a literal colon. Account matching is case insensitive.

    $pylinkacc -> Returns True if the target is logged in to PyLink.
    $pylinkacc:accountname -> Returns True if the target's PyLink login matches the one given.
    """
    login = irc.toLower(irc.users[uid].identified)
    groups = list(map(irc.toLower, host.split(':')))
    log.debug('(%s) exttargets.pylinkacc: groups to match: %s', irc.name, groups)

    if len(groups) == 1:
        # First scenario. Return True if user is logged in.
        return bool(login)
    elif len(groups) == 2:
        # Second scenario. Return True if the user's login matches the one given.
        return login == groups[1]
<|endoftext|>


<commit_before>"""Tests for the API"""
# pylint: disable=no-self-use
from collections import OrderedDict

from django.core.urlresolvers import reverse
from rest_framework import status
from rest_framework.test import APITestCase

from courses.factories import ProgramFactory, CourseFactory
from courses.serializers import ProgramSerializer
from dashboard.factories import ProgramEnrollmentFactory
from profiles.factories import UserFactory
from search.base import ESTestCase

class ProgramTests(ESTestCase):
    """Tests for the Program API"""
    def test_lists_live_programs(self):
        """Live programs should show up"""
        prog = ProgramFactory.create(live=True)

        resp = self.client.get(reverse('programs-list'))

        assert len(resp.json) == 1
        assert prog.title == resp.json[0]['title']

    def test_doesnt_list_unlive_programs(self):
        """Not-live programs should NOT show up"""
        ProgramFactory.create(live=False)

        resp = self.client.get(reverse('programs-list'))

        assert len(resp.json) == 0

class CourseTests(ESTestCase):
    """Tests for the Course API"""
    def test_list_course_if_program_live(self):
        """
        If the course belongs to a live program, show it.
        """
        course = CourseFactory.create(program__live=True)

        resp = self.client.get(reverse('course-list'))

        assert len(resp.json) == 1
        assert resp.json[0]['id'] == course.id

    def test_doesnt_list_courses_from_unlive_programs(self):
        """
        If the course belongs to a non-live program, hide it.
        """
        CourseFactory.create(program__live=False)

        resp = self.client.get(reverse('course-list'))

        assert len(resp.json) == 0

class ProgramEnrollmentTests(ESTestCase, APITestCase):
    """Tests for the ProgramEnrollment API"""

    @classmethod
    def setUpTestData(cls):
        super(ProgramEnrollmentTests, cls).setUpTestData()

        cls.user1 = UserFactory.create()
        cls.user2 = UserFactory.create()
        cls.program1 = ProgramFactory.create(live=True)
        cls.program2 = ProgramFactory.create(live=True)
        cls.program3 = ProgramFactory.create(live=True)
        for program in (cls.program1, cls.program2,):
            ProgramEnrollmentFactory(
                user=cls.user1,
                program=program,
            )
        cls.url = reverse('user_program_enrollment')

    def test_anonymous(self):
        """Anonymous user cannot access the endpoint"""
        resp = self.client.get(self.url)
        assert resp.status_code == status.HTTP_403_FORBIDDEN

    def test_no_enrollments(self):
        """Requests for a user with no program enrollments result in an empty list"""
        self.client.force_login(self.user2)
        resp = self.client.get(self.url)
        assert resp.status_code == status.HTTP_200_OK
        assert resp.data == []

    def test_enrollments(self):
        """Only the programs where the user is enrolled in are returned"""
        self.client.force_login(self.user1)
        resp = self.client.get(self.url)
        assert resp.status_code == status.HTTP_200_OK
        expected_data = sorted(
            [
             OrderedDict(sorted(program.data.items(), key=lambda t: t[0]))
             for program in (ProgramSerializer(self.program1), ProgramSerializer(self.program2),)
            ],
            key=lambda x: x['title'],
        )
        assert resp.data == expected_data
<commit_msg>fixed linting<commit_after>"""Tests for the API"""
# pylint: disable=no-self-use
from collections import OrderedDict

from django.core.urlresolvers import reverse
from rest_framework import status
from rest_framework.test import APITestCase

from courses.factories import ProgramFactory, CourseFactory
from courses.serializers import ProgramSerializer
from dashboard.factories import ProgramEnrollmentFactory
from profiles.factories import UserFactory
from search.base import ESTestCase

class ProgramTests(ESTestCase):
    """Tests for the Program API"""
    def test_lists_live_programs(self):
        """Live programs should show up"""
        prog = ProgramFactory.create(live=True)

        resp = self.client.get(reverse('programs-list'))

        assert len(resp.json) == 1
        assert prog.title == resp.json[0]['title']

    def test_doesnt_list_unlive_programs(self):
        """Not-live programs should NOT show up"""
        ProgramFactory.create(live=False)

        resp = self.client.get(reverse('programs-list'))

        assert len(resp.json) == 0

class CourseTests(ESTestCase):
    """Tests for the Course API"""
    def test_list_course_if_program_live(self):
        """
        If the course belongs to a live program, show it.
        """
        course = CourseFactory.create(program__live=True)

        resp = self.client.get(reverse('course-list'))

        assert len(resp.json) == 1
        assert resp.json[0]['id'] == course.id

    def test_doesnt_list_courses_from_unlive_programs(self):
        """
        If the course belongs to a non-live program, hide it.
        """
        CourseFactory.create(program__live=False)

        resp = self.client.get(reverse('course-list'))

        assert len(resp.json) == 0

class ProgramEnrollmentTests(ESTestCase, APITestCase):
    """Tests for the ProgramEnrollment API"""

    @classmethod
    def setUpTestData(cls):
        super(ProgramEnrollmentTests, cls).setUpTestData()

        cls.user1 = UserFactory.create()
        cls.user2 = UserFactory.create()
        cls.program1 = ProgramFactory.create(live=True)
        cls.program2 = ProgramFactory.create(live=True)
        cls.program3 = ProgramFactory.create(live=True)
        for program in (cls.program1, cls.program2,):
            ProgramEnrollmentFactory(
                user=cls.user1,
                program=program,
            )
        cls.url = reverse('user_program_enrollment')

    def test_anonymous(self):
        """Anonymous user cannot access the endpoint"""
        resp = self.client.get(self.url)
        assert resp.status_code == status.HTTP_403_FORBIDDEN

    def test_no_enrollments(self):
        """Requests for a user with no program enrollments result in an empty list"""
        self.client.force_login(self.user2)
        resp = self.client.get(self.url)
        assert resp.status_code == status.HTTP_200_OK
        assert resp.data == []

    def test_enrollments(self):
        """Only the programs where the user is enrolled in are returned"""
        self.client.force_login(self.user1)
        resp = self.client.get(self.url)
        assert resp.status_code == status.HTTP_200_OK
        expected_data = sorted(
            [
                OrderedDict(sorted(program.data.items(), key=lambda t: t[0]))
                for program in (ProgramSerializer(self.program1), ProgramSerializer(self.program2),)
            ],
            key=lambda x: x['title'],
        )
        assert resp.data == expected_data
<|endoftext|>


<commit_before># Copyright 2017 Google Inc.
#
# 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.
"""Tests to make sure end-to-end camera inference latency is reasonable."""

import unittest

from picamera import PiCamera
from time import time

from aiy.vision.inference import CameraInference
from aiy.vision.models import dish_classification
from aiy.vision.models import face_detection
from aiy.vision.models import image_classification
from aiy.vision.models import object_detection

class LatencyTest(unittest.TestCase):

    def setUp(self):
        self.camera = PiCamera(sensor_mode=4, framerate=30)
        self.camera.start_preview()

        # Number of frames to run inference on.
        self.num_frames = 30

    def tearDown(self):
        self.camera.stop_preview()
        self.camera.close()

    def benchmarkModel(self, model, interpret):
        """Benchmarks model and reports end-to-end + on bonnet latency.

        Args:
          model: ModelDescriptor.
          interpret: function object on how to interpret inference result.

        Returns:
          (avg_end_to_end, avg_bonnet) latency tuple in ms.
        """
        sum_bonnet = 0
        sum_overall = 0
        with CameraInference(model) as inference:
            overall_start = time()
            for i, result in enumerate(inference.run()):
                if i == self.num_frames:
                    break
                interpret(result)
                sum_bonnet += result.duration_ms
            overall_end = time()
        sum_overall = (overall_end - overall_start) * 1000
        return (sum_overall / self.num_frames, sum_bonnet / self.num_frames)

    def assertLatency(self, measured, expected, variation=0.2):
        lower = (1 - variation) * expected
        upper = (1 + variation) * expected
        if measured > upper or measured < lower:
            raise AssertionError(
                'Measured %f latency is outside of [%f, %f] interval' %
                (measured, lower, upper))

    def testFaceDetectionLatency(self):
        avg_end_to_end, avg_bonnet = self.benchmarkModel(face_detection.model(),
                                                         face_detection.get_faces)
        # Latency depends on number of faces in the scene, which is
        # unpredictable when the test runs. Setting a larger variation value
        # here to accommodate this.
        self.assertLatency(avg_bonnet, 76.0, variation=0.6)
        self.assertLatency(avg_end_to_end, 91.0, variation=0.6)

    def testObjectDetectionLatency(self):
        avg_end_to_end, avg_bonnet = self.benchmarkModel(
            object_detection.model(), object_detection.get_objects)
        self.assertLatency(avg_bonnet, 36.0)
        self.assertLatency(avg_end_to_end, 153.0)

    def testImageClassificationMobilenetLatency(self):
        avg_end_to_end, avg_bonnet = self.benchmarkModel(
            image_classification.model(image_classification.MOBILENET),
            image_classification.get_classes)
        self.assertLatency(avg_bonnet, 42.0)
        self.assertLatency(avg_end_to_end, 70.0, 0.3)

    def testImageClassificationSqueezenetLatency(self):
        avg_end_to_end, avg_bonnet = self.benchmarkModel(
            image_classification.model(image_classification.SQUEEZENET),
            image_classification.get_classes)
        self.assertLatency(avg_bonnet, 183.0)
        self.assertLatency(avg_end_to_end, 202.0)

    def testDishClassificationLatency(self):
        avg_end_to_end, avg_bonnet = self.benchmarkModel(
            dish_classification.model(), dish_classification.get_classes)
        self.assertLatency(avg_bonnet, 304.0)
        self.assertLatency(avg_end_to_end, 328.0)

if __name__ == '__main__':
    unittest.main()
<commit_msg>Cleaning up latency test.<commit_after># Copyright 2017 Google Inc.
#
# 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.
"""Tests to make sure end-to-end camera inference latency is reasonable."""

import time
import unittest

from picamera import PiCamera

from aiy.vision.inference import CameraInference
from aiy.vision.models import dish_classification
from aiy.vision.models import face_detection
from aiy.vision.models import image_classification
from aiy.vision.models import object_detection

class LatencyTest(unittest.TestCase):

    def benchmarkModel(self, model, interpret, num_frames=30):
        """Benchmarks model and reports end-to-end + on bonnet latency.

        Args:
          model: ModelDescriptor.
          interpret: function object on how to interpret inference result.
          num_frames: number of frames to run inference on.

        Returns:
          (avg_end_to_end, avg_bonnet) latency tuple in ms.
        """
        with PiCamera(sensor_mode=4, framerate=30), CameraInference(model) as inference:
            sum_bonnet_ms = 0
            start = time.monotonic()
            for result in inference.run(num_frames):
                interpret(result)
                sum_bonnet_ms += result.duration_ms
            sum_overall_ms = (time.monotonic() - start) * 1000
            return (sum_overall_ms / num_frames, sum_bonnet_ms / num_frames)

    def assertLatency(self, measured, expected, variation=0.2):
        lower = (1 - variation) * expected
        upper = (1 + variation) * expected
        if measured > upper or measured < lower:
            raise AssertionError(
                'Measured %f latency is outside of [%f, %f] interval' % (measured, lower, upper))

    def testFaceDetectionLatency(self):
        avg_end_to_end, avg_bonnet = self.benchmarkModel(
            face_detection.model(), face_detection.get_faces)
        # Latency depends on number of faces in the scene, which is
        # unpredictable when the test runs. Setting a larger variation value
        # here to accommodate this.
        self.assertLatency(avg_bonnet, 76.0, variation=0.6)
        self.assertLatency(avg_end_to_end, 91.0, variation=0.6)

    def testObjectDetectionLatency(self):
        avg_end_to_end, avg_bonnet = self.benchmarkModel(
            object_detection.model(), object_detection.get_objects)
        self.assertLatency(avg_bonnet, 36.0)
        self.assertLatency(avg_end_to_end, 153.0)

    def testImageClassificationMobilenetLatency(self):
        avg_end_to_end, avg_bonnet = self.benchmarkModel(
            image_classification.model(image_classification.MOBILENET),
            image_classification.get_classes)
        self.assertLatency(avg_bonnet, 42.0)
        self.assertLatency(avg_end_to_end, 70.0, 0.3)

    def testImageClassificationSqueezenetLatency(self):
        avg_end_to_end, avg_bonnet = self.benchmarkModel(
            image_classification.model(image_classification.SQUEEZENET),
            image_classification.get_classes)
        self.assertLatency(avg_bonnet, 183.0)
        self.assertLatency(avg_end_to_end, 202.0)

    def testDishClassificationLatency(self):
        avg_end_to_end, avg_bonnet = self.benchmarkModel(
            dish_classification.model(), dish_classification.get_classes)
        self.assertLatency(avg_bonnet, 304.0)
        self.assertLatency(avg_end_to_end, 328.0)

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


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright (C) 2018 Visiotech All Rights Reserved
#    $Jesus Garcia Manzanas <jgmanzanas@visiotechsecurity.com>$
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import models
from openerp.addons.connector.event import on_record_create, on_record_write, \
    on_record_unlink
from openerp.addons.connector.queue.job import job
from .utils import _get_exporter
from ..backend import middleware
from openerp.addons.connector.unit.synchronizer import Exporter
from ..unit.backend_adapter import GenericAdapter

@middleware
class OrderExporter(Exporter):

    _model_name = ['sale.order']

    def update(self, binding_id, mode):
        order = self.model.browse(binding_id)
        state = order.state
        if state in ('shipping_except', 'invoice_except'):
            state = 'done'
        vals = {"odoo_id": order.id,
                "name": order.name,
                "state": state,
                "partner_id": order.partner_id.id,
                "amount_total": order.amount_total,
                "date_order": order.date_order,
                "amount_untaxed": order.amount_untaxed,
                "client_order_ref": order.client_order_ref,
                'shipping_street': order.partner_shipping_id.street,
                'shipping_zip': order.partner_shipping_id.zip,
                'shipping_city': order.partner_shipping_id.city,
                'shipping_state': order.partner_shipping_id.state_id.name,
                'shipping_country': order.partner_shipping_id.country_id.name,
                'delivery_type': order.delivery_type,
        }
        if mode == "insert":
            return self.backend_adapter.insert(vals)
        else:
            return self.backend_adapter.update(binding_id, vals)

    def delete(self, binding_id):
        return self.backend_adapter.remove(binding_id)

@middleware
class OrderAdapter(GenericAdapter):
    _model_name = 'sale.order'
    _middleware_model = 'order'

@on_record_create(model_names='sale.order')
def delay_export_order_create(session, model_name, record_id, vals):
    order = session.env[model_name].browse(record_id)
    if order.partner_id.web or order.partner_id.commercial_partner_id.web:
        export_order.delay(session, model_name, record_id, priority=2, eta=80)

@on_record_write(model_names='sale.order')
def delay_export_order_write(session, model_name, record_id, vals):
    order = session.env[model_name].browse(record_id)
    #He cogido order_line porque no entra amount_total ni amount_untaxed en el write
    up_fields = ["name", "state", "partner_id", "date_order", "client_order_ref",
                 "order_line", "partner_shipping_id", "delivery_type"]
    if order.partner_id.web or order.partner_id.commercial_partner_id.web:
        job = session.env['queue.job'].search([('func_string', 'like', '%, ' + str(order.id) + ')%'),
                                               ('model_name', '=', model_name)], order='date_created desc', limit=1)
        if 'state' in vals.keys() and vals['state'] == 'cancel':
            unlink_order.delay(session, model_name, record_id, priority=7, eta=80)
        elif 'state' in vals.keys() and vals['state'] in ('draft', 'reserve') and job.name and 'unlink' in job.name:
            export_order.delay(session, model_name, record_id, priority=2, eta=80)
            for line in order.order_line:
                export_orderproduct.delay(session, 'sale.order.line', line.id, priority=2, eta=120)
        elif order.state in ('draft', 'reserve', 'progress', 'done', 'shipping_except', 'invoice_except'):
            for field in up_fields:
                if field in vals:
                    update_order.delay(session, model_name, record_id, priority=5, eta=120)
                    break

@on_record_unlink(model_names='sale.order')
def delay_export_order_unlink(session, model_name, record_id):
    order = session.env[model_name].browse(record_id)
    if order.partner_id.web or order.partner_id.commercial_partner_id.web:
        unlink_order.delay(session, model_name, record_id, priority=7, eta=180)

@job(retry_pattern={1: 10 * 60, 2: 20 * 60, 3: 30 * 60, 4: 40 * 60,
                    5: 50 * 60})
def export_order(session, model_name, record_id):
    order_exporter = _get_exporter(session, model_name, record_id,
                                   OrderExporter)
    return order_exporter.update(record_id, "insert")

@job(retry_pattern={1: 10 * 60, 2: 20 * 60, 3: 30 * 60, 4: 40 * 60,
                    5: 50 * 60})
def update_order(session, model_name, record_id):
    order_exporter = _get_exporter(session, model_name, record_id,
                                   OrderExporter)
    return order_exporter.update(record_id, "update")

@job(retry_pattern={1: 10 * 60, 2: 20 * 60, 3: 30 * 60, 4: 40 * 60,
                    5: 50 * 60})
def unlink_order(session, model_name, record_id):
    order_exporter = _get_exporter(session, model_name, record_id,
                                   OrderExporter)
    return order_exporter.delete(record_id)

@middleware
class OrderProductExporter(Exporter):

    _model_name = ['sale.order.line']

    def update(self, binding_id, mode):
        orderproduct = self.model.browse(binding_id)
        vals = {"odoo_id": orderproduct.id,
                "product_id": orderproduct.product_id.id,
                "product_qty": orderproduct.product_uom_qty,
                "price_subtotal": orderproduct.price_subtotal,
                "order_id": orderproduct.order_id.id,
                "no_rappel": orderproduct.no_rappel,
                "deposit": orderproduct.deposit,
                "pack_parent_line_id": orderproduct.pack_parent_line_id.id,
                "discount": orderproduct.discount,
        }
        if mode == "insert":
            return self.backend_adapter.insert(vals)
        else:
            return self.backend_adapter.update(binding_id, vals)

    def delete(self, binding_id):
        return self.backend_adapter.remove(binding_id)

@middleware
class OrderProductAdapter(GenericAdapter):
    _model_name = 'sale.order.line'
    _middleware_model = 'orderproduct'

@on_record_create(model_names='sale.order.line')
def delay_export_orderproduct_create(session, model_name, record_id, vals):
    orderproduct = session.env[model_name].browse(record_id)
    if orderproduct.order_id.partner_id.web or orderproduct.order_id.partner_id.commercial_partner_id.web:
        export_orderproduct.delay(session, model_name, record_id, priority=2, eta=120)

@on_record_write(model_names='sale.order.line')
def delay_export_orderproduct_write(session, model_name, record_id, vals):
    orderproduct = session.env[model_name].browse(record_id)
    up_fields = ["product_id", "product_uom_qty", "price_unit", "discount", "order_id",
                 "no_rappel", "deposit", "pack_parent_line_id"]
    if orderproduct.order_id.partner_id.web or orderproduct.order_id.partner_id.commercial_partner_id.web:
        for field in up_fields:
            if field in vals:
                update_orderproduct.delay(session, model_name, record_id, priority=5, eta=120)
                break

@on_record_unlink(model_names='sale.order.line')
def delay_export_orderproduct_unlink(session, model_name, record_id):
    orderproduct = session.env[model_name].browse(record_id)
    if orderproduct.order_id.partner_id.web or orderproduct.order_id.partner_id.commercial_partner_id.web:
        unlink_orderproduct.delay(session, model_name, record_id, priority=7, eta=180)

@job(retry_pattern={1: 10 * 60, 2: 20 * 60, 3: 30 * 60, 4: 40 * 60,
                    5: 50 * 60})
def export_orderproduct(session, model_name, record_id):
    orderproduct_exporter = _get_exporter(session, model_name, record_id,
                                          OrderProductExporter)
    return orderproduct_exporter.update(record_id, "insert")

@job(retry_pattern={1: 10 * 60, 2: 20 * 60, 3: 30 * 60, 4: 40 * 60,
                    5: 50 * 60})
def update_orderproduct(session, model_name, record_id):
    orderproduct_exporter = _get_exporter(session, model_name, record_id,
                                          OrderProductExporter)
    return orderproduct_exporter.update(record_id, "update")

@job(retry_pattern={1: 10 * 60, 2: 20 * 60, 3: 30 * 60, 4: 40 * 60,
                    5: 50 * 60})
def unlink_orderproduct(session, model_name, record_id):
    orderproduct_exporter = _get_exporter(session, model_name, record_id,
                                          OrderProductExporter)
    return orderproduct_exporter.delete(record_id)

<commit_msg>[FIX]'flask_middleware_connector': ajuste de tiempo y ajuste de consulta en pedidos<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright (C) 2018 Visiotech All Rights Reserved
#    $Jesus Garcia Manzanas <jgmanzanas@visiotechsecurity.com>$
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import models
from openerp.addons.connector.event import on_record_create, on_record_write, \
    on_record_unlink
from openerp.addons.connector.queue.job import job
from .utils import _get_exporter
from ..backend import middleware
from openerp.addons.connector.unit.synchronizer import Exporter
from ..unit.backend_adapter import GenericAdapter

@middleware
class OrderExporter(Exporter):

    _model_name = ['sale.order']

    def update(self, binding_id, mode):
        order = self.model.browse(binding_id)
        state = order.state
        if state in ('shipping_except', 'invoice_except'):
            state = 'done'
        vals = {"odoo_id": order.id,
                "name": order.name,
                "state": state,
                "partner_id": order.partner_id.id,
                "amount_total": order.amount_total,
                "date_order": order.date_order,
                "amount_untaxed": order.amount_untaxed,
                "client_order_ref": order.client_order_ref,
                'shipping_street': order.partner_shipping_id.street,
                'shipping_zip': order.partner_shipping_id.zip,
                'shipping_city': order.partner_shipping_id.city,
                'shipping_state': order.partner_shipping_id.state_id.name,
                'shipping_country': order.partner_shipping_id.country_id.name,
                'delivery_type': order.delivery_type,
        }
        if mode == "insert":
            return self.backend_adapter.insert(vals)
        else:
            return self.backend_adapter.update(binding_id, vals)

    def delete(self, binding_id):
        return self.backend_adapter.remove(binding_id)

@middleware
class OrderAdapter(GenericAdapter):
    _model_name = 'sale.order'
    _middleware_model = 'order'

@on_record_create(model_names='sale.order')
def delay_export_order_create(session, model_name, record_id, vals):
    order = session.env[model_name].browse(record_id)
    if order.partner_id.web or order.partner_id.commercial_partner_id.web:
        export_order.delay(session, model_name, record_id, priority=2, eta=80)

@on_record_write(model_names='sale.order')
def delay_export_order_write(session, model_name, record_id, vals):
    order = session.env[model_name].browse(record_id)
    #He cogido order_line porque no entra amount_total ni amount_untaxed en el write
    up_fields = ["name", "state", "partner_id", "date_order", "client_order_ref",
                 "order_line", "partner_shipping_id", "delivery_type"]
    if order.partner_id.web or order.partner_id.commercial_partner_id.web:
        job = session.env['queue.job'].search([('func_string', 'like', '%, ' + str(order.id) + ')%'),
                                               ('model_name', '=', model_name)], order='date_created desc, id desc', limit=1)
        if 'state' in vals.keys() and vals['state'] == 'cancel':
            unlink_order.delay(session, model_name, record_id, priority=7, eta=80)
        elif 'state' in vals.keys() and vals['state'] in ('draft', 'reserve') and job.name and 'unlink' in job.name:
            export_order.delay(session, model_name, record_id, priority=2, eta=80)
            for line in order.order_line:
                export_orderproduct.delay(session, 'sale.order.line', line.id, priority=2, eta=120)
        elif order.state in ('draft', 'reserve', 'progress', 'done', 'shipping_except', 'invoice_except'):
            for field in up_fields:
                if field in vals:
                    update_order.delay(session, model_name, record_id, priority=5, eta=80)
                    break

@on_record_unlink(model_names='sale.order')
def delay_export_order_unlink(session, model_name, record_id):
    order = session.env[model_name].browse(record_id)
    if order.partner_id.web or order.partner_id.commercial_partner_id.web:
        unlink_order.delay(session, model_name, record_id, priority=7, eta=180)

@job(retry_pattern={1: 10 * 60, 2: 20 * 60, 3: 30 * 60, 4: 40 * 60,
                    5: 50 * 60})
def export_order(session, model_name, record_id):
    order_exporter = _get_exporter(session, model_name, record_id,
                                   OrderExporter)
    return order_exporter.update(record_id, "insert")

@job(retry_pattern={1: 10 * 60, 2: 20 * 60, 3: 30 * 60, 4: 40 * 60,
                    5: 50 * 60})
def update_order(session, model_name, record_id):
    order_exporter = _get_exporter(session, model_name, record_id,
                                   OrderExporter)
    return order_exporter.update(record_id, "update")

@job(retry_pattern={1: 10 * 60, 2: 20 * 60, 3: 30 * 60, 4: 40 * 60,
                    5: 50 * 60})
def unlink_order(session, model_name, record_id):
    order_exporter = _get_exporter(session, model_name, record_id,
                                   OrderExporter)
    return order_exporter.delete(record_id)

@middleware
class OrderProductExporter(Exporter):

    _model_name = ['sale.order.line']

    def update(self, binding_id, mode):
        orderproduct = self.model.browse(binding_id)
        vals = {"odoo_id": orderproduct.id,
                "product_id": orderproduct.product_id.id,
                "product_qty": orderproduct.product_uom_qty,
                "price_subtotal": orderproduct.price_subtotal,
                "order_id": orderproduct.order_id.id,
                "no_rappel": orderproduct.no_rappel,
                "deposit": orderproduct.deposit,
                "pack_parent_line_id": orderproduct.pack_parent_line_id.id,
                "discount": orderproduct.discount,
        }
        if mode == "insert":
            return self.backend_adapter.insert(vals)
        else:
            return self.backend_adapter.update(binding_id, vals)

    def delete(self, binding_id):
        return self.backend_adapter.remove(binding_id)

@middleware
class OrderProductAdapter(GenericAdapter):
    _model_name = 'sale.order.line'
    _middleware_model = 'orderproduct'

@on_record_create(model_names='sale.order.line')
def delay_export_orderproduct_create(session, model_name, record_id, vals):
    orderproduct = session.env[model_name].browse(record_id)
    if orderproduct.order_id.partner_id.web or orderproduct.order_id.partner_id.commercial_partner_id.web:
        export_orderproduct.delay(session, model_name, record_id, priority=2, eta=120)

@on_record_write(model_names='sale.order.line')
def delay_export_orderproduct_write(session, model_name, record_id, vals):
    orderproduct = session.env[model_name].browse(record_id)
    up_fields = ["product_id", "product_uom_qty", "price_unit", "discount", "order_id",
                 "no_rappel", "deposit", "pack_parent_line_id"]
    if orderproduct.order_id.partner_id.web or orderproduct.order_id.partner_id.commercial_partner_id.web:
        for field in up_fields:
            if field in vals:
                update_orderproduct.delay(session, model_name, record_id, priority=5, eta=120)
                break

@on_record_unlink(model_names='sale.order.line')
def delay_export_orderproduct_unlink(session, model_name, record_id):
    orderproduct = session.env[model_name].browse(record_id)
    if orderproduct.order_id.partner_id.web or orderproduct.order_id.partner_id.commercial_partner_id.web:
        unlink_orderproduct.delay(session, model_name, record_id, priority=7, eta=180)

@job(retry_pattern={1: 10 * 60, 2: 20 * 60, 3: 30 * 60, 4: 40 * 60,
                    5: 50 * 60})
def export_orderproduct(session, model_name, record_id):
    orderproduct_exporter = _get_exporter(session, model_name, record_id,
                                          OrderProductExporter)
    return orderproduct_exporter.update(record_id, "insert")

@job(retry_pattern={1: 10 * 60, 2: 20 * 60, 3: 30 * 60, 4: 40 * 60,
                    5: 50 * 60})
def update_orderproduct(session, model_name, record_id):
    orderproduct_exporter = _get_exporter(session, model_name, record_id,
                                          OrderProductExporter)
    return orderproduct_exporter.update(record_id, "update")

@job(retry_pattern={1: 10 * 60, 2: 20 * 60, 3: 30 * 60, 4: 40 * 60,
                    5: 50 * 60})
def unlink_orderproduct(session, model_name, record_id):
    orderproduct_exporter = _get_exporter(session, model_name, record_id,
                                          OrderProductExporter)
    return orderproduct_exporter.delete(record_id)

<|endoftext|>


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

"""This script scrapes information about the student service office from the univaq website."""

import sys
sys.path.insert(0, '../')
from libs.utils import utils

student_office_url = "http://www.univaq.it/section.php?id=607"

def scrape_student_office(url=student_office_url):
    """Get info about the student service office"""

    first_row = utils.get_soup_from_url(url).find(string="AREA SCIENTIFICA")\
                .parent.parent.find_next_sibling().find("tr")

    address = first_row.find(class_="address_table_description").text
    phone = first_row.find_next_sibling().find(class_="address_table_description").text
    email = first_row.find_next_sibling().find_next_sibling()\
            .find(class_="address_table_description").text
    hours = first_row.find_next_sibling().find_next_sibling().find_next_sibling()\
            .find(class_="address_table_description").text.replace('\n', '')\
            .replace("13", "13, ")

    scraped_info = {
        "indirizzo": address,
        "telefono": phone,
        "e-mail": email,
        "orari": hours
    }

    utils.write_json(scraped_info, "../json/student_office.json")

if __name__ == "__main__":
    scrape_student_office()
<commit_msg>Linted code<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""This script scrapes information about the student service office from the univaq website."""

import sys
sys.path.insert(0, '../')
from libs.utils import utils

STUDENT_OFFICE_URL = "http://www.univaq.it/section.php?id=607"

def scrape_student_office(url=STUDENT_OFFICE_URL):
    """Get info about the student service office"""

    first_row = utils.get_soup_from_url(url).find(string="AREA SCIENTIFICA")\
                .parent.parent.find_next_sibling().find("tr")

    address = first_row.find(class_="address_table_description").text
    phone = first_row.find_next_sibling().find(class_="address_table_description").text
    email = first_row.find_next_sibling().find_next_sibling()\
            .find(class_="address_table_description").text
    hours = first_row.find_next_sibling().find_next_sibling().find_next_sibling()\
            .find(class_="address_table_description").text.replace('\n', '')\
            .replace("13", "13, ")

    scraped_info = {
        "indirizzo": address,
        "telefono": phone,
        "e-mail": email,
        "orari": hours
    }

    utils.write_json(scraped_info, "../json/student_office.json")

if __name__ == "__main__":
    scrape_student_office()
<|endoftext|>