From cd013cf77d940c2f2268f7e63a63a374979b4b0c Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sat, 11 Jan 2025 09:18:52 -0600 Subject: [PATCH 01/11] set up github workflows --- .github/workflows/release-python.yml | 2 -- .github/workflows/test-python.yml | 47 ++++++++++++++++++++++++++++ .github/workflows/zizmor.yml | 32 +++++++++++++++++++ azure-pipelines.yml | 40 ----------------------- 4 files changed, 79 insertions(+), 42 deletions(-) create mode 100644 .github/workflows/test-python.yml create mode 100644 .github/workflows/zizmor.yml delete mode 100644 azure-pipelines.yml diff --git a/.github/workflows/release-python.yml b/.github/workflows/release-python.yml index c2ccec6..9de5690 100644 --- a/.github/workflows/release-python.yml +++ b/.github/workflows/release-python.yml @@ -62,5 +62,3 @@ jobs: path: dist/ - name: Publish distribution 📦 to PyPI uses: pypa/gh-action-pypi-publish@release/v1 - with: - repository-url: https://test.pypi.org/legacy/ diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml new file mode 100644 index 0000000..88b2d7c --- /dev/null +++ b/.github/workflows/test-python.yml @@ -0,0 +1,47 @@ +name: Python Tests + +on: + push: + branches: ["main"] + pull_request: + +concurrency: + group: tests-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -eux {0} + +jobs: + build: + # supercharge/mongodb-github-action requires containers so we don't test other platforms + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: ["ubuntu-latest", "macos-latest", "windows-latest"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + fail-fast: false + name: CPython ${{ matrix.python-version }}-${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: "Create MongoDB Replica Set" + run: | + docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest --detach mongo:latest mongod --replSet rs --setParameter transactionLifetimeLimitSeconds=5 + until docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do + sleep 1 + done + sudo docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "rs.initiate({\"_id\":\"rs\",\"members\":[{\"_id\":0,\"host\":\"127.0.0.1:27017\" }]})" + - name: Install package and pytest + run: | + python -m pip install . + python -m pip install pytest + - name: Run the tests + run: | + pytest . \ No newline at end of file diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml new file mode 100644 index 0000000..0fbdbd6 --- /dev/null +++ b/.github/workflows/zizmor.yml @@ -0,0 +1,32 @@ +name: GitHub Actions Security Analysis with zizmor + +on: + push: + branches: ["main"] + pull_request: + branches: ["**"] + +jobs: + zizmor: + name: zizmor latest via Cargo + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Setup Rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + - name: Get zizmor + run: cargo install zizmor + - name: Run zizmor + run: zizmor --format sarif . > results.sarif + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Upload SARIF file + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: results.sarif + category: zizmor diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index f4826ce..0000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,40 +0,0 @@ -jobs: -- job: 'Style' - pool: - vmImage: 'ubuntu-latest' - steps: - - task: UsePythonVersion@0 - inputs: - versionSpec: '3.9' - architecture: 'x64' - - script: | - pip install tox - tox -e style - displayName: 'tox -e style' - -- job: 'Test' - pool: - vmImage: 'ubuntu-latest' - strategy: - matrix: - Python38: - python.version: '3.8' - Python39: - python.version: '3.9' - Python310: - python.version: '3.10' - Python311: - python.version: '3.11' - maxParallel: 4 - - steps: - - task: UsePythonVersion@0 - inputs: - versionSpec: '$(python.version)' - architecture: 'x64' - - - script: | - pip install wheel - pip install tox tox-docker - tox - displayName: 'tox' From 1d702d851a6b3914eab0fb91da62fe65d05aab46 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sat, 11 Jan 2025 09:22:24 -0600 Subject: [PATCH 02/11] try podman --- .github/workflows/test-python.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index 88b2d7c..f49b48b 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -33,11 +33,11 @@ jobs: python-version: ${{ matrix.python-version }} - name: "Create MongoDB Replica Set" run: | - docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest --detach mongo:latest mongod --replSet rs --setParameter transactionLifetimeLimitSeconds=5 - until docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do + podman run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest --detach mongo:latest mongod --replSet rs --setParameter transactionLifetimeLimitSeconds=5 + until podman exec --tty mongodb mongosh 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do sleep 1 done - sudo docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "rs.initiate({\"_id\":\"rs\",\"members\":[{\"_id\":0,\"host\":\"127.0.0.1:27017\" }]})" + sudo podman exec --tty mongodb mongosh 127.0.0.1:27017 --eval "rs.initiate({\"_id\":\"rs\",\"members\":[{\"_id\":0,\"host\":\"127.0.0.1:27017\" }]})" - name: Install package and pytest run: | python -m pip install . From 18685e8c519eebe66d44c0b30165e99c53480505 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sat, 11 Jan 2025 09:31:16 -0600 Subject: [PATCH 03/11] try this approach --- .github/workflows/test-python.yml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index f49b48b..d5f98e9 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -27,17 +27,23 @@ jobs: - uses: actions/checkout@v4 with: persist-credentials: false + fetch-tags: true - name: Setup Python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - name: "Create MongoDB Replica Set" + - name: Start MongoDB on Linux and Windows + if: ${{ ! startsWith(runner.os, 'macOS') }} + uses: supercharge/mongodb-github-action@1.11.0 + with: + mongodb-version: 8.0 + mongodb-replica-set: test-rs + - name: Start MongoDB on MacOS + if: ${{ startsWith(runner.os, 'macOS') }} run: | - podman run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest --detach mongo:latest mongod --replSet rs --setParameter transactionLifetimeLimitSeconds=5 - until podman exec --tty mongodb mongosh 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do - sleep 1 - done - sudo podman exec --tty mongodb mongosh 127.0.0.1:27017 --eval "rs.initiate({\"_id\":\"rs\",\"members\":[{\"_id\":0,\"host\":\"127.0.0.1:27017\" }]})" + brew tap mongodb/brew + brew install mongodb-community@8.0 + brew services start mongodb-community@8.0 - name: Install package and pytest run: | python -m pip install . From bc540e34717be11900ca7fa079404aa6660c79a9 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sat, 11 Jan 2025 09:37:00 -0600 Subject: [PATCH 04/11] try this approach --- .github/workflows/test-python.yml | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index d5f98e9..c265efe 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -13,9 +13,11 @@ defaults: run: shell: bash -eux {0} +env: + MONGODB_VERSION: 8.0 + jobs: build: - # supercharge/mongodb-github-action requires containers so we don't test other platforms runs-on: ${{ matrix.os }} strategy: matrix: @@ -27,23 +29,25 @@ jobs: - uses: actions/checkout@v4 with: persist-credentials: false - fetch-tags: true + fetch-depth: 0 - name: Setup Python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Start MongoDB on Linux and Windows - if: ${{ ! startsWith(runner.os, 'macOS') }} - uses: supercharge/mongodb-github-action@1.11.0 - with: - mongodb-version: 8.0 - mongodb-replica-set: test-rs + if: ${{ !startsWith(runner.os, 'macOS') }} + run: | + docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest --detach mongo:${MONGODB_VERSION} mongod --replSet rs --setParameter transactionLifetimeLimitSeconds=5 + until docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do + sleep 1 + done + sudo docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "rs.initiate({\"_id\":\"rs\",\"members\":[{\"_id\":0,\"host\":\"127.0.0.1:27017\" }]})" - name: Start MongoDB on MacOS if: ${{ startsWith(runner.os, 'macOS') }} run: | brew tap mongodb/brew - brew install mongodb-community@8.0 - brew services start mongodb-community@8.0 + brew install mongodb-community@${MONGODB_VERSION} + brew services start mongodb-community@${MONGODB_VERSION} - name: Install package and pytest run: | python -m pip install . From c1f07293bdc0e88863dddd7bf7a52a69c13560e6 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sat, 11 Jan 2025 09:42:40 -0600 Subject: [PATCH 05/11] fixups --- .github/workflows/test-python.yml | 2 +- flask_pymongo/helpers.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index c265efe..9c8dc28 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -14,7 +14,7 @@ defaults: shell: bash -eux {0} env: - MONGODB_VERSION: 8.0 + MONGODB_VERSION: 7.0 jobs: build: diff --git a/flask_pymongo/helpers.py b/flask_pymongo/helpers.py index 617b6ed..a2111c2 100644 --- a/flask_pymongo/helpers.py +++ b/flask_pymongo/helpers.py @@ -29,7 +29,8 @@ from bson import json_util, SON from bson.errors import InvalidId from bson.objectid import ObjectId -from flask import abort, json as flask_json +from flask import abort +from json import JSONEncoder from six import iteritems, string_types from werkzeug.routing import BaseConverter import pymongo @@ -83,7 +84,7 @@ def to_url(self, value): return str(value) -class JSONEncoder(flask_json.JSONEncoder): +class JSONEncoder(JSONEncoder): """A JSON encoder that uses :mod:`bson.json_util` for MongoDB documents. From d9f84e47d22e8fb27c20ae0a84027c976d099e7d Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sat, 11 Jan 2025 09:46:48 -0600 Subject: [PATCH 06/11] fixups --- .github/workflows/test-python.yml | 2 +- flask_pymongo/tests/util.py | 30 ++---------------------------- 2 files changed, 3 insertions(+), 29 deletions(-) diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index 9c8dc28..0e01348 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -46,7 +46,7 @@ jobs: if: ${{ startsWith(runner.os, 'macOS') }} run: | brew tap mongodb/brew - brew install mongodb-community@${MONGODB_VERSION} + brew install mongodb/brew/mongodb-community@${MONGODB_VERSION} brew services start mongodb-community@${MONGODB_VERSION} - name: Install package and pytest run: | diff --git a/flask_pymongo/tests/util.py b/flask_pymongo/tests/util.py index a6e7496..b35cd9c 100644 --- a/flask_pymongo/tests/util.py +++ b/flask_pymongo/tests/util.py @@ -1,4 +1,3 @@ -import os import unittest import flask @@ -6,34 +5,8 @@ import flask_pymongo -class ToxDockerMixin(object): - """ - Sets :attr:`port` based on the env var from tox-docker, if present. - """ - - def setUp(self): - super(ToxDockerMixin, self).setUp() - - # tox-docker could be running any version; find the env - # var that looks like what tox-docker would provide, but - # fail if there are more than one - env_vars = [ - (k, v) - for k, v in os.environ.items() - if k.startswith("MONGO") and k.endswith("_TCP_PORT") - ] - - self.port = 27017 - if len(env_vars) == 1: - self.port = int(env_vars[0][1]) - else: - self.fail( - f"too many tox-docker mongo port env vars (found {len(env_vars)})", - ) - - -class FlaskRequestTest(ToxDockerMixin, unittest.TestCase): +class FlaskRequestTest(unittest.TestCase): def setUp(self): super(FlaskRequestTest, self).setUp() @@ -42,6 +15,7 @@ def setUp(self): self.app = flask.Flask("test") self.context = self.app.test_request_context("/") self.context.push() + self.port = 27017 def tearDown(self): super(FlaskRequestTest, self).tearDown() From 51d2a0de14df0c942c20cc707fd9019b89b34ce9 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sat, 11 Jan 2025 09:52:39 -0600 Subject: [PATCH 07/11] fix startup --- .github/workflows/test-python.yml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-python.yml b/.github/workflows/test-python.yml index 0e01348..1e2c168 100644 --- a/.github/workflows/test-python.yml +++ b/.github/workflows/test-python.yml @@ -14,7 +14,7 @@ defaults: shell: bash -eux {0} env: - MONGODB_VERSION: 7.0 + MONGODB_VERSION: "7.0" jobs: build: @@ -34,8 +34,8 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - name: Start MongoDB on Linux and Windows - if: ${{ !startsWith(runner.os, 'macOS') }} + - name: Start MongoDB on Linux + if: ${{ startsWith(runner.os, 'Linux') }} run: | docker run --name mongodb -p 27017:27017 -e MONGO_INITDB_DATABASE=unittest --detach mongo:${MONGODB_VERSION} mongod --replSet rs --setParameter transactionLifetimeLimitSeconds=5 until docker exec --tty mongodb mongosh 127.0.0.1:27017 --eval "db.runCommand({ ping: 1 })"; do @@ -48,6 +48,14 @@ jobs: brew tap mongodb/brew brew install mongodb/brew/mongodb-community@${MONGODB_VERSION} brew services start mongodb-community@${MONGODB_VERSION} + - name: Start MongoDB on Windows + if: ${{ startsWith(runner.os, 'Windows') }} + shell: powershell + run: | + mkdir data + mongod --remove + mongod --install --dbpath=$(pwd)/data --logpath=$PWD/mongo.log + net start MongoDB - name: Install package and pytest run: | python -m pip install . From 8a1a9b012bd063740ab6503e63acbd6407ee0b53 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sat, 11 Jan 2025 10:30:43 -0600 Subject: [PATCH 08/11] fix tests --- flask_pymongo/__init__.py | 11 +++++++++-- flask_pymongo/tests/test_gridfs.py | 13 ++----------- flask_pymongo/tests/test_wrappers.py | 13 ------------- 3 files changed, 11 insertions(+), 26 deletions(-) diff --git a/flask_pymongo/__init__.py b/flask_pymongo/__init__.py index 974202d..5406cc0 100644 --- a/flask_pymongo/__init__.py +++ b/flask_pymongo/__init__.py @@ -28,6 +28,7 @@ from functools import partial from mimetypes import guess_type +import hashlib from flask import abort, current_app, request from gridfs import GridFS, NoFile @@ -163,14 +164,20 @@ def get_upload(filename): # mostly copied from flask/helpers.py, with # modifications for GridFS data = wrap_file(request.environ, fileobj, buffer_size=1024 * 255) + content_type, _ = guess_type(filename) response = current_app.response_class( data, - mimetype=fileobj.content_type, + mimetype=content_type, direct_passthrough=True, ) response.content_length = fileobj.length response.last_modified = fileobj.upload_date - response.set_etag(fileobj.md5) + # Compute the sha1 sum of the file for the etag. + pos = fileobj.tell() + raw_data = fileobj.read() + fileobj.seek(pos) + digest = hashlib.sha1(raw_data).hexdigest() + response.set_etag(digest) response.cache_control.max_age = cache_for response.cache_control.public = True response.make_conditional(request) diff --git a/flask_pymongo/tests/test_gridfs.py b/flask_pymongo/tests/test_gridfs.py index 5dc57da..ff742c5 100644 --- a/flask_pymongo/tests/test_gridfs.py +++ b/flask_pymongo/tests/test_gridfs.py @@ -1,4 +1,4 @@ -from hashlib import md5 +from hashlib import sha1 from io import BytesIO from bson.objectid import ObjectId @@ -30,15 +30,6 @@ def test_it_saves_files(self): gridfs = GridFS(self.mongo.db) assert gridfs.exists({"filename": "my-file"}) - def test_it_guesses_type_from_filename(self): - fileobj = BytesIO(b"these are the bytes") - - self.mongo.save_file("my-file.txt", fileobj) - - gridfs = GridFS(self.mongo.db) - gridfile = gridfs.find_one({"filename": "my-file.txt"}) - assert gridfile.content_type == "text/plain" - def test_it_saves_files_with_props(self): fileobj = BytesIO(b"these are the bytes") @@ -82,7 +73,7 @@ def test_it_sets_supports_conditional_gets(self): environ_args = { "method": "GET", "headers": { - "If-None-Match": md5(self.myfile.getvalue()).hexdigest(), + "If-None-Match": sha1(self.myfile.getvalue()).hexdigest(), }, } diff --git a/flask_pymongo/tests/test_wrappers.py b/flask_pymongo/tests/test_wrappers.py index 1bb334b..537887f 100644 --- a/flask_pymongo/tests/test_wrappers.py +++ b/flask_pymongo/tests/test_wrappers.py @@ -18,16 +18,3 @@ def test_find_one_or_404(self): # now it should not raise thing = self.mongo.db.things.find_one_or_404({"_id": "thing"}) assert thing["val"] == "foo", "got wrong thing" - - # also test with dotted-named collections - self.mongo.db.things.morethings.delete_many({}) - try: - self.mongo.db.things.morethings.find_one_or_404({"_id": "thing"}) - except HTTPException as notfound: - assert notfound.code == 404, "raised wrong exception" - - self.mongo.db.things.morethings.insert_one({"_id": "thing", "val": "foo"}) - - # now it should not raise - thing = self.mongo.db.things.morethings.find_one_or_404({"_id": "thing"}) - assert thing["val"] == "foo", "got wrong thing" From c644346985e10c69165ea9085e136f9cc71f80e2 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sat, 11 Jan 2025 11:31:48 -0600 Subject: [PATCH 09/11] fix tests --- flask_pymongo/__init__.py | 6 ++--- flask_pymongo/helpers.py | 38 ++++++++++-------------------- flask_pymongo/tests/test_config.py | 4 ++-- setup.py | 2 +- 4 files changed, 18 insertions(+), 32 deletions(-) diff --git a/flask_pymongo/__init__.py b/flask_pymongo/__init__.py index 5406cc0..caf8e60 100644 --- a/flask_pymongo/__init__.py +++ b/flask_pymongo/__init__.py @@ -42,7 +42,7 @@ DriverInfo = None from flask_pymongo._version import __version__ -from flask_pymongo.helpers import BSONObjectIdConverter, JSONEncoder +from flask_pymongo.helpers import BSONObjectIdConverter, BSONProvider from flask_pymongo.wrappers import MongoClient DESCENDING = pymongo.DESCENDING @@ -69,7 +69,7 @@ class PyMongo(object): def __init__(self, app=None, uri=None, json_options=None, *args, **kwargs): self.cx = None self.db = None - self._json_encoder = partial(JSONEncoder, json_options=json_options) + self._json_provider = BSONProvider(json_options, app) if app is not None: self.init_app(app, uri, *args, **kwargs) @@ -123,7 +123,7 @@ def init_app(self, app, uri=None, *args, **kwargs): self.db = self.cx[database_name] app.url_map.converters["ObjectId"] = BSONObjectIdConverter - app.json_encoder = self._json_encoder + app.json = self._json_provider # view helpers def send_file(self, filename, base="fs", version=-1, cache_for=31536000): diff --git a/flask_pymongo/helpers.py b/flask_pymongo/helpers.py index a2111c2..b846c34 100644 --- a/flask_pymongo/helpers.py +++ b/flask_pymongo/helpers.py @@ -24,14 +24,13 @@ # POSSIBILITY OF SUCH DAMAGE. -__all__ = ("BSONObjectIdConverter", "JSONEncoder") +__all__ = ("BSONObjectIdConverter", "BSONProvider") -from bson import json_util, SON +from bson import json_util from bson.errors import InvalidId from bson.objectid import ObjectId from flask import abort -from json import JSONEncoder -from six import iteritems, string_types +from flask.json.provider import JSONProvider from werkzeug.routing import BaseConverter import pymongo @@ -84,7 +83,7 @@ def to_url(self, value): return str(value) -class JSONEncoder(JSONEncoder): +class BSONProvider(JSONProvider): """A JSON encoder that uses :mod:`bson.json_util` for MongoDB documents. @@ -121,7 +120,7 @@ def json_route(cart_id): """ - def __init__(self, json_options, *args, **kwargs): + def __init__(self, json_options, app): if json_options is None: json_options = DEFAULT_JSON_OPTIONS if json_options is not None: @@ -129,27 +128,14 @@ def __init__(self, json_options, *args, **kwargs): else: self._default_kwargs = {} - super(JSONEncoder, self).__init__(*args, **kwargs) + super().__init__(app) - def default(self, obj): + def dumps(self, obj): """Serialize MongoDB object types using :mod:`bson.json_util`. + """ + return json_util.dumps(obj) - Falls back to Flask's default JSON serialization for all other types. - - This may raise ``TypeError`` for object types not recognized. - - .. versionadded:: 2.4.0 - + def loads(self, str_obj): + """Deserialize MongoDB object types using :mod:`bson.json_util`. """ - if hasattr(obj, "iteritems") or hasattr(obj, "items"): - return SON((k, self.default(v)) for k, v in iteritems(obj)) - elif hasattr(obj, "__iter__") and not isinstance(obj, string_types): - return [self.default(v) for v in obj] - else: - try: - return json_util.default(obj, **self._default_kwargs) - except TypeError: - # PyMongo couldn't convert into a serializable object, and - # the Flask default JSONEncoder won't; so we return the - # object itself and let stdlib json handle it if possible - return obj + return json_util.loads(str_obj) \ No newline at end of file diff --git a/flask_pymongo/tests/test_config.py b/flask_pymongo/tests/test_config.py index 9da8914..f2f5e5e 100644 --- a/flask_pymongo/tests/test_config.py +++ b/flask_pymongo/tests/test_config.py @@ -44,7 +44,7 @@ def test_config_with_uri_in_flask_conf_var(self): _wait_until_connected(mongo) assert mongo.db.name == self.dbname - assert ("localhost", self.port) == mongo.cx.address + assert ("localhost", self.port) == mongo.cx.address or ("127.0.0.1", self.port) == mongo.cx.address def test_config_with_uri_passed_directly(self): uri = "mongodb://localhost:{}/{}".format(self.port, self.dbname) @@ -53,7 +53,7 @@ def test_config_with_uri_passed_directly(self): _wait_until_connected(mongo) assert mongo.db.name == self.dbname - assert ("localhost", self.port) == mongo.cx.address + assert ("localhost", self.port) == mongo.cx.address or ("127.0.0.1", self.port) == mongo.cx.address def test_it_fails_with_no_uri(self): self.app.config.pop("MONGO_URI", None) diff --git a/setup.py b/setup.py index 539c7d9..0279746 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ platforms="any", packages=find_packages(), install_requires=[ - "Flask>=1.0", + "Flask>=3.0", "PyMongo>=3.11", "six", ], From 0df9706bddbdaf3b9e8687b5f0c377a9805ec44e Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sat, 11 Jan 2025 11:36:04 -0600 Subject: [PATCH 10/11] cleanup --- README.md | 2 +- flask_pymongo/tests/test_json.py | 7 +++---- setup.py | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2ea4f8f..da9b637 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Flask-PyMongo -PyMongo support for Flask applications +PyMongo support for Flask applications. Requires `flask>=3.0` and `pymongo>=4.0` ## Quickstart diff --git a/flask_pymongo/tests/test_json.py b/flask_pymongo/tests/test_json.py index 93d179d..4f506d9 100644 --- a/flask_pymongo/tests/test_json.py +++ b/flask_pymongo/tests/test_json.py @@ -2,7 +2,6 @@ from bson import ObjectId from flask import jsonify -from six import ensure_str from flask_pymongo.tests.util import FlaskPyMongoTest @@ -11,12 +10,12 @@ class JSONTest(FlaskPyMongoTest): def test_it_encodes_json(self): resp = jsonify({"foo": "bar"}) - dumped = json.loads(ensure_str(resp.get_data())) + dumped = json.loads(resp.get_data().decode('utf-8')) self.assertEqual(dumped, {"foo": "bar"}) def test_it_handles_pymongo_types(self): resp = jsonify({"id": ObjectId("5cf29abb5167a14c9e6e12c4")}) - dumped = json.loads(ensure_str(resp.get_data())) + dumped = json.loads(resp.get_data().decode('utf-8')) self.assertEqual(dumped, {"id": {"$oid": "5cf29abb5167a14c9e6e12c4"}}) def test_it_jsonifies_a_cursor(self): @@ -25,5 +24,5 @@ def test_it_jsonifies_a_cursor(self): curs = self.mongo.db.rows.find(projection={"_id": False}).sort("foo") resp = jsonify(curs) - dumped = json.loads(ensure_str(resp.get_data())) + dumped = json.loads(resp.get_data().decode('utf-8')) self.assertEqual([{"foo": "bar"}, {"foo": "baz"}], dumped) diff --git a/setup.py b/setup.py index 0279746..4644b25 100644 --- a/setup.py +++ b/setup.py @@ -31,8 +31,7 @@ packages=find_packages(), install_requires=[ "Flask>=3.0", - "PyMongo>=3.11", - "six", + "PyMongo>=4.0", ], classifiers=[ "Environment :: Web Environment", From a44bb38d41d7e678672ff5ff625add09339d887f Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Sat, 11 Jan 2025 15:00:57 -0600 Subject: [PATCH 11/11] fix handling of json_options --- flask_pymongo/__init__.py | 4 ++-- flask_pymongo/helpers.py | 33 +++++---------------------------- 2 files changed, 7 insertions(+), 30 deletions(-) diff --git a/flask_pymongo/__init__.py b/flask_pymongo/__init__.py index caf8e60..892649c 100644 --- a/flask_pymongo/__init__.py +++ b/flask_pymongo/__init__.py @@ -66,10 +66,10 @@ class PyMongo(object): """ - def __init__(self, app=None, uri=None, json_options=None, *args, **kwargs): + def __init__(self, app=None, uri=None, *args, **kwargs): self.cx = None self.db = None - self._json_provider = BSONProvider(json_options, app) + self._json_provider = BSONProvider(app) if app is not None: self.init_app(app, uri, *args, **kwargs) diff --git a/flask_pymongo/helpers.py b/flask_pymongo/helpers.py index b846c34..8cdda23 100644 --- a/flask_pymongo/helpers.py +++ b/flask_pymongo/helpers.py @@ -33,12 +33,7 @@ from flask.json.provider import JSONProvider from werkzeug.routing import BaseConverter import pymongo - -if pymongo.version_tuple >= (3, 5, 0): - from bson.json_util import RELAXED_JSON_OPTIONS - DEFAULT_JSON_OPTIONS = RELAXED_JSON_OPTIONS -else: - DEFAULT_JSON_OPTIONS = None +from bson.json_util import RELAXED_JSON_OPTIONS def _iteritems(obj): @@ -101,32 +96,14 @@ def json_route(cart_id): differently than you expect. See :class:`~bson.json_util.JSONOptions` for details on the particular serialization that will be used. - A :class:`~flask_pymongo.helpers.JSONEncoder` is automatically + A :class:`~flask_pymongo.helpers.JSONProvider` is automatically automatically installed on the :class:`~flask_pymongo.PyMongo` instance at creation time, using - :const:`~bson.json_util.RELAXED_JSON_OPTIONS`. You can change the - :class:`~bson.json_util.JSONOptions` in use by passing - ``json_options`` to the :class:`~flask_pymongo.PyMongo` - constructor. - - .. note:: - - :class:`~bson.json_util.JSONOptions` is only supported as of - PyMongo version 3.4. For older versions of PyMongo, you will - have less control over the JSON format that results from calls - to :func:`~flask.json.jsonify`. - - .. versionadded:: 2.4.0 - + :const:`~bson.json_util.RELAXED_JSON_OPTIONS`. """ - def __init__(self, json_options, app): - if json_options is None: - json_options = DEFAULT_JSON_OPTIONS - if json_options is not None: - self._default_kwargs = {"json_options": json_options} - else: - self._default_kwargs = {} + def __init__(self, app): + self._default_kwargs = {"json_options": RELAXED_JSON_OPTIONS} super().__init__(app)