meerschaum 2.7.2__py3-none-any.whl → 2.7.4__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.
- meerschaum/_internal/arguments/_parse_arguments.py +2 -0
- meerschaum/_internal/arguments/_parser.py +17 -11
- meerschaum/actions/clear.py +1 -1
- meerschaum/actions/edit.py +1 -1
- meerschaum/actions/start.py +2 -2
- meerschaum/actions/verify.py +18 -21
- meerschaum/config/_version.py +1 -1
- meerschaum/connectors/sql/_fetch.py +45 -26
- meerschaum/connectors/sql/_instance.py +4 -4
- meerschaum/connectors/sql/_pipes.py +135 -103
- meerschaum/core/Pipe/_attributes.py +1 -1
- meerschaum/core/Pipe/_dtypes.py +9 -9
- meerschaum/core/Pipe/_fetch.py +2 -3
- meerschaum/core/Pipe/_sync.py +11 -3
- meerschaum/core/Pipe/_verify.py +9 -5
- meerschaum/jobs/__init__.py +1 -3
- meerschaum/utils/daemon/Daemon.py +1 -1
- meerschaum/utils/daemon/StdinFile.py +4 -1
- meerschaum/utils/dataframe.py +10 -2
- meerschaum/utils/dtypes/sql.py +1 -1
- meerschaum/utils/formatting/__init__.py +5 -25
- meerschaum/utils/formatting/_pipes.py +9 -6
- meerschaum/utils/sql.py +156 -87
- meerschaum/utils/venv/__init__.py +61 -13
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.4.dist-info}/METADATA +1 -1
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.4.dist-info}/RECORD +32 -32
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.4.dist-info}/LICENSE +0 -0
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.4.dist-info}/NOTICE +0 -0
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.4.dist-info}/WHEEL +0 -0
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.4.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.4.dist-info}/top_level.txt +0 -0
- {meerschaum-2.7.2.dist-info → meerschaum-2.7.4.dist-info}/zip-safe +0 -0
| @@ -240,6 +240,8 @@ def parse_synonyms( | |
| 240 240 | 
             
                    args_dict['instance'] = args_dict['mrsm_instance']
         | 
| 241 241 | 
             
                if args_dict.get('skip_check_existing', None):
         | 
| 242 242 | 
             
                    args_dict['check_existing'] = False
         | 
| 243 | 
            +
                if args_dict.get('skip_enforce_dtypes', None):
         | 
| 244 | 
            +
                    args_dict['enforce_dtypes'] = False
         | 
| 243 245 | 
             
                if args_dict.get('venv', None) in ('None', '[None]'):
         | 
| 244 246 | 
             
                    args_dict['venv'] = None
         | 
| 245 247 | 
             
                chunk_minutes = args_dict.get('chunk_minutes', None)
         | 
| @@ -87,7 +87,7 @@ def parse_datetime(dt_str: str) -> Union[datetime, int, str]: | |
| 87 87 | 
             
                            dt = round_time(dt, round_delta)
         | 
| 88 88 | 
             
                    else:
         | 
| 89 89 | 
             
                        dt = dateutil_parser.parse(dt_str)
         | 
| 90 | 
            -
                except Exception | 
| 90 | 
            +
                except Exception:
         | 
| 91 91 | 
             
                    dt = None
         | 
| 92 92 | 
             
                if dt is None:
         | 
| 93 93 | 
             
                    from meerschaum.utils.warnings import error
         | 
| @@ -121,7 +121,7 @@ def parse_help(sysargs: Union[List[str], Dict[str, Any]]) -> None: | |
| 121 121 | 
             
                """Parse the `--help` flag to determine which help message to print."""
         | 
| 122 122 | 
             
                from meerschaum._internal.arguments._parse_arguments import parse_arguments, parse_line
         | 
| 123 123 | 
             
                from meerschaum.actions import actions, get_subactions
         | 
| 124 | 
            -
                import  | 
| 124 | 
            +
                import textwrap
         | 
| 125 125 | 
             
                from copy import deepcopy
         | 
| 126 126 | 
             
                if isinstance(sysargs, list):
         | 
| 127 127 | 
             
                    args = parse_arguments(sysargs)
         | 
| @@ -140,14 +140,14 @@ def parse_help(sysargs: Union[List[str], Dict[str, Any]]) -> None: | |
| 140 140 | 
             
                if len(args['action']) > 1:
         | 
| 141 141 | 
             
                    try:
         | 
| 142 142 | 
             
                        subaction = get_subactions(args['action'][0])[args['action'][1]]
         | 
| 143 | 
            -
                    except Exception | 
| 143 | 
            +
                    except Exception:
         | 
| 144 144 | 
             
                        subaction = None
         | 
| 145 145 | 
             
                    if subaction is not None:
         | 
| 146 146 | 
             
                        return print(textwrap.dedent(subaction.__doc__))
         | 
| 147 147 |  | 
| 148 148 | 
             
                try:
         | 
| 149 149 | 
             
                    doc = actions[args['action'][0]].__doc__
         | 
| 150 | 
            -
                except Exception | 
| 150 | 
            +
                except Exception:
         | 
| 151 151 | 
             
                    doc = None
         | 
| 152 152 | 
             
                if doc is None:
         | 
| 153 153 | 
             
                    doc = "No help available for '" + f"{args['action'][0]}" + "'."
         | 
| @@ -309,7 +309,7 @@ groups['sync'].add_argument( | |
| 309 309 | 
             
            )
         | 
| 310 310 | 
             
            groups['sync'].add_argument(
         | 
| 311 311 | 
             
                '--chunksize', type=int, help=(
         | 
| 312 | 
            -
                    "Specify the database chunksize. Defaults to  | 
| 312 | 
            +
                    "Specify the database chunksize. Defaults to 100,000."
         | 
| 313 313 | 
             
                ),
         | 
| 314 314 | 
             
            )
         | 
| 315 315 | 
             
            groups['sync'].add_argument(
         | 
| @@ -336,19 +336,25 @@ groups['sync'].add_argument( | |
| 336 336 | 
             
            )
         | 
| 337 337 | 
             
            groups['sync'].add_argument(
         | 
| 338 338 | 
             
                '--bounded', '--bound', action="store_true",
         | 
| 339 | 
            -
                help | 
| 339 | 
            +
                help=(
         | 
| 340 340 | 
             
                    "When verifying, do not sync outside "
         | 
| 341 | 
            -
                     | 
| 341 | 
            +
                    "the existing oldest and newest datetime bounds."
         | 
| 342 342 | 
             
                )
         | 
| 343 343 | 
             
            )
         | 
| 344 344 | 
             
            groups['sync'].add_argument(
         | 
| 345 345 | 
             
                '--skip-check-existing', '--allow-duplicates', action='store_true',
         | 
| 346 | 
            -
                help | 
| 347 | 
            -
                    "Skip checking for duplicate rows when syncing. " | 
| 348 | 
            -
                    "This  | 
| 349 | 
            -
                    "For example, this setting is highly recommended for use with IoT devices."
         | 
| 346 | 
            +
                help=(
         | 
| 347 | 
            +
                    "Skip checking for duplicate rows when syncing. "
         | 
| 348 | 
            +
                    "This improves performance when all rows to be synced are unique. "
         | 
| 350 349 | 
             
                )
         | 
| 351 350 | 
             
            )
         | 
| 351 | 
            +
            groups['sync'].add_argument(
         | 
| 352 | 
            +
                '--skip-enforce-dtypes', action='store_true',
         | 
| 353 | 
            +
                help=(
         | 
| 354 | 
            +
                    "Skip enforcing incoming data to a pipe's dtypes. "
         | 
| 355 | 
            +
                    "This improves performance when all rows are expected to already be of the correct type."
         | 
| 356 | 
            +
                ),
         | 
| 357 | 
            +
            )
         | 
| 352 358 | 
             
            groups['sync'].add_argument(
         | 
| 353 359 | 
             
                '--cache', action='store_true',
         | 
| 354 360 | 
             
                help = (
         | 
    
        meerschaum/actions/clear.py
    CHANGED
    
    | @@ -137,7 +137,7 @@ def _ask_with_rowcounts( | |
| 137 137 | 
             
                )
         | 
| 138 138 | 
             
                total_num_rows = sum([rc for p, rc in pipes_rowcounts.items()])
         | 
| 139 139 | 
             
                question = (
         | 
| 140 | 
            -
                    f"Are you sure you want to delete {total_num_rows} rows across {len(pipes)} pipe"
         | 
| 140 | 
            +
                    f"Are you sure you want to delete {total_num_rows:,} rows across {len(pipes)} pipe"
         | 
| 141 141 | 
             
                    + ('s' if len(pipes) != 1 else '')
         | 
| 142 142 | 
             
                    + " in the following range?\n"
         | 
| 143 143 | 
             
                )
         | 
    
        meerschaum/actions/edit.py
    CHANGED
    
    
    
        meerschaum/actions/start.py
    CHANGED
    
    | @@ -183,7 +183,7 @@ def _start_jobs( | |
| 183 183 | 
             
                    ### Cannot find dameon_id
         | 
| 184 184 | 
             
                    else:
         | 
| 185 185 | 
             
                        msg = (
         | 
| 186 | 
            -
                             | 
| 186 | 
            +
                            "Unknown job" + ('s' if len(action) != 1 else '') + ' '
         | 
| 187 187 | 
             
                            + items_str(action, and_str='or') + '.'
         | 
| 188 188 | 
             
                        )
         | 
| 189 189 | 
             
                        return False, msg
         | 
| @@ -216,7 +216,7 @@ def _start_jobs( | |
| 216 216 | 
             
                    return job.start(debug=debug), name
         | 
| 217 217 |  | 
| 218 218 | 
             
                def _run_existing_job(name: str):
         | 
| 219 | 
            -
                    job = Job(name, executor_keys=executor_keys)
         | 
| 219 | 
            +
                    job = jobs.get(name, Job(name, executor_keys=executor_keys))
         | 
| 220 220 | 
             
                    return job.start(debug=debug), name
         | 
| 221 221 |  | 
| 222 222 | 
             
                if not names:
         | 
    
        meerschaum/actions/verify.py
    CHANGED
    
    | @@ -10,9 +10,9 @@ from __future__ import annotations | |
| 10 10 | 
             
            from meerschaum.utils.typing import Union, Any, Sequence, SuccessTuple, Optional, Tuple, List
         | 
| 11 11 |  | 
| 12 12 | 
             
            def verify(
         | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 13 | 
            +
                action: Optional[List[str]] = None,
         | 
| 14 | 
            +
                **kwargs: Any
         | 
| 15 | 
            +
            ) -> SuccessTuple:
         | 
| 16 16 | 
             
                """
         | 
| 17 17 | 
             
                Verify the states of pipes, packages, and more.
         | 
| 18 18 | 
             
                """
         | 
| @@ -36,19 +36,17 @@ def _verify_pipes(**kwargs) -> SuccessTuple: | |
| 36 36 |  | 
| 37 37 |  | 
| 38 38 | 
             
            def _verify_packages(
         | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 39 | 
            +
                debug: bool = False,
         | 
| 40 | 
            +
                venv: Optional[str] = 'mrsm',
         | 
| 41 | 
            +
                **kw
         | 
| 42 | 
            +
            ) -> SuccessTuple:
         | 
| 43 43 | 
             
                """
         | 
| 44 44 | 
             
                Verify the versions of packages.
         | 
| 45 45 | 
             
                """
         | 
| 46 46 | 
             
                from meerschaum.utils.packages import (
         | 
| 47 | 
            -
                    attempt_import,  | 
| 47 | 
            +
                    attempt_import, all_packages, is_installed, venv_contains_package,
         | 
| 48 48 | 
             
                    _monkey_patch_get_distribution, manually_import_module,
         | 
| 49 49 | 
             
                )
         | 
| 50 | 
            -
                from meerschaum.utils.formatting import pprint
         | 
| 51 | 
            -
                from meerschaum.utils.debug import dprint
         | 
| 52 50 |  | 
| 53 51 | 
             
                venv_packages, base_packages, miss_packages = [], [], []
         | 
| 54 52 |  | 
| @@ -80,10 +78,10 @@ def _verify_packages( | |
| 80 78 |  | 
| 81 79 |  | 
| 82 80 | 
             
            def _verify_venvs(
         | 
| 83 | 
            -
             | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 86 | 
            -
             | 
| 81 | 
            +
                action: Optional[List[str]],
         | 
| 82 | 
            +
                debug: bool = False,
         | 
| 83 | 
            +
                **kw
         | 
| 84 | 
            +
            ) -> SuccessTuple:
         | 
| 87 85 | 
             
                """
         | 
| 88 86 | 
             
                Verify your virtual environments.
         | 
| 89 87 | 
             
                """
         | 
| @@ -94,15 +92,14 @@ def _verify_venvs( | |
| 94 92 |  | 
| 95 93 |  | 
| 96 94 | 
             
            def _verify_plugins(
         | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 95 | 
            +
                action: Optional[List[str]] = None,
         | 
| 96 | 
            +
                **kwargs: Any
         | 
| 97 | 
            +
            ) -> SuccessTuple:
         | 
| 100 98 | 
             
                """
         | 
| 101 99 | 
             
                Verify that all of the available plugins are able to be imported as expected.
         | 
| 102 100 | 
             
                """
         | 
| 103 | 
            -
                from meerschaum.utils.formatting import print_options,  | 
| 104 | 
            -
                from meerschaum.plugins import  | 
| 105 | 
            -
                from meerschaum.config import get_config
         | 
| 101 | 
            +
                from meerschaum.utils.formatting import print_options, print_tuple
         | 
| 102 | 
            +
                from meerschaum.plugins import get_plugins_names, Plugin
         | 
| 106 103 | 
             
                from meerschaum.utils.misc import items_str
         | 
| 107 104 |  | 
| 108 105 | 
             
                plugins_names_to_verify = action or get_plugins_names()
         | 
| @@ -135,7 +132,7 @@ def _verify_plugins( | |
| 135 132 | 
             
                    f"Successfully imported {len(plugins_names_to_verify)} plugins."
         | 
| 136 133 | 
             
                    if success
         | 
| 137 134 | 
             
                    else (
         | 
| 138 | 
            -
                         | 
| 135 | 
            +
                        "Failed to import plugin"
         | 
| 139 136 | 
             
                        + ('s' if len(failed_to_import) != 1 else '')
         | 
| 140 137 | 
             
                        + f" {items_str(failed_to_import)}."
         | 
| 141 138 | 
             
                    )
         | 
    
        meerschaum/config/_version.py
    CHANGED
    
    
| @@ -9,6 +9,7 @@ Implement the Connector fetch() method | |
| 9 9 | 
             
            from __future__ import annotations
         | 
| 10 10 |  | 
| 11 11 | 
             
            from datetime import datetime, timedelta
         | 
| 12 | 
            +
             | 
| 12 13 | 
             
            import meerschaum as mrsm
         | 
| 13 14 | 
             
            from meerschaum.utils.typing import Optional, Union, Callable, Any, List, Dict
         | 
| 14 15 |  | 
| @@ -144,37 +145,37 @@ def get_pipe_metadef( | |
| 144 145 | 
             
                -------
         | 
| 145 146 | 
             
                A pipe's meta definition fetch query string.
         | 
| 146 147 | 
             
                """
         | 
| 147 | 
            -
                from meerschaum.utils. | 
| 148 | 
            -
                from meerschaum.utils.warnings import warn, error
         | 
| 148 | 
            +
                from meerschaum.utils.warnings import warn
         | 
| 149 149 | 
             
                from meerschaum.utils.sql import sql_item_name, dateadd_str, build_where
         | 
| 150 | 
            +
                from meerschaum.utils.dtypes.sql import get_db_type_from_pd_type
         | 
| 150 151 | 
             
                from meerschaum.utils.misc import is_int
         | 
| 151 152 | 
             
                from meerschaum.config import get_config
         | 
| 152 153 |  | 
| 153 | 
            -
                 | 
| 154 | 
            -
             | 
| 155 | 
            -
             | 
| 156 | 
            -
                     | 
| 157 | 
            -
                    dt_name = sql_item_name(_dt, self.flavor, None) if _dt else None
         | 
| 154 | 
            +
                dt_col = pipe.columns.get('datetime', None)
         | 
| 155 | 
            +
                if not dt_col:
         | 
| 156 | 
            +
                    dt_col = pipe.guess_datetime()
         | 
| 157 | 
            +
                    dt_name = sql_item_name(dt_col, self.flavor, None) if dt_col else None
         | 
| 158 158 | 
             
                    is_guess = True
         | 
| 159 159 | 
             
                else:
         | 
| 160 | 
            -
                     | 
| 161 | 
            -
                    dt_name = sql_item_name(_dt, self.flavor, None)
         | 
| 160 | 
            +
                    dt_name = sql_item_name(dt_col, self.flavor, None)
         | 
| 162 161 | 
             
                    is_guess = False
         | 
| 162 | 
            +
                dt_typ = pipe.dtypes.get(dt_col, 'datetime') if dt_col else None
         | 
| 163 | 
            +
                db_dt_typ = get_db_type_from_pd_type(dt_typ, self.flavor) if dt_typ else None
         | 
| 163 164 |  | 
| 164 165 | 
             
                if begin not in (None, '') or end is not None:
         | 
| 165 166 | 
             
                    if is_guess:
         | 
| 166 | 
            -
                        if  | 
| 167 | 
            +
                        if dt_col is None:
         | 
| 167 168 | 
             
                            warn(
         | 
| 168 169 | 
             
                                f"Unable to determine a datetime column for {pipe}."
         | 
| 169 170 | 
             
                                + "\n    Ignoring begin and end...",
         | 
| 170 | 
            -
                                stack | 
| 171 | 
            +
                                stack=False,
         | 
| 171 172 | 
             
                            )
         | 
| 172 173 | 
             
                            begin, end = '', None
         | 
| 173 174 | 
             
                        else:
         | 
| 174 175 | 
             
                            warn(
         | 
| 175 176 | 
             
                                f"A datetime wasn't specified for {pipe}.\n"
         | 
| 176 | 
            -
                                + f"    Using column \"{ | 
| 177 | 
            -
                                stack | 
| 177 | 
            +
                                + f"    Using column \"{dt_col}\" for datetime bounds...",
         | 
| 178 | 
            +
                                stack=False
         | 
| 178 179 | 
             
                            )
         | 
| 179 180 |  | 
| 180 181 | 
             
                apply_backtrack = begin == '' and check_existing
         | 
| @@ -200,6 +201,7 @@ def get_pipe_metadef( | |
| 200 201 | 
             
                            datepart='minute',
         | 
| 201 202 | 
             
                            number=((-1 * btm) if apply_backtrack else 0),
         | 
| 202 203 | 
             
                            begin=begin,
         | 
| 204 | 
            +
                            db_type=db_dt_typ,
         | 
| 203 205 | 
             
                        )
         | 
| 204 206 | 
             
                        if begin
         | 
| 205 207 | 
             
                        else None
         | 
| @@ -210,11 +212,13 @@ def get_pipe_metadef( | |
| 210 212 | 
             
                            datepart='minute',
         | 
| 211 213 | 
             
                            number=0,
         | 
| 212 214 | 
             
                            begin=end,
         | 
| 215 | 
            +
                            db_type=db_dt_typ,
         | 
| 213 216 | 
             
                        )
         | 
| 214 217 | 
             
                        if end
         | 
| 215 218 | 
             
                        else None
         | 
| 216 219 | 
             
                    )
         | 
| 217 220 |  | 
| 221 | 
            +
                definition_name = sql_item_name('definition', self.flavor, None)
         | 
| 218 222 | 
             
                meta_def = (
         | 
| 219 223 | 
             
                    _simple_fetch_query(pipe, self.flavor) if (
         | 
| 220 224 | 
             
                        (not (pipe.columns or {}).get('id', None))
         | 
| @@ -225,26 +229,26 @@ def get_pipe_metadef( | |
| 225 229 | 
             
                has_where = 'where' in meta_def.lower()[meta_def.lower().rfind('definition'):]
         | 
| 226 230 | 
             
                if dt_name and (begin_da or end_da):
         | 
| 227 231 | 
             
                    definition_dt_name = (
         | 
| 228 | 
            -
                        dateadd_str(self.flavor, 'minute', 0, f" | 
| 232 | 
            +
                        dateadd_str(self.flavor, 'minute', 0, f"{definition_name}.{dt_name}", db_type=db_dt_typ)
         | 
| 229 233 | 
             
                        if not is_int((begin_da or end_da))
         | 
| 230 | 
            -
                        else f" | 
| 234 | 
            +
                        else f"{definition_name}.{dt_name}"
         | 
| 231 235 | 
             
                    )
         | 
| 232 236 | 
             
                    meta_def += "\n" + ("AND" if has_where else "WHERE") + " "
         | 
| 233 237 | 
             
                    has_where = True
         | 
| 234 238 | 
             
                    if begin_da:
         | 
| 235 | 
            -
                        meta_def += f"{definition_dt_name} | 
| 239 | 
            +
                        meta_def += f"\n    {definition_dt_name}\n    >=\n    {begin_da}\n"
         | 
| 236 240 | 
             
                    if begin_da and end_da:
         | 
| 237 | 
            -
                        meta_def += " | 
| 241 | 
            +
                        meta_def += "    AND"
         | 
| 238 242 | 
             
                    if end_da:
         | 
| 239 | 
            -
                        meta_def += f"{definition_dt_name} | 
| 243 | 
            +
                        meta_def += f"\n    {definition_dt_name}\n    <\n    {end_da}\n"
         | 
| 240 244 |  | 
| 241 245 | 
             
                if params is not None:
         | 
| 242 246 | 
             
                    params_where = build_where(params, self, with_where=False)
         | 
| 243 | 
            -
                    meta_def += "\n" + ("AND" if has_where else "WHERE") + " | 
| 247 | 
            +
                    meta_def += "\n    " + ("AND" if has_where else "WHERE") + "    "
         | 
| 244 248 | 
             
                    has_where = True
         | 
| 245 249 | 
             
                    meta_def += params_where
         | 
| 246 250 |  | 
| 247 | 
            -
                return meta_def
         | 
| 251 | 
            +
                return meta_def.rstrip()
         | 
| 248 252 |  | 
| 249 253 |  | 
| 250 254 | 
             
            def get_pipe_query(pipe: mrsm.Pipe, warn: bool = True) -> Union[str, None]:
         | 
| @@ -256,7 +260,11 @@ def get_pipe_query(pipe: mrsm.Pipe, warn: bool = True) -> Union[str, None]: | |
| 256 260 | 
             
                - query
         | 
| 257 261 | 
             
                - sql
         | 
| 258 262 | 
             
                """
         | 
| 263 | 
            +
                import re
         | 
| 264 | 
            +
                import textwrap
         | 
| 259 265 | 
             
                from meerschaum.utils.warnings import warn as _warn
         | 
| 266 | 
            +
                from meerschaum.utils.misc import parse_arguments_str
         | 
| 267 | 
            +
                from meerschaum.utils.sql import sql_item_name
         | 
| 260 268 | 
             
                if pipe.parameters.get('fetch', {}).get('definition', None):
         | 
| 261 269 | 
             
                    definition = pipe.parameters['fetch']['definition']
         | 
| 262 270 | 
             
                elif pipe.parameters.get('definition', None):
         | 
| @@ -272,7 +280,23 @@ def get_pipe_query(pipe: mrsm.Pipe, warn: bool = True) -> Union[str, None]: | |
| 272 280 | 
             
                            + "    Set the key `query` in `pipe.parameters` to a valid SQL query."
         | 
| 273 281 | 
             
                        )
         | 
| 274 282 | 
             
                    return None
         | 
| 275 | 
            -
             | 
| 283 | 
            +
             | 
| 284 | 
            +
                def replace_pipe_match(pipe_match):
         | 
| 285 | 
            +
                    try:
         | 
| 286 | 
            +
                        args_str = pipe_match.group(1)
         | 
| 287 | 
            +
                        args, kwargs = parse_arguments_str(args_str)
         | 
| 288 | 
            +
                        pipe = mrsm.Pipe(*args, **kwargs)
         | 
| 289 | 
            +
                    except Exception as e:
         | 
| 290 | 
            +
                        if warn:
         | 
| 291 | 
            +
                            _warn(f"Failed to parse pipe from SQL definition:\n{e}")
         | 
| 292 | 
            +
                        raise e
         | 
| 293 | 
            +
             | 
| 294 | 
            +
                    target = pipe.target
         | 
| 295 | 
            +
                    schema = pipe.instance_connector.get_pipe_schema(pipe)
         | 
| 296 | 
            +
                    return sql_item_name(target, pipe.instance_connector.flavor, schema)
         | 
| 297 | 
            +
             | 
| 298 | 
            +
                definition = re.sub(r'\{\{Pipe\((.*?)\)\}\}', replace_pipe_match, definition)
         | 
| 299 | 
            +
                return textwrap.dedent(definition.lstrip().rstrip())
         | 
| 276 300 |  | 
| 277 301 |  | 
| 278 302 | 
             
            def set_pipe_query(pipe: mrsm.Pipe, query: str) -> None:
         | 
| @@ -331,11 +355,7 @@ def _join_fetch_query( | |
| 331 355 | 
             
                pipe_instance_name = sql_item_name(
         | 
| 332 356 | 
             
                    pipe.target, pipe.instance_connector.flavor, pipe.instance_connector.schema
         | 
| 333 357 | 
             
                )
         | 
| 334 | 
            -
                #  pipe_remote_name = sql_item_name(pipe.target, pipe.connector.flavor)
         | 
| 335 358 | 
             
                sync_times_table = pipe.target + "_sync_times"
         | 
| 336 | 
            -
                sync_times_instance_name = sql_item_name(
         | 
| 337 | 
            -
                    sync_times_table, pipe.instance_connector.flavor, None
         | 
| 338 | 
            -
                )
         | 
| 339 359 | 
             
                sync_times_remote_name = sql_item_name(
         | 
| 340 360 | 
             
                    sync_times_table, pipe.connector.flavor, None
         | 
| 341 361 | 
             
                )
         | 
| @@ -393,4 +413,3 @@ def _join_fetch_query( | |
| 393 413 | 
             
                WHERE definition.{dt_remote_name} > st.{dt_remote_name}
         | 
| 394 414 | 
             
                """ + (f"  OR st.{id_remote_name} IS NULL" if new_ids else "")
         | 
| 395 415 | 
             
                return query
         | 
| 396 | 
            -
             | 
| @@ -96,15 +96,15 @@ def _drop_temporary_tables(self, debug: bool = False) -> SuccessTuple: | |
| 96 96 | 
             
                    sqlalchemy.select(temp_tables_table.c.table)
         | 
| 97 97 | 
             
                    .where(temp_tables_table.c.ready_to_drop.is_not(None))
         | 
| 98 98 | 
             
                )
         | 
| 99 | 
            -
                tables_to_drop =  | 
| 99 | 
            +
                tables_to_drop = {
         | 
| 100 100 | 
             
                    table
         | 
| 101 101 | 
             
                    for table, ready_to_drop in _in_memory_temp_tables.items()
         | 
| 102 102 | 
             
                    if ready_to_drop
         | 
| 103 | 
            -
                 | 
| 103 | 
            +
                }
         | 
| 104 104 | 
             
                if not tables_to_drop:
         | 
| 105 105 | 
             
                    df = self.read(query, silent=True, debug=debug)
         | 
| 106 106 | 
             
                    tables_to_drop = (
         | 
| 107 | 
            -
                         | 
| 107 | 
            +
                        set(df['table'])
         | 
| 108 108 | 
             
                        if df is not None
         | 
| 109 109 | 
             
                        else []
         | 
| 110 110 | 
             
                    )
         | 
| @@ -126,7 +126,7 @@ def _drop_temporary_tables(self, debug: bool = False) -> SuccessTuple: | |
| 126 126 | 
             
                        sqlalchemy.delete(temp_tables_table)
         | 
| 127 127 | 
             
                        .where(temp_tables_table.c.table.in_(dropped_tables))
         | 
| 128 128 | 
             
                    )
         | 
| 129 | 
            -
                     | 
| 129 | 
            +
                    _ = self.exec(delete_query, silent=True, debug=debug)
         | 
| 130 130 |  | 
| 131 131 | 
             
                success = len(failed_tables) == 0
         | 
| 132 132 | 
             
                msg = (
         |