Exemple #1
0
    def validate(definition: SchemaDefinition):
        try:
            definition.validate()
        except ValidationError as e:
            return SymlServiceResponse(
                data=dict(
                    message=e.message,
                    validator=e.validator,
                    validator_value=e.validator_value,
                    absolute_path=list(e.absolute_path),
                    instance=e.instance,
                ),
                errors=[
                    dict(
                        message="validation failed ${file}",
                        file=definition.path
                    )
                ]
            )

        return SymlServiceResponse(
            data={'status': 'ok'},
            info=[
                dict(message="validated ${file}", file=definition.path)
            ]
        )
Exemple #2
0
    async def cmd_alias(self, cmd: SymlServiceCommand[ProfileSetAlias]):

        profile_name = cmd.args.profile_name
        alias_name = cmd.args.alias_name
        alias_val = cmd.args.alias_val

        manifest = self.load_profile_manifest(profile_name)

        if isinstance(manifest, SymlServiceResponse):
            return manifest

        aliases = manifest.get('aliases')
        if alias_val is not None:
            aliases[alias_name] = alias_val
        else:
            if alias_name in aliases:
                del aliases[alias_name]
            else:
                return SymlServiceResponse(errors=[
                    dict(
                        message="unable to find the alias {alias}",
                        alias=alias_name,
                    )
                ])

        return SymlServiceResponse(info=[
            dict(
                message="alias {alias} set to {value}",
                alias=alias_name,
                value=alias_val,
            ) if alias_val is not None else dict(
                message="alias {alias} deleted",
                alias=alias_name,
            )
        ]).combined_with(self.store_profile_manifest(profile_name, manifest))
Exemple #3
0
    async def cmd_get(self, cmd: SymlServiceCommand[GetSchemaParams]):
        path = cmd.args.path
        validate = cmd.args.validate

        definition = SchemaDefinition(self.spec, path)
        return SymlServiceResponse.merge(
            definition=SymlServiceResponse(
                data=definition.body,
                info=[
                    dict(message="loaded ${file}", file=definition.path)
                ]
            ),
            validation=self.validate(definition) if validate else None,
        )
Exemple #4
0
    async def cmd_create(self, cmd: SymlServiceCommand[CreateProfile]):

        base = cmd.args.base
        profile_name = cmd.args.profile_name

        use_default = base is None

        if base is None:
            base = self.DEFAULT_BASE

        base = str(base).replace('@profiles',
                                 str(self.DEFAULT_PROFILES_STORAGE_PATH))

        base = Path(base).expanduser().resolve()
        base_profile_manifest_path = base / self.PROFILE_FILENAME

        if base_profile_manifest_path.exists():
            with open(str(base_profile_manifest_path), 'r') as f:
                base_profile_manifest = yaml.load(f, Loader=yaml.SafeLoader)
        elif use_default:
            base_profile_manifest = dict(
                aliases={},
                areas={},
                # TODO: better defaults
            )
            self.store_profile_manifest(profile_name, base_profile_manifest)
        else:
            return SymlServiceResponse(errors=[
                dict(
                    message='unable to find base {base} for profile {profile}',
                    base=base,
                    profile=profile_name)
            ])

        return self.store_profile_manifest(profile_name, base_profile_manifest)
Exemple #5
0
    def store_profile_manifest(self, name, body):

        path = self.resolve_profile_manifest_path(name)

        is_new = 'created_at' not in body

        path.parent.mkdir(parents=True, exist_ok=True)
        with open(str(path), 'w') as profile_file:
            yaml.dump(
                {
                    **body,
                    'created_at': body.get('created_at', datetime.now()),
                    'updated_at': datetime.now(),
                }, profile_file)

        # TODO: error handling

        return SymlServiceResponse(
            data=body,
            info=[
                dict(
                    message='profile {profile} created'
                    if is_new else 'profile {profile} updated',
                    profile=name,
                )
            ])
Exemple #6
0
    async def cmd_alchemy(self, cmd: SymlServiceCommand[ReverseUsingAlchemy]):

        connection_string = cmd.args.connection_string
        schemas = cmd.args.schemas
        objects_names = cmd.args.objects_names
        objects_types = cmd.args.objects_types

        if connection_string == '@postgres':
            connection_string = "postgresql://*****:*****@localhost:5432/symltest"
            # TODO: postgres in the docker locally or something like that?
            # https://pypi.org/project/pyembedpg/ kinda sucks :(

        engine = create_engine(connection_string)

        if schemas == '@all':
            # TODO: adjust this if necessary with the schema filter
            pass

        metadata = MetaData(engine)

        # TODO: check if we can get schema list instead
        #self.metadata = MetaData(engine, schema=schema)

        # TODO: support for views, and other object types
        if objects_names != '@all':
            metadata.reflect(only=objects_names.split(','))
        else:
            metadata.reflect()

        # TODO:  filter tables by schema name maybe? probably not gonna work :(
        return SymlServiceResponse(
            data=self.get_transformed_tables(metadata),
        )
Exemple #7
0
    async def cmd_list(self):
        await self.ensure()

        items = []
        for d in self.DEFAULT_PROFILES_STORAGE_PATH.iterdir():
            # TODO: more specific data
            profile_manifest = self.load_profile_manifest(d.name)
            item = dict(name=d.name,
                        meta=dict(
                            created_at=profile_manifest.get('created_at'),
                            updated_at=profile_manifest.get('updated_at'),
                        ))

            items.append(item)

        return SymlServiceResponse(data=dict(items=items))
Exemple #8
0
    def load_profile_manifest(self, name):

        path = self.resolve_profile_manifest_path(name)

        if path.exists():
            with open(str(path), 'r') as f:
                return yaml.load(f, Loader=yaml.SafeLoader)
        else:
            return SymlServiceResponse(errors=[
                dict(
                    message='unable to find profile {profile} '
                    'in the path {path}',
                    profile=name,
                    path=str(path),
                )
            ])
Exemple #9
0
    async def on_client_connected(self, reader: StreamReader,
                                  writer: StreamWriter):
        self.logger.debug('client connected')
        while True:  # TODO: while active instead
            raw_command = await reader.readline()

            if raw_command == b'':
                # TODO: not ideal, remove pooling if possible
                await asyncio.sleep(0.5)
                continue

            try:

                command = SymlServiceCommand.parse(raw_command)

                logging.debug("received command %s", command)
                callable_command = getattr(self, f'cmd_{command.name}')

                cmd_arg = get_type_hints(callable_command).get('cmd')

                if cmd_arg:
                    args_type = get_args(cmd_arg)[0]
                    command.args = args_type(**command.args)

                # TODO: handle generators
                try:
                    response: SymlServiceResponse
                    if cmd_arg:
                        response = await callable_command(command)
                    else:
                        response = await callable_command()

                except Exception as e:
                    exc_type, exc_value, traceback = sys.exc_info()
                    tb = Traceback()
                    trace = tb.extract(exc_type,
                                       exc_value,
                                       traceback,
                                       show_locals=False)

                    trace = [dataclasses.asdict(s) for s in trace.stacks]
                    trace = [{
                        **t, 'frames': t.get('frames')[1:]
                    } for t in trace]

                    response = SymlServiceResponse(
                        data=dict(),
                        errors=[
                            dict(message="unhandled exception while "
                                 "processing command (${exception})",
                                 exception=e,
                                 trace=trace)
                        ])

                response.command = command

                writer.write(response.jsonb())
                writer.write('\n'.encode())

                logging.debug("sending response %s", response)

                await writer.drain()
            except Exception as e:
                self.logger.exception("oh no", e)