Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ticket 37 - move init.sql from sbl-project repo to user-fi-management #43

Merged
merged 22 commits into from
Nov 6, 2023

Conversation

nargis-sultani
Copy link
Contributor

No description provided.

@github-actions
Copy link

github-actions bot commented Oct 18, 2023

Coverage report

The coverage rate went from 84.93% to 84.93% ⬇️
The branch rate is 85%.

None of the new lines are part of the tested code. Therefore, there is no coverage data about them.

@nargis-sultani
Copy link
Contributor Author

Still working on adding the sample data and testing into the tables.

@nargis-sultani
Copy link
Contributor Author

Some of my tests are failing and I will be working in them today. I am creating a separate ticket for the testing part so this part can be reviewed in the meantime.

@aharjati
Copy link
Contributor

Some of my tests are failing and I will be working in them today. I am creating a separate ticket for the testing part so this part can be reviewed in the meantime.

Are the failed tests related to the alembic script? does the current script work?

@nargis-sultani
Copy link
Contributor Author

Some of my tests are failing and I will be working in them today. I am creating a separate ticket for the testing part so this part can be reviewed in the meantime.

Are the failed tests related to the alembic script? does the current script work?
Yup, the scripts work. I have tested it manually. All the tables exits in the db with data.

Copy link
Contributor

@aharjati aharjati left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added few quick comments. I'll look into it more later today

alembic.ini Outdated
@@ -1,5 +1,6 @@
# A generic, single database configuration.


[alembic]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you remove this empty space

@@ -22,5 +22,6 @@ def upgrade() -> None:
${upgrades if upgrades else "pass"}



Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any changes here.
can you remove the extra white spaces?

op.drop_index("ix_financial_institutions_lei", table_name="financial_institutions")
op.drop_table("financial_institutions")
op.drop_index("ix_denied_domains_domain", table_name="denied_domains")
op.drop_table("denied_domains")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you check if drop_table instruction includes drop_index ?

{"lei": "TEST1LEI", "name": "Test 1"},
{"lei": "TEST2LEI", "name": "Test 2"},
{"lei": "TEST3LEI", "name": "Test 3"},
],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lchen-2101 do you still want to keep these test data?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This data was part of init.sql in sbl-project.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's remove the test data.

@aharjati
Copy link
Contributor

when I ran this local manual test:

curl localhost:8888/v1/institutions -H "Authorization: Bearer ${RT_ACCESS_TOKEN}" | jq -r '.'

I see this error:

sqlalchemy.exc.ProgrammingError: (sqlalchemy.dialects.postgresql.asyncpg.ProgrammingError) <class 'asyncpg.exceptions.UndefinedTableError'>: relation "public.financial_institution_domains" does not exist
[SQL: SELECT anon_1.lei, anon_1.name, anon_1.event_time, financial_institution_domains_1.domain, financial_institution_domains_1.lei AS lei_1, financial_institution_domains_1.event_time AS event_time_1 
FROM (SELECT public.financial_institutions.lei AS lei, public.financial_institutions.name AS name, public.financial_institutions.event_time AS event_time 
FROM public.financial_institutions 
 LIMIT $1::INTEGER OFFSET $2::INTEGER) AS anon_1 LEFT OUTER JOIN public.financial_institution_domains AS financial_institution_domains_1 ON anon_1.lei = financial_institution_domains_1.lei]

Can you check this out?

@nargis-sultani
Copy link
Contributor Author

when I ran this local manual test:

curl localhost:8888/v1/institutions -H "Authorization: Bearer ${RT_ACCESS_TOKEN}" | jq -r '.'

I see this error:

sqlalchemy.exc.ProgrammingError: (sqlalchemy.dialects.postgresql.asyncpg.ProgrammingError) <class 'asyncpg.exceptions.UndefinedTableError'>: relation "public.financial_institution_domains" does not exist
[SQL: SELECT anon_1.lei, anon_1.name, anon_1.event_time, financial_institution_domains_1.domain, financial_institution_domains_1.lei AS lei_1, financial_institution_domains_1.event_time AS event_time_1 
FROM (SELECT public.financial_institutions.lei AS lei, public.financial_institutions.name AS name, public.financial_institutions.event_time AS event_time 
FROM public.financial_institutions 
 LIMIT $1::INTEGER OFFSET $2::INTEGER) AS anon_1 LEFT OUTER JOIN public.financial_institution_domains AS financial_institution_domains_1 ON anon_1.lei = financial_institution_domains_1.lei]

Can you check this out?

I thought the table is supposed to be in financial_intitutions database? Should it be in public database ?

@aharjati
Copy link
Contributor

when I ran this local manual test:

curl localhost:8888/v1/institutions -H "Authorization: Bearer ${RT_ACCESS_TOKEN}" | jq -r '.'

I see this error:

sqlalchemy.exc.ProgrammingError: (sqlalchemy.dialects.postgresql.asyncpg.ProgrammingError) <class 'asyncpg.exceptions.UndefinedTableError'>: relation "public.financial_institution_domains" does not exist
[SQL: SELECT anon_1.lei, anon_1.name, anon_1.event_time, financial_institution_domains_1.domain, financial_institution_domains_1.lei AS lei_1, financial_institution_domains_1.event_time AS event_time_1 
FROM (SELECT public.financial_institutions.lei AS lei, public.financial_institutions.name AS name, public.financial_institutions.event_time AS event_time 
FROM public.financial_institutions 
 LIMIT $1::INTEGER OFFSET $2::INTEGER) AS anon_1 LEFT OUTER JOIN public.financial_institution_domains AS financial_institution_domains_1 ON anon_1.lei = financial_institution_domains_1.lei]

Can you check this out?

I thought the table is supposed to be in financial_intitutions database? Should it be in public database ?

I believe the public is postgres related keyword / structure. If you browse postgres DB, you should see all tables are located under public

Here's what I get when I ran same test on main branch:

$ curl localhost:8888/v1/institutions -H "Authorization: Bearer ${RT_ACCESS_TOKEN}" | jq -r '.'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   268  100   268    0     0   4992      0 --:--:-- --:--:-- --:--:--  5583
[
  {
    "name": "Test 1",
    "lei": "TEST1LEI",
    "domains": [
      {
        "domain": "test1.local",
        "lei": "TEST1LEI"
      }
    ]
  },
  {
    "name": "Test 2",
    "lei": "TEST2LEI",
    "domains": [
      {
        "domain": "test2.local",
        "lei": "TEST2LEI"
      }
    ]
  },
  {
    "name": "Test 3",
    "lei": "TEST3LEI",
    "domains": [
      {
        "domain": "test3.local",
        "lei": "TEST3LEI"
      }
    ]
  }
]

src/models.py Outdated
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this file created? we already have all the models.

from alembic import context
from entities import models
from src.models import Base
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did we create a new models file when we already have all the models?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I didn't see the existing models, will modify it.

@lchen-2101
Copy link
Collaborator

when I ran this local manual test:

curl localhost:8888/v1/institutions -H "Authorization: Bearer ${RT_ACCESS_TOKEN}" | jq -r '.'

I see this error:

sqlalchemy.exc.ProgrammingError: (sqlalchemy.dialects.postgresql.asyncpg.ProgrammingError) <class 'asyncpg.exceptions.UndefinedTableError'>: relation "public.financial_institution_domains" does not exist
[SQL: SELECT anon_1.lei, anon_1.name, anon_1.event_time, financial_institution_domains_1.domain, financial_institution_domains_1.lei AS lei_1, financial_institution_domains_1.event_time AS event_time_1 
FROM (SELECT public.financial_institutions.lei AS lei, public.financial_institutions.name AS name, public.financial_institutions.event_time AS event_time 
FROM public.financial_institutions 
 LIMIT $1::INTEGER OFFSET $2::INTEGER) AS anon_1 LEFT OUTER JOIN public.financial_institution_domains AS financial_institution_domains_1 ON anon_1.lei = financial_institution_domains_1.lei]

Can you check this out?

I thought the table is supposed to be in financial_intitutions database? Should it be in public database ?

sorry, haven't gotten around to the full code yet, but public stands for the schema, this depends on the configuration, so it can live under the public schema like in our local dev setup, or in our dev alto environment it's fi; the name, and schema of the database is configurable in the app code, I'm hoping it's the same with alembic?

@nargis-sultani
Copy link
Contributor Author

when I ran this local manual test:

curl localhost:8888/v1/institutions -H "Authorization: Bearer ${RT_ACCESS_TOKEN}" | jq -r '.'

I see this error:

sqlalchemy.exc.ProgrammingError: (sqlalchemy.dialects.postgresql.asyncpg.ProgrammingError) <class 'asyncpg.exceptions.UndefinedTableError'>: relation "public.financial_institution_domains" does not exist
[SQL: SELECT anon_1.lei, anon_1.name, anon_1.event_time, financial_institution_domains_1.domain, financial_institution_domains_1.lei AS lei_1, financial_institution_domains_1.event_time AS event_time_1 
FROM (SELECT public.financial_institutions.lei AS lei, public.financial_institutions.name AS name, public.financial_institutions.event_time AS event_time 
FROM public.financial_institutions 
 LIMIT $1::INTEGER OFFSET $2::INTEGER) AS anon_1 LEFT OUTER JOIN public.financial_institution_domains AS financial_institution_domains_1 ON anon_1.lei = financial_institution_domains_1.lei]

Can you check this out?

I thought the table is supposed to be in financial_intitutions database? Should it be in public database ?

sorry, haven't gotten around to the full code yet, but public stands for the schema, this depends on the configuration, so it can live under the public schema like in our local dev setup, or in our dev alto environment it's fi; the name, and schema of the database is configurable in the app code, I'm hoping it's the same with alembic?

Yes, it is configurable.

@nargis-sultani
Copy link
Contributor Author

nargis-sultani commented Oct 23, 2023

So, the tests are added. This PR will also close ticket # 44.

from alembic import context
from entities import models
from src.entities.models import Base
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't need to have src in the path, should follow what it was previously, and just be entities..., you want to import Base directly, do entities.models

Comment on lines 108 to 123
"""connectable = engine_from_config(
config.get_section(config.config_ini_section, {}),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)

with connectable.connect() as connection:
context.configure(connection=connection, target_metadata=target_metadata)
context.configure(
connection=connection,
target_metadata=target_metadata,
version_table_schema=target_metadata.schema,
include_object=include_object,
)

with context.begin_transaction():
context.run_migrations()
context.run_migrations()"""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this section a docstring? looks like it's the same code as above?

@@ -73,7 +73,7 @@ def from_claim(cls, claims: Dict[str, Any]) -> "AuthenticatedUser":
)

@classmethod
def parse_institutions(cls, institutions: List[str] | None) -> List[str]:
def parse_institutions(cls, institutions: Optional[List[str]] = None) -> List[str]:
Copy link
Collaborator

@lchen-2101 lchen-2101 Oct 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's stick with union instead of optional, it would seem to be the preferred way.

def parse_institutions(cls, institutions: List[str] | None = None) -> List[str]:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was throwing errors with alembic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lchen-2101 it was throwing errors, this was the only way to fix.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what errors was it throwing? I just tried with List[str] | None = None.



def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove this auto-generated comment?

op.drop_index(op.f("ix_financial_institutions_lei"), table_name="financial_institutions")
op.drop_table("financial_institutions")
op.drop_index(op.f("ix_denied_domains_domain"), table_name="denied_domains")
op.drop_table("denied_domains")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may have missed comment's reply on drop_index. Do we need drop_index even though we're going to drop the table anyway?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, it was removed but it was generated when I tried to fix the previous issues. Removing them again.

sa.Column("event_time", sa.DateTime(), server_default=sa.text("now()"), nullable=False),
sa.ForeignKeyConstraint(
["lei"],
["public.financial_institutions.lei"],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the schema name needed here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking into it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lchen-2101 removed in latest commit.

@aharjati
Copy link
Contributor

I verified the error when querying institutions is fixed:

curl localhost:8888/v1/institutions -H "Authorization: Bearer ${RT_ACCESS_TOKEN}" | jq -r '.'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   268  100   268    0     0   1659      0 --:--:-- --:--:-- --:--:--  1729
[
  {
    "name": "Test 1",
    "lei": "TEST1LEI",
    "domains": [
      {
        "domain": "test1.local",
        "lei": "TEST1LEI"
      }
    ]
  },
  {
    "name": "Test 2",
    "lei": "TEST2LEI",
    "domains": [
      {
        "domain": "test2.local",
        "lei": "TEST2LEI"
      }
    ]
  },
  {
    "name": "Test 3",
    "lei": "TEST3LEI",
    "domains": [
      {
        "domain": "test3.local",
        "lei": "TEST3LEI"
      }
    ]
  }
]

@aharjati
Copy link
Contributor

aharjati commented Oct 24, 2023

However, when I tried to add entry, I received "forbidden":

$ curl localhost:8888/v1/institutions/ -X POST \
-H "Authorization: Bearer ${RT_ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d '{"lei": "TESTBANK123", "name": "Test Bank 123"}' | jq -r '.'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    69  100    22  100    47    370    790 --:--:-- --:--:-- --:--:--  1326
{
  "detail": "Forbidden"
}

@lchen-2101 is this what expected with current codebase?

debug printout:

Traceback (most recent call last):
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__
    raise e
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__
    await self.app(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/routing.py", line 718, in __call__
    await route.handle(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/fastapi/routing.py", line 231, in app
    solved_result = await solve_dependencies(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/fastapi/dependencies/utils.py", line 622, in solve_dependencies
    solved = await call(**sub_values)
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harjatia/Projects/regtech-user-fi-management/src/dependencies.py", line 16, in check_domain
    raise HTTPException(status_code=HTTPStatus.FORBIDDEN)
fastapi.exceptions.HTTPException
Stack (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/spawn.py", line 122, in spawn_main
    exitcode = _main(fd, parent_sentinel)
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/spawn.py", line 135, in _main
    return self._bootstrap(parent_sentinel)
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/process.py", line 314, in _bootstrap
    self.run()
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started
    target(sockets=sockets)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/uvicorn/server.py", line 61, in run
    return asyncio.run(self.serve(sockets=sockets))
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py", line 640, in run_until_complete
    self.run_forever()
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py", line 607, in run_forever
    self._run_once()
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py", line 1922, in _run_once
    handle._run()
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/events.py", line 80, in _run
    self._context.run(self._callback, *self._args)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py", line 428, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/fastapi/applications.py", line 282, in __call__
    await super().__call__(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/applications.py", line 122, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/middleware/cors.py", line 83, in __call__
    await self.app(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/middleware/authentication.py", line 48, in __call__
    await self.app(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 88, in __call__
    response = await handler(request, exc)
  File "/Users/harjatia/Projects/regtech-user-fi-management/src/main.py", line 22, in http_exception_handler
    log.error(exception, exc_info=True, stack_info=True)
INFO:     127.0.0.1:51436 - "POST /v1/institutions/ HTTP/1.1" 403 Forbidden

@lchen-2101
Copy link
Collaborator

However, when I tried to add entry, I received "forbidden":

$ curl localhost:8888/v1/institutions/ -X POST \
-H "Authorization: Bearer ${RT_ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d '{"lei": "TESTBANK123", "name": "Test Bank 123"}' | jq -r '.'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    69  100    22  100    47    370    790 --:--:-- --:--:-- --:--:--  1326
{
  "detail": "Forbidden"
}

@lchen-2101 is this what expected with current codebase?

debug printout:

Traceback (most recent call last):
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 20, in __call__
    raise e
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 17, in __call__
    await self.app(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/routing.py", line 718, in __call__
    await route.handle(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
               ^^^^^^^^^^^^^^^^^^^
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/fastapi/routing.py", line 231, in app
    solved_result = await solve_dependencies(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/fastapi/dependencies/utils.py", line 622, in solve_dependencies
    solved = await call(**sub_values)
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/harjatia/Projects/regtech-user-fi-management/src/dependencies.py", line 16, in check_domain
    raise HTTPException(status_code=HTTPStatus.FORBIDDEN)
fastapi.exceptions.HTTPException
Stack (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/spawn.py", line 122, in spawn_main
    exitcode = _main(fd, parent_sentinel)
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/spawn.py", line 135, in _main
    return self._bootstrap(parent_sentinel)
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/process.py", line 314, in _bootstrap
    self.run()
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started
    target(sockets=sockets)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/uvicorn/server.py", line 61, in run
    return asyncio.run(self.serve(sockets=sockets))
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py", line 190, in run
    return runner.run(main)
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py", line 640, in run_until_complete
    self.run_forever()
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py", line 607, in run_forever
    self._run_once()
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/base_events.py", line 1922, in _run_once
    handle._run()
  File "/Users/harjatia/homebrew/Cellar/python@3.11/3.11.5/Frameworks/Python.framework/Versions/3.11/lib/python3.11/asyncio/events.py", line 80, in _run
    self._context.run(self._callback, *self._args)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py", line 428, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/fastapi/applications.py", line 282, in __call__
    await super().__call__(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/applications.py", line 122, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/middleware/cors.py", line 83, in __call__
    await self.app(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/middleware/authentication.py", line 48, in __call__
    await self.app(scope, receive, send)
  File "/Users/harjatia/Projects/regtech-user-fi-management/.venv/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 88, in __call__
    response = await handler(request, exc)
  File "/Users/harjatia/Projects/regtech-user-fi-management/src/main.py", line 22, in http_exception_handler
    log.error(exception, exc_info=True, stack_info=True)
INFO:     127.0.0.1:51436 - "POST /v1/institutions/ HTTP/1.1" 403 Forbidden

yeap, user1 doesn't have the permissions to do this call, admin1 is the account for testing this functionality, also need to update the email for the account, something like admin1@local.host would work.

@aharjati
Copy link
Contributor

aharjati commented Oct 25, 2023

yeap, user1 doesn't have the permissions to do this call, admin1 is the account for testing this functionality, also need to update the email for the account, something like admin1@local.host would work.

Thanks! after changing to admin1 and update the email through keycloak admin webui, I am able to run upsert.

$ export RT_ACCESS_TOKEN=$(curl 'localhost:8880/realms/regtech/protocol/openid-connect/token' \
-X POST \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'username=admin1' \
--data-urlencode 'password=admin' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id=regtech-client' | jq -r '.access_token')

curl localhost:8888/v1/institutions/ -X POST \
-H "Authorization: Bearer ${RT_ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d '{"lei": "TESTBANK123", "name": "Test Bank 123"}' | jq -r '.'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  2341  100  2266  100    75  19318    639 --:--:-- --:--:-- --:--:-- 21281
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   132  100    85  100    47    187    103 --:--:-- --:--:-- --:--:--   295
[
  "636cab94-3044-4877-b2e2-3969e82b8861",
  {
    "name": "Test Bank 123",
    "lei": "TESTBANK123"
  }
]



def include_object(object, name, type_, reflected, compare_to):
if type_ == "table" and name == "alembic_version":
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we definitely need to have the alembic_version table to be included, this is how alembic tracks what has been ran, and what hasn't.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, we'll need to update the configuration to include version_table_schema since on local machine it'll be the default public, but in other environments, it'll be different. look into https://alembic.sqlalchemy.org/en/latest/api/runtime.html#alembic.runtime.environment.EnvironmentContext.configure.params.version_table_schema

pyproject.toml Outdated
@@ -18,6 +18,8 @@ python-jose = "^3.3.0"
requests = "^2.31.0"
asyncpg = "^0.27.0"
alembic = "^1.12.0"
pytest-alembic = "0.10.7"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the testing dependency should only exist in the dev group

@lchen-2101
Copy link
Collaborator

Currently tables already exists, and running this would cause failure because of that, we need a way to mark a certain revision to be completed in case failure occurs in this specific scenario. It would be better to make these revisions smaller; i.e. one table creation per script instead of having all of them in one script. This would allow for much better error isolation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how is this test ran? when I issue pytest command, this doesn't show up in the report.

@nargis-sultani
Copy link
Contributor Author

Looking into it.

@lchen-2101
Copy link
Collaborator

Currently tables already exists, and running this would cause failure because of that, we need a way to mark a certain revision to be completed in case failure occurs in this specific scenario. It would be better to make these revisions smaller; i.e. one table creation per script instead of having all of them in one script. This would allow for much better error isolation.

here's one way to check if the table already exists: https://stackoverflow.com/questions/31299709/alembic-create-table-check-if-table-exists

essentially:

from sqlalchemy.engine.reflection import Inspector

conn = op.get_bind()
inspector = Inspector.from_engine(conn)
tables = inspector.get_table_names()

if table_name not in tables:
   # run the table creation script

@nargis-sultani
Copy link
Contributor Author

Currently tables already exists, and running this would cause failure because of that, we need a way to mark a certain revision to be completed in case failure occurs in this specific scenario. It would be better to make these revisions smaller; i.e. one table creation per script instead of having all of them in one script. This would allow for much better error isolation.

here's one way to check if the table already exists: https://stackoverflow.com/questions/31299709/alembic-create-table-check-if-table-exists

essentially:

from sqlalchemy.engine.reflection import Inspector

conn = op.get_bind()
inspector = Inspector.from_engine(conn)
tables = inspector.get_table_names()

if table_name not in tables:
   # run the table creation script

Thanks, Le. I am pushing the changes later today.

Copy link
Collaborator

@lchen-2101 lchen-2101 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good for now, will add additional issue to expand coverage and add custom tests.

@lchen-2101 lchen-2101 merged commit de058eb into main Nov 6, 2023
3 checks passed
@lchen-2101 lchen-2101 deleted the features/37_move_init.sql_to_use_alembic branch November 6, 2023 18:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants