diff --git a/README.rst b/README.rst index 2c1abcbb..214590e0 100644 --- a/README.rst +++ b/README.rst @@ -80,7 +80,7 @@ a DuckDuckGo search: # Fill-in the search form browser.select_form('#search_form_homepage') browser["q"] = "MechanicalSoup" - browser.submit_selected() + browser.submit() # Display the results for link in browser.get_current_page().select('a.result__a'): diff --git a/docs/ChangeLog.rst b/docs/ChangeLog.rst index 4dbdc55b..bb685bd3 100644 --- a/docs/ChangeLog.rst +++ b/docs/ChangeLog.rst @@ -5,6 +5,15 @@ Release Notes Version 1.0 (in development) ============================ +Main changes: +------------- + +* **Breaking Change:** The method ``StatefulBrowser.submit_selected`` has been + renamed to :func:`StatefulBrowser.submit`. The original name remains usable + for backwards compatibility. This is a breaking change _only_ if you use the + :func:`Browser.submit` method from a ``StatefulBrowser`` instance (this is + not typical), since it is now overridden by :func:`StatefulBrowser.submit`. + Bug fixes --------- diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 58233edf..2e6ad22f 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -166,7 +166,7 @@ used to list the fields):: Assuming we're satisfied with the content of the form, we can submit it (i.e. simulate a click on the submit button):: - >>> response = browser.submit_selected() + >>> response = browser.submit() The response is not an HTML page, so the browser doesn't parse it to a BeautifulSoup object, but we can still see the text it contains:: diff --git a/examples/example.py b/examples/example.py index 0e6d2331..a057ad3e 100644 --- a/examples/example.py +++ b/examples/example.py @@ -24,7 +24,7 @@ browser.select_form('#login form') browser["login"] = args.username browser["password"] = args.password -resp = browser.submit_selected() +resp = browser.submit() # Uncomment to launch a web browser on the current page: # browser.launch_browser() diff --git a/examples/expl_duck_duck_go.py b/examples/expl_duck_duck_go.py index 800fd5d2..74ca53ee 100644 --- a/examples/expl_duck_duck_go.py +++ b/examples/expl_duck_duck_go.py @@ -10,7 +10,7 @@ # Fill-in the search form browser.select_form('#search_form_homepage') browser["q"] = "MechanicalSoup" -browser.submit_selected() +browser.submit() # Display the results for link in browser.get_current_page().select('a.result__a'): diff --git a/examples/expl_google.py b/examples/expl_google.py index 3dd99d3d..2a433990 100644 --- a/examples/expl_google.py +++ b/examples/expl_google.py @@ -10,7 +10,7 @@ browser["q"] = "MechanicalSoup" # Note: the button name is btnK in the content served to actual # browsers, but btnG for bots. -browser.submit_selected(btnName="btnG") +browser.submit(btnName="btnG") # Display links for link in browser.links(): diff --git a/examples/expl_httpbin.py b/examples/expl_httpbin.py index 7aa2cad5..9eb454ad 100644 --- a/examples/expl_httpbin.py +++ b/examples/expl_httpbin.py @@ -23,5 +23,5 @@ # Uncomment to display a summary of the filled-in form # browser.get_current_form().print_summary() -response = browser.submit_selected() +response = browser.submit() print(response.text) diff --git a/mechanicalsoup/form.py b/mechanicalsoup/form.py index f99c033c..3491fd0c 100644 --- a/mechanicalsoup/form.py +++ b/mechanicalsoup/form.py @@ -306,7 +306,7 @@ def choose_submit(self, submit): browser.open(url) form = browser.select_form() form.choose_submit('form_name_attr') - browser.submit_selected() + browser.submit() """ # Since choose_submit is destructive, it doesn't make sense to call # this method twice unless no submit is specified. diff --git a/mechanicalsoup/stateful_browser.py b/mechanicalsoup/stateful_browser.py index 0abbb996..6b250d71 100644 --- a/mechanicalsoup/stateful_browser.py +++ b/mechanicalsoup/stateful_browser.py @@ -7,6 +7,7 @@ import sys import re import bs4 +import warnings class _BrowserState: @@ -60,6 +61,10 @@ def __init__(self, *args, **kwargs): self.__verbose = 0 self.__state = _BrowserState() + # Aliases for backwards compatibility + # (Included specifically in __init__ to suppress them in Sphinx docs) + self.submit_selected = self.submit + def set_debug(self, debug): """Set the debug mode (off by default). @@ -207,7 +212,7 @@ def select_form(self, selector="form", nr=0): return self.get_current_form() - def submit_selected(self, btnName=None, *args, **kwargs): + def submit(self, btnName=None, *args, **kwargs): """Submit the form that was selected with :func:`select_form`. :return: Forwarded from :func:`Browser.submit`. @@ -216,6 +221,19 @@ def submit_selected(self, btnName=None, *args, **kwargs): to :func:`Form.choose_submit` on the current form to choose between them. All other arguments are forwarded to :func:`Browser.submit`. """ + # Temporarily allow calling the old inherited Browser.submit directly + # in case we can detect with certainty that the call is an old style. + # Note: Browser.submit also accepts a bs4.element.Tag with name="form", + # but we cannot assume this is an old-style call since there could be + # a submit button with name="form". + if isinstance(btnName, Form): + warnings.warn("This usage of StatefulBrowser.submit is deprecated." + " Please see the documentation for this function to " + "upgrade to the new interface.", + DeprecationWarning) + return super(StatefulBrowser, self).submit(btnName, *args, + **kwargs) + self.get_current_form().choose_submit(btnName) referer = self.get_url() @@ -225,8 +243,9 @@ def submit_selected(self, btnName=None, *args, **kwargs): else: kwargs['headers'] = {'Referer': referer} - resp = self.submit(self.__state.form, url=self.__state.url, - *args, **kwargs) + resp = super(StatefulBrowser, self).submit(self.__state.form, + url=self.__state.url, + *args, **kwargs) self.__state = _BrowserState(page=resp.soup, url=resp.url, request=resp.request) return resp diff --git a/tests/test_stateful_browser.py b/tests/test_stateful_browser.py index 291bec2a..4a6e855a 100644 --- a/tests/test_stateful_browser.py +++ b/tests/test_stateful_browser.py @@ -621,5 +621,20 @@ def test_refresh_error(): browser.refresh() +def test_deprecated_submit(recwarn): + """Check that calling StatefulBrowser.submit forwards to the base class + with a deprecation warning when a deprecated call is detected.""" + expected_post = [('diff', 'Review Changes'), + ('text', 'All I know is my gut says maybe')] + browser, url = setup_mock_browser(expected_post=expected_post) + browser.open(url) + form = browser.select_form('#choose-submit-form') + form.choose_submit(expected_post[0][0]) + form[expected_post[1][0]] = expected_post[1][1] + res = browser.submit(form, browser.get_url()) + assert issubclass(recwarn.pop().category, DeprecationWarning) + assert(res.status_code == 200 and res.text == 'Success!') + + if __name__ == '__main__': pytest.main(sys.argv)