Skip to content

New driver interface#1252

Merged
phenobarbital merged 17 commits into
masterfrom
new-drivers
Sep 9, 2024
Merged

New driver interface#1252
phenobarbital merged 17 commits into
masterfrom
new-drivers

Conversation

@phenobarbital
Copy link
Copy Markdown
Owner

@phenobarbital phenobarbital commented Sep 9, 2024

  • optimized interfaces for driver creation

Summary by Sourcery

Refactor the driver interface to introduce a new base module, enhancing code organization and readability. Implement a new driver interface with support for asynchronous context management and event loop handling. Improve error handling and add typing annotations for better type safety. Update the library version to 2.9.0.

New Features:

  • Introduce a new driver interface for managing database connections and operations, including support for asynchronous context management and event loop handling.

Enhancements:

  • Refactor driver classes to use a new base module instead of the abstract module, improving code organization and clarity.
  • Enhance the initialization of driver classes by using multi-line function signatures for better readability.
  • Improve error handling by formatting exception messages across various driver implementations.
  • Add support for typing annotations across the codebase to improve type safety and code readability.

Chores:

  • Update the version of the library to 2.9.0 to reflect the new changes and improvements.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Sep 9, 2024

Reviewer's Guide by Sourcery

This pull request introduces significant changes to the AsyncDB library, focusing on code restructuring, interface improvements, and the addition of new features. The changes aim to enhance the modularity, readability, and maintainability of the codebase.

File-Level Changes

Change Details Files
Restructured and improved interfaces
  • Created new interface files for model, abstract, cursors, connection, database, and pool
  • Moved existing interface classes to their respective new files
  • Updated import statements across the codebase to reflect the new structure
asyncdb/interfaces/model.py
asyncdb/interfaces/abstract.py
asyncdb/interfaces/cursors.py
asyncdb/interfaces/connection.py
asyncdb/interfaces/database.py
asyncdb/interfaces/pool.py
asyncdb/interfaces.py
Refactored driver implementations
  • Updated import statements to use new interface locations
  • Improved code formatting and readability
  • Implemented new abstract methods from updated interfaces
asyncdb/drivers/redis.py
asyncdb/drivers/base.py
asyncdb/drivers/memcache.py
asyncdb/drivers/pg.py
asyncdb/drivers/mysql.py
asyncdb/drivers/mysqlclient.py
asyncdb/drivers/rethink.py
asyncdb/drivers/bigquery.py
asyncdb/drivers/mongo.py
asyncdb/drivers/dummy.py
asyncdb/drivers/mredis.py
asyncdb/drivers/scylladb.py
asyncdb/drivers/cassandra.py
asyncdb/drivers/hazel.py
asyncdb/drivers/influx.py
Added new BaseCursor class
  • Created a new file for BaseCursor implementation
  • Moved BaseCursor from abstract.py to its own file
asyncdb/drivers/cursor.py
Updated version and setup configuration
  • Bumped version to 2.9.0
  • Improved formatting in setup.py
asyncdb/version.py
setup.py
Added example for checking interfaces
  • Created a new example file to demonstrate interface usage
examples/check_interfaces.py

Tips
  • Trigger a new Sourcery review by commenting @sourcery-ai review on the pull request.
  • Continue your discussion with Sourcery by replying directly to review comments.
  • You can change your review settings at any time by accessing your dashboard:
    • Enable or disable the Sourcery-generated pull request summary or reviewer's guide;
    • Change the review language;
  • You can always contact us if you have any questions or feedback.

@phenobarbital phenobarbital merged commit f545a81 into master Sep 9, 2024
@phenobarbital phenobarbital deleted the new-drivers branch September 9, 2024 20:54
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey @phenobarbital - I've reviewed your changes and they look great!

Here's what I looked at during the review
  • 🟢 General issues: all looks good
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment to tell me if it was helpful.

Comment thread asyncdb/drivers/redis.py

class redisPool(BasePool):
def __init__(self, dsn: str = "", loop: asyncio.AbstractEventLoop = None, params: dict = None, **kwargs) -> None:
def __init__(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue (complexity): Consider refactoring error handling, simplifying parameter passing, and consolidating similar methods to reduce code complexity.

While the changes provide more specific error handling, which can be beneficial for debugging, the code complexity has increased significantly. Consider the following improvements:

  1. Simplify error handling:
    Create a helper function to reduce repetition in error handling. For example:

    def handle_redis_error(error_type, message):
        if isinstance(error_type, ConnectionError):
            raise DriverError(f"Error connecting to Redis: {message}") from error_type
        elif isinstance(error_type, RedisError):
            raise DriverError(f"Redis error: {message}") from error_type
        else:
            raise DriverError(f"Unknown Redis error: {message}") from error_type
    
    # Usage in methods:
    try:
        # Redis operation
    except Exception as err:
        handle_redis_error(err, "Error on operation X")
  2. Simplify parameter unpacking:
    For methods with many parameters, consider using a configuration object or dataclass. For example:

    from dataclasses import dataclass
    
    @dataclass
    class RedisConfig:
        dsn: str = ""
        loop: asyncio.AbstractEventLoop = None
        params: dict = None
    
    class redisPool(BasePool):
        def __init__(self, config: RedisConfig, **kwargs):
            self._dsn = "redis://{host}:{port}/{db}"
            super(redisPool, self).__init__(
                dsn=config.dsn,
                loop=config.loop,
                params=config.params,
                **kwargs
            )
  3. Consolidate similar methods:
    Methods like keys and values that simply call other methods can be removed to reduce code duplication:

    async def keys(self, key):
        return await self.hkeys(key)
    
    async def values(self, key):
        return await self.hvals(key)

    Instead, use the hkeys and hvals methods directly where needed.

These changes will help reduce complexity while maintaining the improved error handling and functionality.

Comment on lines 260 to 262
args = {}
if timeout:
args = {"exptime": timeout}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion (code-quality): We've found these issues:

Suggested change
args = {}
if timeout:
args = {"exptime": timeout}
args = {"exptime": timeout} if timeout else {}

Comment thread asyncdb/drivers/redis.py
Comment on lines +120 to +124
result = await self._connection.execute_command(
sentence,
*args,
**kwargs
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)

Comment on lines +80 to +86
try:
self._loop = asyncio.get_event_loop()
asyncio.set_event_loop(self._loop)
except RuntimeError:
raise RuntimeError(
f"No Event Loop is running. Please, run this driver inside an asyncio loop."
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue (code-quality): We've found these issues:

Comment on lines +99 to +103
if not self._loop:
return True
if self._loop.is_closed():
return True
return False
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion (code-quality): We've found these issues:

Suggested change
if not self._loop:
return True
if self._loop.is_closed():
return True
return False
return True if not self._loop else bool(self._loop.is_closed())

Comment on lines +152 to +155
if params:
return self._dsn.format_map(SafeDict(**params))
else:
return None
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion (code-quality): Replace if statement with if expression (assign-if-exp)

Suggested change
if params:
return self._dsn.format_map(SafeDict(**params))
else:
return None
return self._dsn.format_map(SafeDict(**params)) if params else None

Comment on lines +115 to +118
if is_missing(value):
new_val = None
else:
new_val = value
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion (code-quality): Replace if statement with if expression (assign-if-exp)

Suggested change
if is_missing(value):
new_val = None
else:
new_val = value
new_val = None if is_missing(value) else value


def _get_attribute(self, field: Field, value: Any, attr: str = "primary_key") -> Any:
if hasattr(field, attr):
datatype = field.type
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion (code-quality): Move assignments closer to their usage (move-assign)

Suggested change
datatype = field.type
datatype = field.type

Comment on lines +154 to +155
result = f"\nWHERE {_and}"
return result
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)

Suggested change
result = f"\nWHERE {_and}"
return result
return f"\nWHERE {_and}"


def _get_condition(self, key: str, field: Field, value: Any, datatype: Any) -> str:
condition = ""
if isinstance(value, list):
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

issue (code-quality): Lift return into if (lift-return-into-if)

phenobarbital added a commit that referenced this pull request Mar 20, 2026
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.

1 participant