diff options
author | Tom Ritchford <tom@swirly.com> | 2021-12-05 13:27:45 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2021-12-06 16:57:02 -0500 |
commit | 924cc31975f8874d369db6599575e361bdb34be9 (patch) | |
tree | 210f4f3ed66439bea14a767acfd436cc49ac665f | |
parent | 995fb577a64061a9cbab62b481c65a4c4d3e5a67 (diff) | |
download | sqlalchemy-924cc31975f8874d369db6599575e361bdb34be9.tar.gz |
Add __copy__, __deepcopy__ to URL. Fixes: #7400
Added support for ``copy()`` and ``deepcopy()`` to the :class:`_url.URL`
class. Pull request courtesy Tom Ritchford.
Fixes: #7400
Closes: #7401
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/7401
Pull-request-sha: a2c1b8992f5d153c6210178cda47b8ae96b91fb5
Change-Id: I55977338b2655a7d4f733ae786d31e589185e9ca
-rw-r--r-- | doc/build/changelog/unreleased_14/7400.rst | 6 | ||||
-rw-r--r-- | lib/sqlalchemy/engine/url.py | 16 | ||||
-rw-r--r-- | test/engine/test_parseconnect.py | 32 |
3 files changed, 54 insertions, 0 deletions
diff --git a/doc/build/changelog/unreleased_14/7400.rst b/doc/build/changelog/unreleased_14/7400.rst new file mode 100644 index 000000000..799b3b9a3 --- /dev/null +++ b/doc/build/changelog/unreleased_14/7400.rst @@ -0,0 +1,6 @@ +.. change:: + :tags: usecase, engine + :tickets: 7400 + + Added support for ``copy()`` and ``deepcopy()`` to the :class:`_url.URL` + class. Pull request courtesy Tom Ritchford. diff --git a/lib/sqlalchemy/engine/url.py b/lib/sqlalchemy/engine/url.py index 7cdf25c21..778d2112f 100644 --- a/lib/sqlalchemy/engine/url.py +++ b/lib/sqlalchemy/engine/url.py @@ -560,6 +560,22 @@ class URL( def __repr__(self): return self.render_as_string() + def __copy__(self): + return self.__class__.create( + self.drivername, + self.username, + self.password, + self.host, + self.port, + self.database, + # note this is an immutabledict of str-> str / tuple of str, + # also fully immutable. does not require deepcopy + self.query, + ) + + def __deepcopy__(self, memo): + return self.__copy__() + def __hash__(self): return hash(str(self)) diff --git a/test/engine/test_parseconnect.py b/test/engine/test_parseconnect.py index f12d32d5d..19fce5c18 100644 --- a/test/engine/test_parseconnect.py +++ b/test/engine/test_parseconnect.py @@ -1,3 +1,4 @@ +import copy from unittest.mock import call from unittest.mock import MagicMock from unittest.mock import Mock @@ -18,6 +19,7 @@ from sqlalchemy.testing import eq_ from sqlalchemy.testing import fixtures from sqlalchemy.testing import is_ from sqlalchemy.testing import is_false +from sqlalchemy.testing import is_not from sqlalchemy.testing import is_true from sqlalchemy.testing import mock from sqlalchemy.testing import ne_ @@ -196,6 +198,25 @@ class URLTest(fixtures.TestBase): is_true(url1 != url3) is_false(url1 == url3) + def test_copy(self): + url1 = url.make_url( + "dialect://user:pass@host/db?arg1%3D=param1&arg2=param+2" + ) + url2 = copy.copy(url1) + eq_(url1, url2) + is_not(url1, url2) + + def test_deepcopy(self): + url1 = url.make_url( + "dialect://user:pass@host/db?arg1%3D=param1&arg2=param+2" + ) + url2 = copy.deepcopy(url1) + eq_(url1, url2) + is_not(url1, url2) + is_not(url1.query, url2.query) # immutabledict of immutable k/v, + # but it copies it on constructor + # in any case if params are present + @testing.combinations( "drivername", "username", @@ -243,6 +264,17 @@ class URLTest(fixtures.TestBase): ) @testing.combinations( + "drivername://", + "drivername://?foo=bar", + "drivername://?foo=bar&foo=bat", + ) + def test_query_dict_immutable(self, urlstr): + url_obj = url.make_url(urlstr) + + with expect_raises_message(TypeError, ".*immutable"): + url_obj.query["foo"] = "hoho" + + @testing.combinations( ( "foo1=bar1&foo2=bar2", "foo2=bar22&foo3=bar3", |