title: Python library with dynamic database library
body: <h1>A bit of background</h1>
  <p>I am writing a python library called <a href="https://gitlab.com/sagbot/resty-filter/-/tree/dev" rel="nofollow noreferrer">resty-filter</a> that helps REST api developers quickly add an option for advanced filtering. for example:<br />
  <code>GET /users?q=field(gender)=&quot;female&quot; and field(age) &gt; 50</code><br />
  This sould returns all female users over the age of 50.</p>
  <p>The library works in 3 stages</p>
  <ol>
  <li>the raw query string is parsed into python objects</li>
  <li>the parsed query is translated into a database query (<code>mongoengine</code> / <code>sqlalchemy</code> / any other database querying library)</li>
  <li>The query is added to the database call that retrieves all the users, and filters out the elements as the API user intended</li>
  </ol>
  <h1>Goal</h1>
  <p>When translating the parsed query (stage 2) I want to:</p>
  <ol>
  <li>Support translation to many formats, in order to support any database that my libraries clients desire to use</li>
  <li>Allow other developers to add support for more translation database languages without needing to alter my libraries source code</li>
  <li>Not require installation of <code>mongoengine</code> (which is required for when translating to mongoengine filter) if the user only needs to translated to an <code>sqlalchemy</code> filter (and thus only needs to install the <code>sqlalchemy</code> package)</li>
  </ol>
  <p>I really like how sqlalchemy works in that it can connect to many SQL databases, and you only need to install the package that is relevant to the database type you are using. I would like to reproduce that experience in my library.</p>
  <h1>Possible solutions so far</h1>
  <h2>Splitting each translator into a plugin</h2>
  <p>I tried to splitting each translator into a different plungin package, as described <a href="https://packaging.python.org/en/latest/guides/creating-and-discovering-plugins/#using-naming-convention" rel="nofollow noreferrer">here</a></p>
  <h3>Problem</h3>
  <p>I want my library to support mongoengine &amp; sqlalchemy translations by default (because they are popular), without the need to install another plugin library.</p>
  <h2>Dynamically importing the packages</h2>
  <p>In this approch whenever I try and run the mongoengine translator for example, I first try to import the <code>mongoengine</code> library. If I fail importing it, I throw an error that says somthing like:<br />
  <code>The mongoengine translator could not find mongoengine package, please install it</code></p>
  <h3>Problem</h3>
  <ol>
  <li>How will I make sure that the correct version of <code>mongoengine</code> package is installed? I don't want to implement code that checks the version against the supported versions, I would rather use some other built in package version manager (like pip)</li>
  <li>As soon as I import the file that imports mongoengine I would get the error, So I will need to write the translator code (Is a bunch of classes) inside a function called <code>get_translator</code>, and then import mongoengine &amp; define all the classes inside the function. This doesn't sound easy to work with in my opinion. It will look somthing like this:</li>
  </ol>
  <pre class="lang-py prettyprint-override"><code># main.py
  translation_language = 'mongoengine'
  raw_query = 'field(age) &gt; 50'
  parsed_query = parse_query(raw_query)
  
  if translation_language == 'mongoengine':
      from translators.mongoengine import get_translator
  elif translation_language == 'sqlalchemy':
      from translators.sqlalchemy import get_translator
  
  # This line will raise an exception if mongoengine is not installed
  translator = get_translator()
  </code></pre>
  <pre class="lang-py prettyprint-override"><code># translators.mongoengine
  
  def get_translator():
      import mongoengine
      
      class Translator(BaseTranslator):
          pass
      
      return Translator
  </code></pre>
  <h1>An example translator</h1>
  <p>Here is a link to the mongoengine I implemented: <a href="https://gitlab.com/sagbot/resty-filter/-/tree/dev/resty_filter/translating/mongo_translation" rel="nofollow noreferrer">https://gitlab.com/sagbot/resty-filter/-/tree/dev/resty_filter/translating/mongo_translation</a>
  Note: it does not implement any dynamic importing yet (IDK how to implement it, thats why I am writing this post...)</p>