Repository: ipython/ipython

Issue:
Unable to pass arguments to modules with run -m
I am working with the git master branch. The following:
`In [1]: %run -m my_packages.my_module -verbosity 20`

returns:
`UsageError: option -v not recognized ( allowed: "nidtN:b:pD:l:rs:T:em:G" )`

Even though the following works:
`$ python -m my_packages.my_module -verbosity 20`

I am using `argparse` as follows:

```
parser = argparse.ArgumentParser(description='my_program)
parser.add_argument('-verbosity',   help='Verbosity', required=True);
```



Discussion:
For the moment you can do

%run -m my_packages.my_module -- -verbosity 20


Resolving patch:
diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py
--- a/IPython/core/magics/execution.py
+++ b/IPython/core/magics/execution.py
@@ -11,6 +11,7 @@
 import gc
 import itertools
 import os
+import shlex
 import sys
 import time
 import timeit
@@ -617,6 +618,20 @@ def run(self, parameter_s='', runner=None,
 
         """
 
+        # Logic to handle issue #3664
+        # Add '--' after '-m <module_name>' to ignore additional args passed to a module.
+        if '-m' in parameter_s and '--' not in parameter_s:
+            argv = shlex.split(parameter_s, posix=(os.name == 'posix'))
+            for idx, arg in enumerate(argv):
+                if arg and arg.startswith('-') and arg != '-':
+                    if arg == '-m':
+                        argv.insert(idx + 2, '--')
+                        break
+                else:
+                    # Positional arg, break
+                    break
+            parameter_s = ' '.join(shlex.quote(arg) for arg in argv)
+
         # get arguments and set sys.argv for program to be run.
         opts, arg_lst = self.parse_options(parameter_s,
                                            'nidtN:b:pD:l:rs:T:em:G',


Test patch:
diff --git a/IPython/core/tests/test_run.py b/IPython/core/tests/test_run.py
--- a/IPython/core/tests/test_run.py
+++ b/IPython/core/tests/test_run.py
@@ -384,7 +384,14 @@ def test_run_nb(self):
         _ip.magic("run %s" % self.fname)
         
         nt.assert_equal(_ip.user_ns['answer'], 42)
-        
+
+    def test_file_options(self):
+        src = ('import sys\n'
+               'a = " ".join(sys.argv[1:])\n')
+        self.mktmp(src)
+        test_opts = '-x 3 --verbose'
+        _ip.run_line_magic("run", '{0} {1}'.format(self.fname, test_opts))
+        nt.assert_equal(_ip.user_ns['a'], test_opts)
 
 
 class TestMagicRunWithPackage(unittest.TestCase):
@@ -417,6 +424,10 @@ def setUp(self):
         self.writefile(os.path.join(package, 'absolute.py'), """
         from {0}.sub import x
         """.format(package))
+        self.writefile(os.path.join(package, 'args.py'), """
+        import sys
+        a = " ".join(sys.argv[1:])
+        """.format(package))
 
     def tearDown(self):
         os.chdir(self.__orig_cwd)
@@ -458,6 +469,18 @@ def test_debug_run_submodule_with_absolute_import(self):
     def test_debug_run_submodule_with_relative_import(self):
         self.check_run_submodule('relative', '-d')
 
+    def test_module_options(self):
+        _ip.user_ns.pop('a', None)
+        test_opts = '-x abc -m test'
+        _ip.run_line_magic('run', '-m {0}.args {1}'.format(self.package, test_opts))
+        nt.assert_equal(_ip.user_ns['a'], test_opts)
+
+    def test_module_options_with_separator(self):
+        _ip.user_ns.pop('a', None)
+        test_opts = '-x abc -m test'
+        _ip.run_line_magic('run', '-m {0}.args -- {1}'.format(self.package, test_opts))
+        nt.assert_equal(_ip.user_ns['a'], test_opts)
+
 def test_run__name__():
     with TemporaryDirectory() as td:
         path = pjoin(td, 'foo.py')