diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4dede8343..c84447013 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -244,3 +244,7 @@ The `-b` flag adds as a regex pattern to block files you do not wish to update in PyMongo. This is primarily helpful if you are implementing a new feature in PyMongo that has spec tests already implemented, or if you are attempting to validate new spec tests in PyMongo. + +## Making a Release + +Follow the [Python Driver Release Process Wiki](https://wiki.corp.mongodb.com/display/DRIVERS/Python+Driver+Release+Process). diff --git a/RELEASE.md b/RELEASE.md deleted file mode 100644 index 3c2990df0..000000000 --- a/RELEASE.md +++ /dev/null @@ -1,109 +0,0 @@ -# Some notes on PyMongo releases - -## Versioning - -We follow [semver](https://semver.org/) and [pep-0440](https://www.python.org/dev/peps/pep-0440) -for versioning. - -We shoot for a release every few months - that will generally just -increment the middle / minor version number (e.g. `3.5.0` -> `3.6.0`). - -Patch releases are reserved for bug fixes (in general no new features or -deprecations) - they only happen in cases where there is a critical bug -in a recently released version, or when a release has no new features or -API changes. - -In between releases we add `.devN` to the version number to denote the -version under development. So if we just released `3.6.0`, then the -current dev version might be `3.6.1.dev0` or `3.7.0.dev0`. When we make the -next release we replace all instances of `3.x.x.devN` in the docs with the -new version number. - -## Deprecation - -Changes should be backwards compatible unless absolutely necessary. When -making API changes the approach is generally to add a deprecation -warning but keeping the existing API functional. Deprecated features can -be removed in a release that changes the major version number. - -## Doing a Release - -1. PyMongo is tested on Evergreen. Ensure the latest commit are passing - [CI](https://spruce.mongodb.com/commits/mongo-python-driver) as expected. - -2. Check Jira to ensure all the tickets in this version have been - completed. - -3. Make a PR that adds the release notes to `doc/changelog.rst`. Generally just - summarize/clarify the git log, but you might add some more long form - notes for big changes. - -4. Merge the PR. - -5. Clone the source repository in a temporary directory and check out the - release branch. - -6. Update the version number in `pymongo/_version.py`. - -7. Commit the change, e.g. `git add . && git commit -m "BUMP "` - -7. Tag w/ version_number, eg, - `git tag -a '4.1.0' -m 'BUMP 4.1.0'`. - -8. Bump the version number to `.dev0` in - `pymongo/_version.py`, commit, push. - -9. Push commit / tag, eg `git push && git push --tags`. - -10. Pushing a tag will trigger the release process on GitHub Actions - that will require a member of the team to authorize the deployment. - Navigate to https://github.com/mongodb/mongo-python-driver/actions/workflows/release-python.yml - and wait for the publish to complete. - -11. Make sure the new version appears on - `https://pymongo.readthedocs.io/en/stable/`. If the new version does not show - up automatically, trigger a rebuild of "stable" on https://readthedocs.org/projects/pymongo/builds/. - -12. Publish the release version in Jira and add a description of the release, such as a the reason - or the main feature. - -13. Announce the release on the [community forum](https://www.mongodb.com/community/forums/tags/c/announcements/driver-releases/110/python) - -14. File a ticket for DOCSP highlighting changes in server version and - Python version compatibility or the lack thereof, for example https://jira.mongodb.org/browse/DOCSP-34040 - -15. Create a GitHub Release for the tag using https://github.com/mongodb/mongo-python-driver/releases/new. - The title should be "PyMongo X.Y.Z", and the description should - contain a link to the release notes on the the community forum, e.g. - "Release notes: mongodb.com/community/forums/t/pymongo-4-0-2-released/150457" - -16. Wait for automated update PR on conda-forge, e.g.: https://github.com/conda-forge/pymongo-feedstock/pull/81 - Update dependencies if needed. - - -## Doing a Bug Fix Release - -1. If it is a new branch, first create the release branch and Evergreen project. - -- Clone the source repository in a temporary location. - -- Create a branch from the tag, e.g. `git checkout -b v4.1 4.1.0`. - -- Push the branch, e.g.: `git push origin v4.6`. - -- Create a new project in Evergreen for the branch by duplicating the "Mongo Python Driver" project. - Select the option to create a JIRA ticket for S3 bucket permissions. - -- Update the "Display Name", "Branch Name", and "Identifier". - -- Attach the project to the repository. - -- Wait for the JIRA ticket to be resolved and verify S3 upload capability with a patch release on the - new project. - -2. Create a PR against the release branch. - -3. Create a release using the "Doing a Release" checklist above, ensuring that you - check out the appropriate release branch in the source checkout. - -4. Cherry-pick the changelog PR onto the `master` branch. diff --git a/bson/tz_util.py b/bson/tz_util.py index a21d3c173..4d31c04f9 100644 --- a/bson/tz_util.py +++ b/bson/tz_util.py @@ -39,6 +39,9 @@ class FixedOffset(tzinfo): def __getinitargs__(self) -> Tuple[timedelta, str]: return self.__offset, self.__name + def __repr__(self) -> str: + return f"{self.__class__.__name__}({self.__offset!r}, {self.__name!r})" + def utcoffset(self, dt: Optional[datetime]) -> timedelta: return self.__offset diff --git a/doc/changelog.rst b/doc/changelog.rst index 8d1c6f118..d80f78fe4 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -30,6 +30,7 @@ PyMongo 4.9 brings a number of improvements including: :class:`~pymongo.operations.DeleteOne`, and :class:`~pymongo.operations.DeleteMany` operations, so they can be used in the new :meth:`~pymongo.mongo_client.MongoClient.bulk_write`. +- Added :func:`repr` support to :class:`bson.tz_util.FixedOffset`. Issues Resolved ............... diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index 406ea5ec1..fa4b7d669 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -40,11 +40,7 @@ from pymongo.cursor_shared import CursorType from pymongo.errors import AutoReconnect, ConfigurationError, OperationFailure from pymongo.hello import HelloCompat from pymongo.operations import InsertOne -from pymongo.synchronous.auth_oidc import ( - OIDCCallback, - OIDCCallbackContext, - OIDCCallbackResult, -) +from pymongo.synchronous.auth_oidc import OIDCCallback, OIDCCallbackContext, OIDCCallbackResult from pymongo.uri_parser import parse_uri ROOT = Path(__file__).parent.parent.resolve() @@ -1019,6 +1015,51 @@ class TestAuthOIDCMachine(OIDCTestBase): # Close the client. client.close() + def test_4_4_speculative_authentication_should_be_ignored_on_reauthentication(self): + # Create an OIDC configured client that can listen for `SaslStart` commands. + listener = EventListener() + client = self.create_client(event_listeners=[listener]) + + # Preload the *Client Cache* with a valid access token to enforce Speculative Authentication. + client2 = self.create_client() + client2.test.test.find_one() + client.options.pool_options._credentials.cache.data = ( + client2.options.pool_options._credentials.cache.data + ) + client2.close() + self.request_called = 0 + + # Perform an `insert` operation that succeeds. + client.test.test.insert_one({}) + + # Assert that the callback was not called. + self.assertEqual(self.request_called, 0) + + # Assert there were no `SaslStart` commands executed. + assert not any( + event.command_name.lower() == "saslstart" for event in listener.started_events + ) + listener.reset() + + # Set a fail point for `insert` commands of the form: + with self.fail_point( + { + "mode": {"times": 1}, + "data": {"failCommands": ["insert"], "errorCode": 391}, + } + ): + # Perform an `insert` operation that succeeds. + client.test.test.insert_one({}) + + # Assert that the callback was called once. + self.assertEqual(self.request_called, 1) + + # Assert there were `SaslStart` commands executed. + assert any(event.command_name.lower() == "saslstart" for event in listener.started_events) + + # Close the client. + client.close() + def test_5_1_azure_with_no_username(self): if ENVIRON != "azure": raise unittest.SkipTest("Test is only supported on Azure") diff --git a/test/test_bson.py b/test/test_bson.py index fec84090d..79a7fa061 100644 --- a/test/test_bson.py +++ b/test/test_bson.py @@ -1019,6 +1019,10 @@ class TestCodecOptions(unittest.TestCase): tz = FixedOffset(42, "forty-two") self.assertRaises(ValueError, CodecOptions, tzinfo=tz) self.assertEqual(tz, CodecOptions(tz_aware=True, tzinfo=tz).tzinfo) + self.assertEqual(repr(tz), "FixedOffset(datetime.timedelta(seconds=2520), 'forty-two')") + self.assertEqual( + repr(eval(repr(tz))), "FixedOffset(datetime.timedelta(seconds=2520), 'forty-two')" + ) def test_codec_options_repr(self): r = (