diracx-db 0.0.1a50__py3-none-any.whl → 0.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- diracx/db/__main__.py +1 -0
 - diracx/db/sql/auth/db.py +69 -2
 - diracx/db/sql/utils/base.py +5 -0
 - {diracx_db-0.0.1a50.dist-info → diracx_db-0.0.2.dist-info}/METADATA +4 -1
 - {diracx_db-0.0.1a50.dist-info → diracx_db-0.0.2.dist-info}/RECORD +7 -7
 - {diracx_db-0.0.1a50.dist-info → diracx_db-0.0.2.dist-info}/WHEEL +0 -0
 - {diracx_db-0.0.1a50.dist-info → diracx_db-0.0.2.dist-info}/entry_points.txt +0 -0
 
    
        diracx/db/__main__.py
    CHANGED
    
    
    
        diracx/db/sql/auth/db.py
    CHANGED
    
    | 
         @@ -1,16 +1,21 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            from __future__ import annotations
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            import logging
         
     | 
| 
       3 
4 
     | 
    
         
             
            import secrets
         
     | 
| 
      
 5 
     | 
    
         
            +
            from datetime import UTC, datetime
         
     | 
| 
      
 6 
     | 
    
         
            +
            from itertools import pairwise
         
     | 
| 
       4 
7 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
            from  
     | 
| 
      
 8 
     | 
    
         
            +
            from dateutil.rrule import MONTHLY, rrule
         
     | 
| 
      
 9 
     | 
    
         
            +
            from sqlalchemy import insert, select, text, update
         
     | 
| 
       6 
10 
     | 
    
         
             
            from sqlalchemy.exc import IntegrityError, NoResultFound
         
     | 
| 
      
 11 
     | 
    
         
            +
            from sqlalchemy.ext.asyncio import AsyncConnection
         
     | 
| 
       7 
12 
     | 
    
         
             
            from uuid_utils import UUID, uuid7
         
     | 
| 
       8 
13 
     | 
    
         | 
| 
       9 
14 
     | 
    
         
             
            from diracx.core.exceptions import (
         
     | 
| 
       10 
15 
     | 
    
         
             
                AuthorizationError,
         
     | 
| 
       11 
16 
     | 
    
         
             
                TokenNotFoundError,
         
     | 
| 
       12 
17 
     | 
    
         
             
            )
         
     | 
| 
       13 
     | 
    
         
            -
            from diracx.db.sql.utils import BaseSQLDB, hash, substract_date
         
     | 
| 
      
 18 
     | 
    
         
            +
            from diracx.db.sql.utils import BaseSQLDB, hash, substract_date, uuid7_from_datetime
         
     | 
| 
       14 
19 
     | 
    
         | 
| 
       15 
20 
     | 
    
         
             
            from .schema import (
         
     | 
| 
       16 
21 
     | 
    
         
             
                AuthorizationFlows,
         
     | 
| 
         @@ -25,10 +30,72 @@ from .schema import Base as AuthDBBase 
     | 
|
| 
       25 
30 
     | 
    
         
             
            USER_CODE_ALPHABET = "BCDFGHJKLMNPQRSTVWXZ"
         
     | 
| 
       26 
31 
     | 
    
         
             
            MAX_RETRY = 5
         
     | 
| 
       27 
32 
     | 
    
         | 
| 
      
 33 
     | 
    
         
            +
            logger = logging.getLogger(__name__)
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
       28 
35 
     | 
    
         | 
| 
       29 
36 
     | 
    
         
             
            class AuthDB(BaseSQLDB):
         
     | 
| 
       30 
37 
     | 
    
         
             
                metadata = AuthDBBase.metadata
         
     | 
| 
       31 
38 
     | 
    
         | 
| 
      
 39 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 40 
     | 
    
         
            +
                async def post_create(cls, conn: AsyncConnection) -> None:
         
     | 
| 
      
 41 
     | 
    
         
            +
                    """Create partitions if it is a MySQL DB and it does not have
         
     | 
| 
      
 42 
     | 
    
         
            +
                    it yet and the table does not have any data yet.
         
     | 
| 
      
 43 
     | 
    
         
            +
                    We do this as a post_create step as sqlalchemy does not support
         
     | 
| 
      
 44 
     | 
    
         
            +
                    partition so well.
         
     | 
| 
      
 45 
     | 
    
         
            +
                    """
         
     | 
| 
      
 46 
     | 
    
         
            +
                    if conn.dialect.name == "mysql":
         
     | 
| 
      
 47 
     | 
    
         
            +
                        check_partition_query = text(
         
     | 
| 
      
 48 
     | 
    
         
            +
                            "SELECT PARTITION_NAME FROM information_schema.partitions "
         
     | 
| 
      
 49 
     | 
    
         
            +
                            "WHERE TABLE_NAME = 'RefreshTokens' AND PARTITION_NAME is not NULL"
         
     | 
| 
      
 50 
     | 
    
         
            +
                        )
         
     | 
| 
      
 51 
     | 
    
         
            +
                        partition_names = (await conn.execute(check_partition_query)).all()
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                        if not partition_names:
         
     | 
| 
      
 54 
     | 
    
         
            +
                            # Create a monthly partition from today until 2 years
         
     | 
| 
      
 55 
     | 
    
         
            +
                            # The partition are named p_<year>_<month>
         
     | 
| 
      
 56 
     | 
    
         
            +
                            start_date = datetime.now(tz=UTC).replace(
         
     | 
| 
      
 57 
     | 
    
         
            +
                                day=1, hour=0, minute=0, second=0, microsecond=0
         
     | 
| 
      
 58 
     | 
    
         
            +
                            )
         
     | 
| 
      
 59 
     | 
    
         
            +
                            end_date = start_date.replace(year=start_date.year + 2)
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                            dates = [
         
     | 
| 
      
 62 
     | 
    
         
            +
                                dt for dt in rrule(MONTHLY, dtstart=start_date, until=end_date)
         
     | 
| 
      
 63 
     | 
    
         
            +
                            ]
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                            partition_list = []
         
     | 
| 
      
 66 
     | 
    
         
            +
                            for name, limit in pairwise(dates):
         
     | 
| 
      
 67 
     | 
    
         
            +
                                partition_list.append(
         
     | 
| 
      
 68 
     | 
    
         
            +
                                    f"PARTITION p_{name.year}_{name.month} "
         
     | 
| 
      
 69 
     | 
    
         
            +
                                    f"VALUES LESS THAN ('{str(uuid7_from_datetime(limit, randomize=False)).replace('-', '')}')"
         
     | 
| 
      
 70 
     | 
    
         
            +
                                )
         
     | 
| 
      
 71 
     | 
    
         
            +
                            partition_list.append("PARTITION p_future VALUES LESS THAN (MAXVALUE)")
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                            alter_query = text(
         
     | 
| 
      
 74 
     | 
    
         
            +
                                f"ALTER TABLE RefreshTokens PARTITION BY RANGE COLUMNS (JTI) ({','.join(partition_list)})"
         
     | 
| 
      
 75 
     | 
    
         
            +
                            )
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                            check_table_empty_query = text("SELECT * FROM RefreshTokens LIMIT 1")
         
     | 
| 
      
 78 
     | 
    
         
            +
                            refresh_table_content = (
         
     | 
| 
      
 79 
     | 
    
         
            +
                                await conn.execute(check_table_empty_query)
         
     | 
| 
      
 80 
     | 
    
         
            +
                            ).all()
         
     | 
| 
      
 81 
     | 
    
         
            +
                            if refresh_table_content:
         
     | 
| 
      
 82 
     | 
    
         
            +
                                logger.warning(
         
     | 
| 
      
 83 
     | 
    
         
            +
                                    "RefreshTokens table not empty. Run the following query yourself"
         
     | 
| 
      
 84 
     | 
    
         
            +
                                )
         
     | 
| 
      
 85 
     | 
    
         
            +
                                logger.warning(alter_query)
         
     | 
| 
      
 86 
     | 
    
         
            +
                                return
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                            await conn.execute(alter_query)
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                            partition_names = (
         
     | 
| 
      
 91 
     | 
    
         
            +
                                await conn.execute(
         
     | 
| 
      
 92 
     | 
    
         
            +
                                    check_partition_query, {"table_name": "RefreshTokens"}
         
     | 
| 
      
 93 
     | 
    
         
            +
                                )
         
     | 
| 
      
 94 
     | 
    
         
            +
                            ).all()
         
     | 
| 
      
 95 
     | 
    
         
            +
                            assert partition_names, (
         
     | 
| 
      
 96 
     | 
    
         
            +
                                f"There should be partitions now {partition_names}"
         
     | 
| 
      
 97 
     | 
    
         
            +
                            )
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
       32 
99 
     | 
    
         
             
                async def device_flow_validate_user_code(
         
     | 
| 
       33 
100 
     | 
    
         
             
                    self, user_code: str, max_validity: int
         
     | 
| 
       34 
101 
     | 
    
         
             
                ) -> str:
         
     | 
    
        diracx/db/sql/utils/base.py
    CHANGED
    
    | 
         @@ -155,6 +155,11 @@ class BaseSQLDB(metaclass=ABCMeta): 
     | 
|
| 
       155 
155 
     | 
    
         
             
                                raise
         
     | 
| 
       156 
156 
     | 
    
         
             
                    return db_urls
         
     | 
| 
       157 
157 
     | 
    
         | 
| 
      
 158 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 159 
     | 
    
         
            +
                async def post_create(cls, conn: AsyncConnection) -> None:
         
     | 
| 
      
 160 
     | 
    
         
            +
                    """Execute actions after the schema has been created."""
         
     | 
| 
      
 161 
     | 
    
         
            +
                    return
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
       158 
163 
     | 
    
         
             
                @classmethod
         
     | 
| 
       159 
164 
     | 
    
         
             
                def transaction(cls) -> Self:
         
     | 
| 
       160 
165 
     | 
    
         
             
                    raise NotImplementedError("This should never be called")
         
     | 
| 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            Metadata-Version: 2.4
         
     | 
| 
       2 
2 
     | 
    
         
             
            Name: diracx-db
         
     | 
| 
       3 
     | 
    
         
            -
            Version: 0.0. 
     | 
| 
      
 3 
     | 
    
         
            +
            Version: 0.0.2
         
     | 
| 
       4 
4 
     | 
    
         
             
            Summary: TODO
         
     | 
| 
       5 
5 
     | 
    
         
             
            License: GPL-3.0-only
         
     | 
| 
       6 
6 
     | 
    
         
             
            Classifier: Intended Audience :: Science/Research
         
     | 
| 
         @@ -12,8 +12,11 @@ Requires-Python: >=3.11 
     | 
|
| 
       12 
12 
     | 
    
         
             
            Requires-Dist: diracx-core
         
     | 
| 
       13 
13 
     | 
    
         
             
            Requires-Dist: opensearch-py[async]
         
     | 
| 
       14 
14 
     | 
    
         
             
            Requires-Dist: pydantic>=2.10
         
     | 
| 
      
 15 
     | 
    
         
            +
            Requires-Dist: python-dateutil
         
     | 
| 
       15 
16 
     | 
    
         
             
            Requires-Dist: sqlalchemy[aiomysql,aiosqlite]>=2
         
     | 
| 
       16 
17 
     | 
    
         
             
            Requires-Dist: uuid-utils
         
     | 
| 
       17 
18 
     | 
    
         
             
            Provides-Extra: testing
         
     | 
| 
       18 
19 
     | 
    
         
             
            Requires-Dist: diracx-testing; extra == 'testing'
         
     | 
| 
       19 
20 
     | 
    
         
             
            Requires-Dist: freezegun; extra == 'testing'
         
     | 
| 
      
 21 
     | 
    
         
            +
            Provides-Extra: types
         
     | 
| 
      
 22 
     | 
    
         
            +
            Requires-Dist: types-python-dateutil; extra == 'types'
         
     | 
| 
         @@ -1,5 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            diracx/db/__init__.py,sha256=2oeUeVwZq53bo_ZOflEYZsBn7tcR5Tzb2AIu0TAWELM,109
         
     | 
| 
       2 
     | 
    
         
            -
            diracx/db/__main__.py,sha256= 
     | 
| 
      
 2 
     | 
    
         
            +
            diracx/db/__main__.py,sha256=6YlmpiU1cLLHjKLy1DfdEOQUyvSla-MbJsJ7aQwAOVs,1757
         
     | 
| 
       3 
3 
     | 
    
         
             
            diracx/db/exceptions.py,sha256=1nn-SZLG-nQwkxbvHjZqXhE5ouzWj1f3qhSda2B4ZEg,83
         
     | 
| 
       4 
4 
     | 
    
         
             
            diracx/db/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       5 
5 
     | 
    
         
             
            diracx/db/os/__init__.py,sha256=IZr6z6SefrRvuC8sTC4RmB3_wwOyEt1GzpDuwSMH8O4,112
         
     | 
| 
         @@ -7,7 +7,7 @@ diracx/db/os/job_parameters.py,sha256=3w_CeA2z-cY5pWwXkGu-Fod27FobbUXuwVKK-jN037 
     | 
|
| 
       7 
7 
     | 
    
         
             
            diracx/db/os/utils.py,sha256=V4T-taos64SFNcorfIr7mq5l5y88K6TzyCj1YqWk8VI,11562
         
     | 
| 
       8 
8 
     | 
    
         
             
            diracx/db/sql/__init__.py,sha256=JYu0b0IVhoXy3lX2m2r2dmAjsRS7IbECBUMEDvX0Te4,391
         
     | 
| 
       9 
9 
     | 
    
         
             
            diracx/db/sql/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       10 
     | 
    
         
            -
            diracx/db/sql/auth/db.py,sha256= 
     | 
| 
      
 10 
     | 
    
         
            +
            diracx/db/sql/auth/db.py,sha256=sGXKFLy1iCdrkg1952_F-c7nRSIx4F1JuDloIV6AXN8,11814
         
     | 
| 
       11 
11 
     | 
    
         
             
            diracx/db/sql/auth/schema.py,sha256=9fUV7taDPnoAcoiwRAmQraOmF2Ytoizjs2TFvN7zsVs,3132
         
     | 
| 
       12 
12 
     | 
    
         
             
            diracx/db/sql/dummy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       13 
13 
     | 
    
         
             
            diracx/db/sql/dummy/db.py,sha256=MKSUSJI1BlRgK08tjCfkCkOz02asvJAeBw60pAdiGV8,1212
         
     | 
| 
         @@ -28,10 +28,10 @@ diracx/db/sql/task_queue/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ 
     | 
|
| 
       28 
28 
     | 
    
         
             
            diracx/db/sql/task_queue/db.py,sha256=2qul1D2tX2uCI92N591WK5xWHakG0pNibzDwKQ7W-I8,6246
         
     | 
| 
       29 
29 
     | 
    
         
             
            diracx/db/sql/task_queue/schema.py,sha256=5efAgvNYRkLlaJ2NzRInRfmVa3tyIzQu2l0oRPy4Kzw,3258
         
     | 
| 
       30 
30 
     | 
    
         
             
            diracx/db/sql/utils/__init__.py,sha256=k1DI4Idlqv36pXn2BhQysb947Peio9DnYaePslkTpUQ,685
         
     | 
| 
       31 
     | 
    
         
            -
            diracx/db/sql/utils/base.py,sha256= 
     | 
| 
      
 31 
     | 
    
         
            +
            diracx/db/sql/utils/base.py,sha256=cXwAzWtYtEkukjHSBGaGNtXSozHfXHpZ9p9eXdQTpDY,17065
         
     | 
| 
       32 
32 
     | 
    
         
             
            diracx/db/sql/utils/functions.py,sha256=_E4tc9Gti6LuSh7QEyoqPJSvCuByVqvRenOXCzxsulE,4014
         
     | 
| 
       33 
33 
     | 
    
         
             
            diracx/db/sql/utils/types.py,sha256=KNZWJfpvHTjfIPg6Nn7zY-rS0q3ybnirHcTcLAYSYbE,5118
         
     | 
| 
       34 
     | 
    
         
            -
            diracx_db-0.0. 
     | 
| 
       35 
     | 
    
         
            -
            diracx_db-0.0. 
     | 
| 
       36 
     | 
    
         
            -
            diracx_db-0.0. 
     | 
| 
       37 
     | 
    
         
            -
            diracx_db-0.0. 
     | 
| 
      
 34 
     | 
    
         
            +
            diracx_db-0.0.2.dist-info/METADATA,sha256=n8QuMXRrA6-iLKw14y29Jj2WxBzQZ2plW5qMngBnEqs,780
         
     | 
| 
      
 35 
     | 
    
         
            +
            diracx_db-0.0.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
         
     | 
| 
      
 36 
     | 
    
         
            +
            diracx_db-0.0.2.dist-info/entry_points.txt,sha256=UPqhLvb9gui0kOyWeI_edtefcrHToZmQt1p76vIwujo,317
         
     | 
| 
      
 37 
     | 
    
         
            +
            diracx_db-0.0.2.dist-info/RECORD,,
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     |