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

MOTOR-689: Add async wrapper for pymongo.encryption.ClientEncryption #103

Merged
merged 44 commits into from Mar 31, 2021

Conversation

guanlinzhou
Copy link
Contributor

Add AsyncIOMotorClientEncryption class as a wrapper for Explicit Client Encryption

oops branch was named wrong

motor/motor_asyncio.py Outdated Show resolved Hide resolved
motor/core.py Show resolved Hide resolved
motor/motor_asyncio.py Show resolved Hide resolved
Copy link
Member

@ShaneHarvey ShaneHarvey left a comment

Choose a reason for hiding this comment

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

Could you add some tests for the new class? It doesn't have to be as extensive as PyMongo's tests but we should at least see that create_data_key, encrypt, and decrypt work as expected.

motor/core.py Outdated Show resolved Hide resolved
motor/core.py Outdated Show resolved Hide resolved
@guanlinzhou
Copy link
Contributor Author

Could you add some tests for the new class? It doesn't have to be as extensive as PyMongo's tests but we should at least see that create_data_key, encrypt, and decrypt work as expected.

I think @prashantmital mentioned that we would discuss this tomorrow so I'm leaving this alone for today

Copy link
Contributor

@prashantmital prashantmital left a comment

Choose a reason for hiding this comment

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

Great work so far!

For testing the gold standard would be to port the tests from https://github.com/mongodb/mongo-python-driver/blob/0752280adaa69b3cd80fabdf96aac31a26af826f/test/test_encryption.py#L310 in Motor. There don't seem to be too many tests so I think we can really just port over all of them, but my mind isn't made up in this regard.

@guanlinzhou
Copy link
Contributor Author

Ok I'll work on porting those tests over

Copy link
Contributor

@prashantmital prashantmital left a comment

Choose a reason for hiding this comment

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

We need to update the Evergreen matrix to be able to run CSFLE tests. We can discuss offline how to do this.

Edit: on second thought, I think we also need to add an optional extra for encryption to the motor setup.py like we do for pymongo: https://github.com/mongodb/mongo-python-driver/blob/master/setup.py#L285

motor/core.py Show resolved Hide resolved
motor/core.py Outdated Show resolved Hide resolved
motor/docstrings.py Outdated Show resolved Hide resolved
motor/docstrings.py Outdated Show resolved Hide resolved
test/asyncio_tests/test_asyncio_encryption.py Show resolved Hide resolved
test/asyncio_tests/test_asyncio_encryption.py Show resolved Hide resolved
Copy link
Contributor

@prashantmital prashantmital left a comment

Choose a reason for hiding this comment

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

Great job getting this far, but I think we might have over-engineered this. I recommend rolling back the changes you made to mimic PyMongo's CSFLE testing setup and using tox to do the same thing instead.

Tox supports installation of 'extras' - https://tox.readthedocs.io/en/latest/config.html#conf-extras
This means we can simply update the [testenv] section to include:

[testenv]
extras =
    encryption

and this will essentially install Motor as pip install -e .[encryption] which is exactly what we need. AFAICT there is no way to conditionally do this based on whether an environment variable is defined so it will be an all-or-nothing kind of deal (unless we do something funky like dynamically generating tox.ini which I don't think is a good idea).

setup.py Outdated Show resolved Hide resolved
setup.py Outdated Show resolved Hide resolved
motor/docstrings.py Outdated Show resolved Hide resolved
.evergreen/config.yml Outdated Show resolved Hide resolved
.evergreen/run-tox.sh Outdated Show resolved Hide resolved
@guanlinzhou
Copy link
Contributor Author

Great job getting this far, but I think we might have over-engineered this. I recommend rolling back the changes you made to mimic PyMongo's CSFLE testing setup and using tox to do the same thing instead.

Tox supports installation of 'extras' - https://tox.readthedocs.io/en/latest/config.html#conf-extras
This means we can simply update the [testenv] section to include:

[testenv]
extras =
    encryption

and this will essentially install Motor as pip install -e .[encryption] which is exactly what we need. AFAICT there is no way to conditionally do this based on whether an environment variable is defined so it will be an all-or-nothing kind of deal (unless we do something funky like dynamically generating tox.ini which I don't think is a good idea).

Thanks! This is a good point - I was curious about how much I should be actually trying to granularly test this file instead of just running every setup with these tests.

Copy link
Contributor

@prashantmital prashantmital left a comment

Choose a reason for hiding this comment

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

LGTM other than the one minor change to .travis.yml

.travis.yml Outdated Show resolved Hide resolved
Copy link
Contributor

@prashantmital prashantmital left a comment

Choose a reason for hiding this comment

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

Actually, can you also update the CSFLE doc to properly state how to get started with motor + encryption using the extra intall syntax -
https://github.com/mongodb/motor/blob/master/doc/examples/encryption.rst#dependencies

Something like

To get started using client-side field level encryption in your project, you will need to install the pymongocrypt library as well as the driver itself. Install both the driver and a compatible version of pymongocrypt like this:

$ python -m pip install 'motor[encryption]'

Copy link
Member

@ShaneHarvey ShaneHarvey left a comment

Choose a reason for hiding this comment

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

Great work!

.travis.yml Outdated Show resolved Hide resolved
motor/core.py Outdated Show resolved Hide resolved
motor/docstrings.py Outdated Show resolved Hide resolved
motor/docstrings.py Outdated Show resolved Hide resolved
motor/docstrings.py Outdated Show resolved Hide resolved
setup.py Outdated
@@ -33,6 +33,10 @@

tests_require = ['mockupdb>=1.4.0']

extras_require = {
'encryption': ['pymongo[encryption]>=3.11,<4'],
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to add the >=3.11,<4 here? I would hope that the version reqs are added transitively from pymongo in install_requires.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@prashantmital thoughts on this?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think extras are applied on top of (i.e. after) install_requiries so we would probably need this. I'll run a quick test and get back to you.

Copy link
Contributor

Choose a reason for hiding this comment

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

With a setup.py that looks like:

setup(
    name='mypackage',
    version='0.1.0',
    packages=find_packages(),
    ext_modules=get_extension_modules(),
    install_requires=['pymongo==3.10'],
    extras_require={'foo': ['pymongo[srv]']},
)

installing the package has a rather strange output log:

➜   pip install -e '.[foo]'
Obtaining file:///Users/pmital/Developer/playgrounds/python-packaging
Collecting pymongo==3.10
  Downloading pymongo-3.10.0-cp37-cp37m-macosx_10_9_x86_64.whl (350 kB)
     |████████████████████████████████| 350 kB 1.6 MB/s 
Collecting pymongo[srv]
  Using cached pymongo-3.11.3-cp37-cp37m-macosx_10_6_intel.whl (414 kB)
  Downloading pymongo-3.11.2-cp37-cp37m-macosx_10_6_intel.whl (414 kB)
     |████████████████████████████████| 414 kB 1.7 MB/s 
  Downloading pymongo-3.11.1-cp37-cp37m-macosx_10_6_intel.whl (414 kB)
     |████████████████████████████████| 414 kB 2.6 MB/s 
  Downloading pymongo-3.11.0-cp37-cp37m-macosx_10_9_x86_64.whl (378 kB)
     |████████████████████████████████| 378 kB 3.2 MB/s 
  Downloading pymongo-3.10.1-cp37-cp37m-macosx_10_9_x86_64.whl (350 kB)
     |████████████████████████████████| 350 kB 3.8 MB/s 
Collecting dnspython<2.0.0,>=1.16.0
  Using cached dnspython-1.16.0-py2.py3-none-any.whl (188 kB)
Installing collected packages: pymongo, dnspython, mypackage
  Attempting uninstall: mypackage
    Found existing installation: mypackage 0.1.0
    Uninstalling mypackage-0.1.0:
      Successfully uninstalled mypackage-0.1.0
  Running setup.py develop for mypackage
Successfully installed dnspython-1.16.0 mypackage pymongo-3.10.0
➜   pip list 
Package    Version Location
---------- ------- ----------------------------------------------------
Cython     0.29.22
dnspython  1.16.0
mypackage  0.1.0   /Users/pmital/Developer/playgrounds/python-packaging
pip        21.0.1
pymongo    3.10.0
setuptools 47.1.0
wheel      0.36.2

for some reason, it downloads all the versions between 3.10 and latest but ends up only installing the one in install_requires. So @ShaneHarvey does seem to be correct in that pip honors the install_requires version. That being said, it might result in longer install times if there are a lot versions to download.

Specifying the version in extras_require eliminates the extra downloads:

➜  pip --no-cache-dir install -e '.[foo]'
Obtaining file:///Users/pmital/Developer/playgrounds/python-packaging
Collecting pymongo==3.10
  Downloading pymongo-3.10.0-cp37-cp37m-macosx_10_9_x86_64.whl (350 kB)
     |████████████████████████████████| 350 kB 2.1 MB/s 
Requirement already satisfied: dnspython<2.0.0,>=1.16.0 in /Users/pmital/.pyenv/versions/3.7.10/envs/packaging/lib/python3.7/site-packages (from pymongo==3.10->mypackage==0.1.0) (1.16.0)
Installing collected packages: pymongo, mypackage
  Running setup.py develop for mypackage
Successfully installed mypackage pymongo-3.10.0

@ShaneHarvey how would you like to proceed?

Copy link
Member

Choose a reason for hiding this comment

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

Oh well. Let's keep >=3.11,<4. We'll just need to ensure those two reqs never drift apart.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah I see your concern. Let's single-source the PyMongo dependency. Maybe something like:

pymongo_ver = ">=3.11,<4"
install_requires = ["pymongo" + pymongo_ver]
extras_require = {'encryption': ["pymongo" + "[encryption]" + pymongo_ver]}

Thoughts @ShaneHarvey ?

Copy link
Member

Choose a reason for hiding this comment

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

Yes let's do your single-source option.

Copy link
Contributor

Choose a reason for hiding this comment

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

@guanlinzhou can you implement this?

test/asyncio_tests/test_asyncio_encryption.py Outdated Show resolved Hide resolved
setup.py Outdated
@@ -33,6 +33,10 @@

tests_require = ['mockupdb>=1.4.0']

extras_require = {
'encryption': ['pymongo[encryption]>=3.11,<4'],
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah I see your concern. Let's single-source the PyMongo dependency. Maybe something like:

pymongo_ver = ">=3.11,<4"
install_requires = ["pymongo" + pymongo_ver]
extras_require = {'encryption': ["pymongo" + "[encryption]" + pymongo_ver]}

Thoughts @ShaneHarvey ?

Copy link
Contributor

@prashantmital prashantmital left a comment

Choose a reason for hiding this comment

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

LGTM after you've address the last comment.

setup.py Outdated

install_requires = ["pymongo" + pymongo_ver]

extras_require = {'encryption': ["pymongo" + "[encryption]" + pymongo_ver]}
Copy link
Contributor

Choose a reason for hiding this comment

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

I suppose this can just be
["pymongo[encryption]" + pymongo_ver]

Copy link
Member

@ShaneHarvey ShaneHarvey left a comment

Choose a reason for hiding this comment

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

Great work!

@guanlinzhou guanlinzhou merged commit 1b5a21a into mongodb:master Mar 31, 2021
@guanlinzhou guanlinzhou deleted the PYTHON-689 branch March 31, 2021 22:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants