Repository: oppia/oppia

Issue:
Remove python_utils constants and imports
[python_utils](https://github.com/oppia/oppia/blob/develop/python_utils.py) has variables and functions that were defined specifically to support both Python 2 and Python 3.
Now that we have migrated to Python 3, this file is redundant and can be removed.

To be able to contribute to this issue:

1. From `python_utils.py` pick a variable <your_variable> or function <your_function> and ask @vojtechjelinek or @YBCS to be assigned the variable or function.
2. Search the entire code base for python_utils.<your_variable> or python_utils.<your_function>.
3. Simply replace them with the corresponding Python 3 functions.
4. Remove the variable from python_utils.
5. Make sure the tests are passing :slightly_smiling_face:

Sample PRs for reference are: #13882, #13955 

Available functions to migrate:
- [ ] python_utils.get_args_of_function_node #14485










Discussion:
Hi @YBCS, thanks for proposing this as a good first issue. I am removing the label for now and looping in @DubeySandeep to approve the label. It will be added back if approved. Thanks!
hello, I want to try this. Please @YBCS  assign me
Hi @YBCS. I would like to change the `python_utils.open_file` function to a simple `open`. Please assign this to me. Cheers.

Also a doubt, what happens to the tests inside `python_utils_test.py`? Do we comment them out, or replace the `python_utils.open_file` in them too with `open`?
My god, I am new to this, and I was hit by a flurry of bot comments. Like I had everything ready and posted a PR but I didn't meet a lot of the criteria, so the PR was auto-closed. I am developing on Codespaces. Can someone guide me on what to do please step-by-step? For starters, I have filled the `individual-CLA`. @YBCS or @vojtechjelinek
@YBCS @vojtechjelinek , can I work on `python_utls.is_string`?
@anurag629 Done.

@sreyan-ghosh The second PR you made looks good.

@soumyo123-prog Done, I have also assigned you `python_utils.get_args_of_function` since `python_utils.is_string` is quite easy compared to other functions.
@vojtechjelinek i would like to work on this issue.
@kingjuno Please pick a function or variable to work on.
> @kingjuno Please pick a function or variable to work on.

 python_utls.url_join
 python_utls.url_split
 python_utls.url_parse
 python_utls.url_unsplit
 
 I am ready to take any issues from the above list.
@kingjuno Done.
@vojtechjelinek @YBCS  I would like to contribute during the hacktoberfest. 
I choose 
`python_utils.RANGE`
`python_utils.ROUND`
`python_utils.url_request`
`python_utils.divide`
Please assign them to me.

@vojtechjelinek @YBCS I would like to contribute during the hacktoberfest.

can i have this?  python_utils.PRINT

@megamayoy I have only assigned you only `python_utils.RANGE` since there are a lot of occurrences of this in the code.

@poleselfg Done.
@vojtechjelinek @YBCS I would like to contribute to the hacktoberfest.
I choose
 python_utils.string_io
python_utils.url_open

Please assign them to me;Cheers
Hi, I would like to contribute during Hacktoberfest -
please assign me one or more from the following
 `python_utils.url_quote`
 `python_utils.url_unquote_plus`
 `python_utils.url_encode`
 `python_utils.url_retrieve`
Thanks in advance.
@Sangameshdavey Done.

@ProttoyChakraborty Done.
Hi  @YBCS @vojtechjelinek  I would like to  work on the  ` python_utils.yaml_from_dict` 
 python_utils.url_parse
 python_utils.url_unsplit 
@vojtechjelinek @YBCS 
Can you assign me this.
> Hi @YBCS @vojtechjelinek I would like to work on the ` python_utils.yaml_from_dict`

@DiptoChakrabarty Done. you can start working on it.
> python_utils.url_parse python_utils.url_unsplit @vojtechjelinek @YBCS Can you assign me this.

@5andeepNambiar Done. You can start working on it.
python_utils.parse_query_string
python_utils.urllib_unquote
@vojtechjelinek @YBCS
Can you please assign me this?
python_utils.url_request
 python_utils.divide
@vojtechjelinek @YBCS 
Can you assign me this?
> python_utils.parse_query_string python_utils.urllib_unquote @vojtechjelinek @YBCS Can you please assign me this?

@Ragify Done. You can start with it.
> python_utils.url_request python_utils.divide @vojtechjelinek @YBCS Can you assign me this?

@BlackReap-er done. you can start now.
@vojtechjelinek @YBCS Can you please assign me variables ROUND, ZIP and function zip_longest?
@vojtechjelinek @YBCS Can I get any 2 functions assigned? Thanks 
@vojtechjelinek  Please assign me these variables : 
 python_utils.OBJECT
 python_utils.ROUND
 python_utils.ZIP
@Mystic-Slice Done.

@vashuteotia123 Done.

@anurag629 Please pick another issue to work on as you already did some functions in this issue.
@vojtechjelinek can u please review [#13971](https://github.com/oppia/oppia/pull/13971)
@YBCS , @vojtechjelinek  The python 3 alternative for `python_utils.url_retrieve` is `urllib.requests.urlretrieve` however , its not well supported in current python 3 and might be deprecated in the future should I go ahead with the change?
refer -  https://docs.python.org/3/library/urllib.request.html
@vojtechjelinek  can you please review https://github.com/oppia/oppia/pull/13978
Hello @vojtechjelinek @YBCS,

May I take up `python_utils.reraise_exception`?
@vojtechjelinek  can you once review #13970
@vojtechjelinek  can you assign me this function?
python_utils.nullcontext

> @vojtechjelinek can you assign me this function? python_utils.nullcontext
@vpeopleonatank done you can start working on it

@YBCS can you please start the tests on  https://github.com/oppia/oppia/pull/13978 and https://github.com/oppia/oppia/pull/13964?
Thanks in advance 
> Hello @vojtechjelinek @YBCS,
> 
> May I take up `python_utils.reraise_exception`?

@wanjuntham assigned, you can start now
@vojtechjelinek please review [#13985](https://github.com/oppia/oppia/pull/13985).
@vojtechjelinek can you please review [#13987](https://github.com/oppia/oppia/pull/13987)
@ProttoyChakraborty started!
Hi @YBCS, I want to work on `python_utils.create_enum` and `python_utils.ExitStack` functions. Could you assign me?
@Joe-Sin7h 
I have assigned you. You can start now 
> @Joe-Sin7h I have assigned you. You can start now

already on it.
@vojtechjelinek , @YBCS  Please review https://github.com/oppia/oppia/pull/13990
Thanks
Hey i would love to work on this issue . Can you please assign me one ?

@ashish-patwal I have assigned you `python_utils.with_metaclass`
Hi @vojtechjelinek , can I be assigned to this issue?
@MenachemRapp Hey, you can take `python_utils.open_file` this was already attempted in #13958
@vojtechjelinek  Can you `python_utils.get_args_of_function_node` to me ?
@ProttoyChakraborty Done.
@vojtechjelinek @YBCS can you please start the tests at #13970 .Thanks.
@vojtechjelinek , i needed some help . I am trying to run a search through the whole codebase for the functions . The peculiar thing  is that when i am using git grep it is showing a lot less results as compared to grep . Is it because git grep searches only files tracked by git ? What do you recommend ?
> @vojtechjelinek , i needed some help . I am trying to run a search through the whole codebase for the functions . The peculiar thing is that when i am using git grep it is showing a lot less results as compared to grep . Is it because git grep searches only files tracked by git ? What do you recommend ?

Yes, it is because of that, it should be fine to just use `git grep`.
> > @vojtechjelinek , i needed some help . I am trying to run a search through the whole codebase for the functions . The peculiar thing is that when i am using git grep it is showing a lot less results as compared to grep . Is it because git grep searches only files tracked by git ? What do you recommend ?
> 
> Yes, it is because of that, it should be fine to just use `git grep`.

Thanks for the help !!
@vojtechjelinek Can sys.stdout() be the perfect replacement for python_utils.redirect_stdout ?
> @vojtechjelinek Can sys.stdout() be the perfect replacement for python_utils.redirect_stdout ?

No, you should use `contextlib.redirect_stdout`.
> > @vojtechjelinek Can sys.stdout() be the perfect replacement for python_utils.redirect_stdout ?
> 
> No, you should use `contextlib.redirect_stdout`.

Okay. Thanks.

Resolving patch:
diff --git a/core/python_utils.py b/core/python_utils.py
--- a/core/python_utils.py
+++ b/core/python_utils.py
@@ -97,25 +97,6 @@ def SimpleXMLRPCServer( # pylint: disable=invalid-name
         bind_and_activate=bind_and_activate)
 
 
-def redirect_stdout(new_target):
-    """Returns redirect_stdout from contextlib2 if run under Python 2 and from
-    contextlib if run under Python 3.
-
-    Args:
-        new_target: FileLike. The file-like object all messages printed to
-            stdout will be redirected to.
-
-    Returns:
-        contextlib.redirect_stdout or contextlib2.redirect_stdout. The
-        redirect_stdout object.
-    """
-    try:
-        from contextlib import redirect_stdout as impl  # pylint: disable=import-only-modules
-    except ImportError:
-        from contextlib2 import redirect_stdout as impl  # pylint: disable=import-only-modules
-    return impl(new_target)
-
-
 def nullcontext(enter_result=None):
     """Returns nullcontext from contextlib2 if run under Python 2 and from
     contextlib if run under Python 3.


Test patch:
diff --git a/scripts/servers_test.py b/scripts/servers_test.py
--- a/scripts/servers_test.py
+++ b/scripts/servers_test.py
@@ -691,7 +691,7 @@ def test_managed_webpack_compiler_in_watch_mode_when_build_succeeds(self):
         popen_calls = self.exit_stack.enter_context(self.swap_popen(
             outputs=[b'abc', b'Built at: 123', b'def']))
         str_io = python_utils.string_io()
-        self.exit_stack.enter_context(python_utils.redirect_stdout(str_io))
+        self.exit_stack.enter_context(contextlib.redirect_stdout(str_io))
         logs = self.exit_stack.enter_context(self.capture_logging())
 
         proc = self.exit_stack.enter_context(servers.managed_webpack_compiler(
@@ -715,7 +715,7 @@ def test_managed_webpack_compiler_in_watch_mode_raises_when_not_built(self):
         # NOTE: The 'Built at: ' message is never printed.
         self.exit_stack.enter_context(self.swap_popen(outputs=[b'abc', b'def']))
         str_io = python_utils.string_io()
-        self.exit_stack.enter_context(python_utils.redirect_stdout(str_io))
+        self.exit_stack.enter_context(contextlib.redirect_stdout(str_io))
 
         self.assertRaisesRegexp(
             IOError, 'First build never completed',