Skip to content

Commit 521cc5d

Browse files
committed
Merge branch 'main' of github.com:mongodb-labs/flask-pymongo into INTPYTHON-380-finishing
2 parents 188ab5c + 5436690 commit 521cc5d

File tree

10 files changed

+50
-172
lines changed

10 files changed

+50
-172
lines changed

.github/workflows/test-python.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ jobs:
3333
- run: just install
3434
- run: just lint
3535
- run: just docs
36+
- run: just doctest
3637
build:
3738
runs-on: ${{ matrix.os }}
3839
strategy:

CONTRIBUTING.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ actual bugs and improvement requests.
2626
- All new features must include a test. Flask-PyMongo is tested against a
2727
matrix of all supported versions of Flask, PyMongo, and MongoDB, so tests
2828
ensure that your change works for all users.
29-
- There is also a `style` build. Please ensure your code conforms to
30-
Flask-PyMongo's style rules with `tox -e style`
3129
- Use [Sphinx](http://www.sphinx-doc.org/en/master/)-style docstrings
3230

3331
## Recommended development environment

docs/Makefile

Lines changed: 0 additions & 153 deletions
This file was deleted.

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
# Add any Sphinx extension module names here, as strings. They can be extensions
3232
# coming with Sphinx (named "sphinx.ext.*") or your custom ones.
33-
extensions = ["sphinx.ext.intersphinx", "sphinx.ext.autodoc"]
33+
extensions = ["sphinx.ext.intersphinx", "sphinx.ext.autodoc", "sphinx.ext.doctest"]
3434

3535
# Add any paths that contain templates here, relative to this directory.
3636
templates_path = ["_templates"]

docs/index.rst

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,8 @@ versions.
6464

6565
Flask-PyMongo is tested against `supported versions
6666
<https://www.mongodb.com/support-policy>`_ of MongoDB, and Python
67-
and 3.8+. For the exact list of version combinations that are tested and
68-
known to be compatible, see the `envlist` in `tox.ini
69-
<https://github.com/dcrosta/flask-pymongo/blob/master/tox.ini>`_.
67+
and 3.9+. For the exact list of version combinations that are tested and
68+
known to be compatible.
7069

7170

7271
Helpers
@@ -109,7 +108,7 @@ constructor. These are passed directly through to the underlying
109108
By default, Flask-PyMongo sets the ``connect`` keyword argument to
110109
``False``, to prevent PyMongo from connecting immediately. PyMongo
111110
itself `is not fork-safe
112-
<http://api.mongodb.com/python/current/faq.html#is-pymongo-fork-safe>`_,
111+
<https://www.mongodb.com/docs/languages/python/pymongo-driver/current/faq/#is-pymongo-fork-safe->`_,
113112
and delaying connection until the app is actually used is necessary to
114113
avoid issues. If you wish to change this default behavior, pass
115114
``connect=True`` as a keyword argument to ``PyMongo``.

docs/requirements.txt

Lines changed: 0 additions & 2 deletions
This file was deleted.

examples/wiki/wiki.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,4 @@ def save_upload(filename: str) -> str | Response:
8989

9090

9191
if __name__ == "__main__":
92-
import doctest
93-
94-
doctest.testmod()
9592
app.run(debug=True)

flask_pymongo/__init__.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def init_app(self, app: Flask, uri: str | None = None, *args: Any, **kwargs: Any
109109
database_name = parsed_uri["database"]
110110

111111
# Try to delay connecting, in case the app is loaded before forking, per
112-
# http://api.mongodb.com/python/current/faq.html#is-pymongo-fork-safe
112+
# https://www.mongodb.com/docs/languages/python/pymongo-driver/current/faq/#is-pymongo-fork-safe-
113113
kwargs.setdefault("connect", False)
114114
if DriverInfo is not None:
115115
kwargs.setdefault("driver", DriverInfo("Flask-PyMongo", __version__))
@@ -123,7 +123,12 @@ def init_app(self, app: Flask, uri: str | None = None, *args: Any, **kwargs: Any
123123

124124
# view helpers
125125
def send_file(
126-
self, filename: str, base: str = "fs", version: int = -1, cache_for: int = 31536000
126+
self,
127+
filename: str,
128+
base: str = "fs",
129+
version: int = -1,
130+
cache_for: int = 31536000,
131+
db: str | None = None,
127132
) -> Response:
128133
"""Respond with a file from GridFS.
129134
@@ -144,6 +149,7 @@ def get_upload(filename):
144149
revision. If no such version exists, return with HTTP status 404.
145150
:param int cache_for: number of seconds that browsers should be
146151
instructed to cache responses
152+
:param str db: the target database, if different from the default database.
147153
"""
148154
if not isinstance(base, str):
149155
raise TypeError("'base' must be string or unicode")
@@ -152,8 +158,13 @@ def get_upload(filename):
152158
if not isinstance(cache_for, int):
153159
raise TypeError("'cache_for' must be an integer")
154160

155-
assert self.db is not None, "Please initialize the app before calling send_file!"
156-
storage = GridFS(self.db, base)
161+
if db:
162+
db_obj = self.cx[db]
163+
else:
164+
db_obj = self.db
165+
166+
assert db_obj is not None, "Please initialize the app before calling send_file!"
167+
storage = GridFS(db_obj, base)
157168

158169
try:
159170
fileobj = storage.get_version(filename=filename, version=version)
@@ -189,6 +200,7 @@ def save_file(
189200
fileobj: Any,
190201
base: str = "fs",
191202
content_type: str | None = None,
203+
db: str | None = None,
192204
**kwargs: Any,
193205
) -> Any:
194206
"""Save a file-like object to GridFS using the given filename.
@@ -207,6 +219,7 @@ def save_upload(filename):
207219
:param str content_type: the MIME content-type of the file. If
208220
``None``, the content-type is guessed from the filename using
209221
:func:`~mimetypes.guess_type`
222+
:param str db: the target database, if different from the default database.
210223
:param kwargs: extra attributes to be stored in the file's document,
211224
passed directly to :meth:`gridfs.GridFS.put`
212225
"""
@@ -218,7 +231,11 @@ def save_upload(filename):
218231
if content_type is None:
219232
content_type, _ = guess_type(filename)
220233

221-
assert self.db is not None, "Please initialize the app before calling save_file!"
222-
storage = GridFS(self.db, base)
234+
if db:
235+
db_obj = self.cx[db]
236+
else:
237+
db_obj = self.db
238+
assert db_obj is not None, "Please initialize the app before calling save_file!"
239+
storage = GridFS(db_obj, base)
223240
id = storage.put(fileobj, filename=filename, content_type=content_type, **kwargs)
224241
return id

justfile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
docs_build := "docs/_build"
2+
sphinx_opts:= "-d " + docs_build + "/doctrees docs"
3+
14
# Default target executed when no arguments are given.
25
[private]
36
default:
@@ -14,7 +17,12 @@ lint:
1417
uv run pre-commit run --hook-stage manual --all-files
1518

1619
docs:
17-
uv run sphinx-build -T -b html docs docs/_build
20+
uv run sphinx-build -T -b html {{sphinx_opts}} {{docs_build}}
21+
22+
doctest:
23+
uv run python -m doctest -v examples/wiki/wiki.py
24+
uv run sphinx-build -E -b doctest {{sphinx_opts}} {{docs_build}}/doctest
25+
uv run sphinx-build -b linkcheck {{sphinx_opts}} {{docs_build}}/linkcheck
1826

1927
typing:
2028
uv run mypy --install-types --non-interactive .

tests/test_gridfs.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ def test_it_saves_files(self):
3030
gridfs = GridFS(self.mongo.db)
3131
assert gridfs.exists({"filename": "my-file"})
3232

33+
def test_it_saves_files_to_another_db(self):
34+
fileobj = BytesIO(b"these are the bytes")
35+
36+
self.mongo.save_file("my-file", fileobj, db="other")
37+
assert self.mongo.db is not None
38+
gridfs = GridFS(self.mongo.cx["other"])
39+
assert gridfs.exists({"filename": "my-file"})
40+
3341
def test_it_saves_files_with_props(self):
3442
fileobj = BytesIO(b"these are the bytes")
3543

@@ -56,6 +64,7 @@ def setUp(self):
5664
# make it bigger than 1 gridfs chunk
5765
self.myfile = BytesIO(b"a" * 500 * 1024)
5866
self.mongo.save_file("myfile.txt", self.myfile)
67+
self.mongo.save_file("my_other_file.txt", self.myfile, db="other")
5968

6069
def test_it_404s_for_missing_files(self):
6170
with pytest.raises(NotFound):
@@ -65,6 +74,10 @@ def test_it_sets_content_type(self):
6574
resp = self.mongo.send_file("myfile.txt")
6675
assert resp.content_type.startswith("text/plain")
6776

77+
def test_it_sends_file_to_another_db(self):
78+
resp = self.mongo.send_file("my_other_file.txt", db="other")
79+
assert resp.content_type.startswith("text/plain")
80+
6881
def test_it_sets_content_length(self):
6982
resp = self.mongo.send_file("myfile.txt")
7083
assert resp.content_length == len(self.myfile.getvalue())

0 commit comments

Comments
 (0)