internlm/SWE-Fixer-Train-110K huggingface dataset:
Repository: jupyterhub/zero-to-jupyterhub-k8s

Issue:
Let singleuser.cloudMetadata.blockWithIpTables only block TCP port 80
- Closes #3180
  By blocking only TCP Port 80 on the cloud metadata server where the sensitive metadata API is exposed, as compared to all traffic which could include relevant DNS traffic for example when a GKE cluster is configured to use Cloud DNS instead of kube-dns (default).
- Closes #3184
  By adding a versionchanged note, and mentioning TCP Port 80 specifically in docs, and by failing if a config is ambiguous by both blocking via iptables and allowing access via NetworkPolicy.
  
### Notes thinking about this

- I've learned we can do `--destination-ports`, in plural instead of singular, allowing us to specify 80 and 443 (EDIT: didn't get this to work)
- Is the metadata API by GKE/EKS/AKS exposed only on TCP port 80? I'm not 100%, but it seems so.
  - EDIT: GKE, EKS, AKS doesn't have anything on port 443 in clusters I inspected
- Should we block UDP port 80 as well since there are things like QUIC protocol to send HTTP traffic also etc, or is it safe to just assume there is no other ports open etc?
- I've learned we can use an exclamation mark before a flag to say the opposite, like `! --destination-port 53` to block traffic except to port 53.
  - EDIT: But this makes us need to specify a --protocol, either tcp or udp, one at at the time, not `all` or similar.

I currently think that blocking only traffic to 169.254.169.254 TCP port 80 this is a clean solution thats easy to document, but I'd like quite good faith in that. Going to check this against GKE EKS AKS


Discussion:

Resolving patch:
diff --git a/jupyterhub/files/hub/jupyterhub_config.py b/jupyterhub/files/hub/jupyterhub_config.py
--- a/jupyterhub/files/hub/jupyterhub_config.py
+++ b/jupyterhub/files/hub/jupyterhub_config.py
@@ -419,23 +419,28 @@ def camelCaseify(s):
 
 set_config_if_not_none(c.Spawner, "default_url", "singleuser.defaultUrl")
 
-cloud_metadata = get_config("singleuser.cloudMetadata", {})
+cloud_metadata = get_config("singleuser.cloudMetadata")
 
 if cloud_metadata.get("blockWithIptables") == True:
     # Use iptables to block access to cloud metadata by default
     network_tools_image_name = get_config("singleuser.networkTools.image.name")
     network_tools_image_tag = get_config("singleuser.networkTools.image.tag")
     network_tools_resources = get_config("singleuser.networkTools.resources")
+    ip = cloud_metadata["ip"]
     ip_block_container = client.V1Container(
         name="block-cloud-metadata",
         image=f"{network_tools_image_name}:{network_tools_image_tag}",
         command=[
             "iptables",
-            "-A",
+            "--append",
             "OUTPUT",
-            "-d",
-            cloud_metadata.get("ip", "169.254.169.254"),
-            "-j",
+            "--protocol",
+            "tcp",
+            "--destination",
+            ip,
+            "--destination-port",
+            "80",
+            "--jump",
             "DROP",
         ],
         security_context=client.V1SecurityContext(


Test patch:
Repository: cookiecutter/cookiecutter

Issue:
UnicodeEncodeError when the prompt string contains non ascii characters.
The call prompt fails, if the template settings contains non-ASCII characters.

cookiecutter.json example:

```
{
        "full_name": "Jindřich Smitka",
        ...
}
```



Discussion:

Resolving patch:
diff --git a/cookiecutter/prompt.py b/cookiecutter/prompt.py
--- a/cookiecutter/prompt.py
+++ b/cookiecutter/prompt.py
@@ -23,15 +23,15 @@ def prompt_for_config(context):
     field names and sample values.
     """
     cookiecutter_dict = {}
-    
+
     for key, val in iteritems(context['cookiecutter']):
-        prompt = "{0} (default is \"{1}\")? ".format(key, val)
-        new_val = input(prompt)
+        prompt = u"{0} (default is \"{1}\")? ".format(key, val)
+        new_val = input(prompt.encode('utf-8'))
         new_val = new_val.strip()
 
         if new_val == '':
             new_val = val
-        
+
         if PY3:
             cookiecutter_dict[key] = new_val
         else:


Test patch:
diff --git a/tests/test_examples.py b/tests/test_examples.py
--- a/tests/test_examples.py
+++ b/tests/test_examples.py
@@ -15,20 +15,20 @@
 
 PY3 = sys.version > '3'
 if PY3:
+    import subprocess
     from unittest.mock import patch
     input_str = 'builtins.input'
     from io import StringIO
 else:
+    import subprocess32 as subprocess
     import __builtin__
     from mock import patch
     input_str = '__builtin__.raw_input'
     from cStringIO import StringIO
 
-if sys.version_info[:2] < (2, 7):
+if sys.version_info[:3] < (2, 7):
     import unittest2 as unittest
-    import subprocess32 as subprocess
 else:
-    import subprocess
     import unittest
 
 try:
diff --git a/tests/test_prompt.py b/tests/test_prompt.py
--- a/tests/test_prompt.py
+++ b/tests/test_prompt.py
@@ -30,7 +30,7 @@
 
 
 class TestPrompt(unittest.TestCase):
-    
+
     @patch(input_str, lambda x: 'Audrey Roy')
     def test_prompt_for_config_simple(self):
         context = {"cookiecutter": {"full_name": "Your Name"}}
@@ -55,6 +55,20 @@ def test_prompt_for_config_unicode(self):
         else:
             self.assertEqual(cookiecutter_dict, {"full_name": u"Pizzä ïs Gööd"})
 
+    @patch(input_str, lambda x: 'Pizzä ïs Gööd')
+    def test_unicode_prompt_for_config_unicode(self):
+        context = {"cookiecutter": {"full_name": u"Řekni či napiš své jméno"}}
+
+        if not PY3:
+            sys.stdin = StringIO("Pizzä ïs Gööd")
+
+        cookiecutter_dict = prompt.prompt_for_config(context)
+
+        if PY3:
+            self.assertEqual(cookiecutter_dict, {"full_name": "Pizzä ïs Gööd"})
+        else:
+            self.assertEqual(cookiecutter_dict, {"full_name": u"Pizzä ïs Gööd"})
+
 
 class TestQueryAnswers(unittest.TestCase):
Repository: cookiecutter/cookiecutter

Issue:
UnicodeEncodeError when the defualt value is used and contains non ascii characters.
Error occurs when the user uses the default unicode string.

Code:

```
if PY3:
    cookiecutter_dict[key] = new_val
else:
    cookiecutter_dict[key] = new_val.decode('utf-8')
```

Everything is okay in Python 3, but `new_val` is already unicode in 2.x.



Discussion:

Resolving patch:
diff --git a/cookiecutter/prompt.py b/cookiecutter/prompt.py
--- a/cookiecutter/prompt.py
+++ b/cookiecutter/prompt.py
@@ -18,6 +18,7 @@
     input = raw_input
     iteritems = lambda d: d.iteritems()
 
+
 def prompt_for_config(context):
     """
     Prompts the user to enter new config, using context as a source for the
@@ -27,16 +28,18 @@ def prompt_for_config(context):
 
     for key, val in iteritems(context['cookiecutter']):
         prompt = "{0} (default is \"{1}\")? ".format(key, val)
-        new_val = input(prompt.encode('utf-8'))
+
+        if PY3:
+            new_val = input(prompt.encode('utf-8'))
+        else:
+            new_val = input(prompt.encode('utf-8')).decode('utf-8')
+
         new_val = new_val.strip()
 
         if new_val == '':
             new_val = val
 
-        if PY3:
-            cookiecutter_dict[key] = new_val
-        else:
-            cookiecutter_dict[key] = new_val.decode('utf-8')
+        cookiecutter_dict[key] = new_val
     return cookiecutter_dict
 
 


Test patch:
diff --git a/tests/test_prompt.py b/tests/test_prompt.py
--- a/tests/test_prompt.py
+++ b/tests/test_prompt.py
@@ -69,6 +69,20 @@ def test_unicode_prompt_for_config_unicode(self):
         else:
             self.assertEqual(cookiecutter_dict, {"full_name": u"Pizzä ïs Gööd"})
 
+    @patch(input_str, lambda x: '\n')
+    def test_unicode_prompt_for_default_config_unicode(self):
+        context = {"cookiecutter": {"full_name": u"Řekni či napiš své jméno"}}
+
+        if not PY3:
+            sys.stdin = StringIO("\n")
+
+        cookiecutter_dict = prompt.prompt_for_config(context)
+
+        if PY3:
+            self.assertEqual(cookiecutter_dict, {"full_name": "Řekni či napiš své jméno"})
+        else:
+            self.assertEqual(cookiecutter_dict, {"full_name": u"Řekni či napiš své jméno"})
+
 
 class TestQueryAnswers(unittest.TestCase):
Repository: cookiecutter/cookiecutter

Issue:
Get ccext.py functioning again
This worked but when we switch to Click from the old command-line system it broke this extension. 



Discussion:

Resolving patch:
diff --git a/docs/ccext.py b/docs/ccext.py
--- a/docs/ccext.py
+++ b/docs/ccext.py
@@ -1,30 +1,29 @@
 # -*- coding: utf-8 -*-
-import sys
 from cookiecutter import cli
+
+import click
+
 from docutils import nodes
 from docutils.parsers import rst
 from docutils.statemachine import ViewList
 
 
 class CcCommandLineOptions(rst.Directive):
-    def _format_action(self, action):
-        bookmark_line = ".. _`%s`:" % action.dest
-        line = ".. option:: "
-        line += ", ".join(action.option_strings)
-        opt_help = action.help.replace('%default', str(action.default))
-
-        # fix paths with sys.prefix
-        opt_help = opt_help.replace(sys.prefix, "<sys.prefix>")
-
-        return [bookmark_line, "", line, "", " %s" % opt_help, ""]
+    def _format_option(self, option):
+        return [
+            ".. _`%s`:" % option.name,
+            "",
+            ".. option:: " + ", ".join(option.opts),
+            "",
+            option.help,
+            ""
+        ]
 
     def process_actions(self):
-        parser = cli._get_parser()
-        for action in parser._actions:
-            if not action.option_strings:
-                continue
-            for line in self._format_action(action):
-                self.view_list.append(line, "")
+        for option in cli.main.params:
+            if isinstance(option, click.core.Option):
+                for line in self._format_option(option):
+                    self.view_list.append(line, "")
 
     def run(self):
         node = nodes.paragraph()
diff --git a/docs/conf.py b/docs/conf.py
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -63,7 +63,7 @@ def __getattr__(cls, name):
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
 extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx',
               'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.pngmath',
-              'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', ]#'docs.ccext']
+              'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', 'docs.ccext']
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']


Test patch:
Repository: cookiecutter/cookiecutter

Issue:
chg: be more precise in error message on config file.
We can be more helpful when the main config file throws a parser error.



Discussion:

Resolving patch:
diff --git a/cookiecutter/config.py b/cookiecutter/config.py
--- a/cookiecutter/config.py
+++ b/cookiecutter/config.py
@@ -41,9 +41,12 @@ def get_config(config_path):
     with io.open(config_path, encoding='utf-8') as file_handle:
         try:
             yaml_dict = yaml.safe_load(file_handle)
-        except yaml.scanner.ScannerError:
+        except yaml.scanner.ScannerError as e:
             raise InvalidConfiguration(
-                '{0} is no a valid YAML file'.format(config_path))
+                '{0} is not a valid YAML file: line {1}: {2}'.format(
+                    config_path,
+                    e.problem_mark.line,
+                    e.problem))
 
     config_dict = copy.copy(DEFAULT_CONFIG)
     config_dict.update(yaml_dict)


Test patch:
diff --git a/tests/test_get_config.py b/tests/test_get_config.py
--- a/tests/test_get_config.py
+++ b/tests/test_get_config.py
@@ -51,9 +51,15 @@ def test_invalid_config():
     """
     An invalid config file should raise an `InvalidConfiguration` exception.
     """
-    with pytest.raises(InvalidConfiguration):
+    with pytest.raises(InvalidConfiguration) as excinfo:
         config.get_config('tests/test-config/invalid-config.yaml')
 
+    expected_error_msg = (
+        'tests/test-config/invalid-config.yaml is not a valid YAML file: '
+        'line 1: mapping values are not allowed here'
+    )
+    assert str(excinfo.value) == expected_error_msg
+
 
 def test_get_config_with_defaults():
     """
Repository: cookiecutter/cookiecutter

Issue:
Increase development status to 'beta' or 'stable'.
I think we can say the project is waaaay beyond alpha. :wink: 



Discussion:
Hmmmmm :grin: :+1: 


Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -66,7 +66,7 @@
     license='BSD',
     zip_safe=False,
     classifiers=[
-        'Development Status :: 3 - Alpha',
+        'Development Status :: 5 - Production/Stable',
         'Environment :: Console',
         'Intended Audience :: Developers',
         'Natural Language :: English',


Test patch:
Repository: cookiecutter/cookiecutter

Issue:
Improve help access and prompts from the CLI
A new user might enter any of the following and expect to be guided to the Help information about using the CLI:
- `cookiecutter`
- `cookiecutter -h`
- `cookiecutter --h`
- `cookiecutter help`

It would be helpful to improve the CLI messages or handle some of the additional cases for a new user.

@audreyr Thanks for the handy tool :bouquet: 

<img width="773" alt="screen shot 2015-08-07 at 7 54 57 am" src="https://cloud.githubusercontent.com/assets/2680980/9138629/e64cb42a-3cd9-11e5-8c9c-cb9d726bd1eb.png">



Discussion:
Thank you @willingc for submitting an issue on this topic! :bow:

I agree that it would be very helpful to extend the help messages displayed to the user. As I was going over the CLI implementation just yesterday (#489) and noticed that **click** does not support `-h` as a help option as it is not common in posix.

However I feel we should add `cookiecutter` and `cookiecutter help`. :smile: 

Sure, we can start with `cookiecutter` and `cookiecutter help`. 

This would be a particularly good feature to have sooner than later, so I added please-help and high-priority tags.


Resolving patch:
diff --git a/cookiecutter/cli.py b/cookiecutter/cli.py
--- a/cookiecutter/cli.py
+++ b/cookiecutter/cli.py
@@ -30,7 +30,7 @@ def version_msg():
     return message.format(location, python_version)
 
 
-@click.command()
+@click.command(context_settings=dict(help_option_names=[u'-h', u'--help']))
 @click.version_option(__version__, u'-V', u'--version', message=version_msg())
 @click.argument(u'template')
 @click.option(
@@ -75,6 +75,13 @@ def main(template, no_input, checkout, verbose, replay, overwrite_if_exists,
         )
 
     try:
+
+        # If you _need_ to support a local template in a directory
+        # called 'help', use a qualified path to the directory.
+        if template == u'help':
+            click.echo(click.get_current_context().get_help())
+            sys.exit(0)
+
         cookiecutter(
             template, checkout, no_input,
             replay=replay,


Test patch:
diff --git a/tests/test_cli.py b/tests/test_cli.py
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -203,3 +203,14 @@ def test_cli_output_dir(mocker, output_dir_flag, output_dir):
         overwrite_if_exists=False,
         output_dir=output_dir
     )
+
+
+@pytest.fixture(params=['-h', '--help', 'help'])
+def help_cli_flag(request):
+    return request.param
+
+
+def test_cli_help(help_cli_flag):
+    result = runner.invoke(main, [help_cli_flag])
+    assert result.exit_code == 0
+    assert result.output.startswith('Usage')
Repository: cookiecutter/cookiecutter

Issue:
Cookiecutter needs to always use utf-8 for writing files
I get this on Windows (pitty me):

```
  File "c:\program files\python 3.5\lib\site-packages\cookiecutter\generate.py", line 318, in generate_files
    run_hook('post_gen_project', project_dir, context)
  File "c:\program files\python 3.5\lib\site-packages\cookiecutter\hooks.py", line 107, in run_hook
    return run_script_with_context(script, project_dir, context)
  File "c:\program files\python 3.5\lib\site-packages\cookiecutter\hooks.py", line 90, in run_script_with_context
    temp.write(Template(contents).render(**context))
  File "c:\program files\python 3.5\lib\tempfile.py", line 482, in func_wrapper
    return func(*args, **kwargs)
  File "c:\program files\python 3.5\lib\encodings\cp1252.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\u0103' in position 1626: character maps to <undefined>
```

cookiecutter should pass `encoding='utf-8'` to `NamedTemporaryFile`



Discussion:
Unfortunately `encoding` is only supported in Python 3.

https://docs.python.org/3.5/library/tempfile.html#tempfile.NamedTemporaryFile

What's your recommendation? 

Ugh ... version check and perhaps strong alcohol to wash out the dirty feeling? :grimacing: 

On second thought, you might want to also have the encoding handling on py2. Hmmmmmm ...

I know! Something like `NamedTemporaryFile('rb').write(Template(contents).render(**context).encode('utf-8'))` - how about that?

Let's give it a try. Wanna submit a PR? :joy_cat: 

If you promise to make a new cookiecutter release ... yesterday! :joy_cat:


Resolving patch:
diff --git a/cookiecutter/hooks.py b/cookiecutter/hooks.py
--- a/cookiecutter/hooks.py
+++ b/cookiecutter/hooks.py
@@ -90,10 +90,11 @@ def run_script_with_context(script_path, cwd, context):
 
     with tempfile.NamedTemporaryFile(
         delete=False,
-        mode='w',
+        mode='wb',
         suffix=extension
     ) as temp:
-        temp.write(Template(contents).render(**context))
+        output = Template(contents).render(**context)
+        temp.write(output.encode('utf-8'))
 
     run_script(temp.name, cwd)
 


Test patch:
Repository: cookiecutter/cookiecutter

Issue:
No way to define options that have no defaults
Currently if you set a value in `cookiecutter.json` to `null` it becomes `None` and is then turned into the _string_ `'None'`.



Discussion:

Resolving patch:
diff --git a/cookiecutter/prompt.py b/cookiecutter/prompt.py
--- a/cookiecutter/prompt.py
+++ b/cookiecutter/prompt.py
@@ -81,6 +81,8 @@ def read_user_choice(var_name, options):
 
 
 def render_variable(env, raw, cookiecutter_dict):
+    if raw is None:
+        return None
     if not isinstance(raw, basestring):
         raw = str(raw)
     template = env.from_string(raw)


Test patch:
diff --git a/tests/test_prompt.py b/tests/test_prompt.py
--- a/tests/test_prompt.py
+++ b/tests/test_prompt.py
@@ -22,7 +22,8 @@
     (1, '1'),
     (True, 'True'),
     ('foo', 'foo'),
-    ('{{cookiecutter.project}}', 'foobar')
+    ('{{cookiecutter.project}}', 'foobar'),
+    (None, None),
 ])
 def test_convert_to_str(mocker, raw_var, rendered_var):
     env = Environment()
@@ -35,10 +36,13 @@ def test_convert_to_str(mocker, raw_var, rendered_var):
     result = prompt.render_variable(env, raw_var, context)
     assert result == rendered_var
 
-    # Make sure that non str variables are conerted beforehand
-    if not isinstance(raw_var, basestring):
-        raw_var = str(raw_var)
-    from_string.assert_called_once_with(raw_var)
+    # Make sure that non None non str variables are conerted beforehand
+    if raw_var is not None:
+        if not isinstance(raw_var, basestring):
+            raw_var = str(raw_var)
+        from_string.assert_called_once_with(raw_var)
+    else:
+        assert not from_string.called
 
 
 @pytest.fixture(autouse=True)
Repository: cookiecutter/cookiecutter

Issue:
file_handle.close() is never called -- and it causes a bug!!
In https://github.com/audreyr/cookiecutter/blob/master/cookiecutter/generate.py#L90, `file_handle.close()` is never called, and there's no need for it to remain open.

This is the first time in over 10 years of python programming that I've run into an actual issue with file handles left open, so I felt that the use of two exclamation points in the subject was warranted. I'm removing a temporary template after an unrelated error, and...

```
  File "D:\anaconda32\lib\shutil.py", line 250, in rmtree
    os.remove(fullname)
WindowsError: [Error 32] The process cannot access the file because it is being
used by another process: '.\\tmpp2duu1\\cookiecutter.json'
```

This change in generate.py:90 helps python not stumble on this particular issue:

```
try:
    with open(context_file) as file_handle:
        obj = json.load(file_handle, object_pairs_hook=OrderedDict)
except ValueError as e:
    # ...
```



Discussion:

Resolving patch:
diff --git a/cookiecutter/generate.py b/cookiecutter/generate.py
--- a/cookiecutter/generate.py
+++ b/cookiecutter/generate.py
@@ -87,9 +87,9 @@ def generate_context(context_file='cookiecutter.json', default_context=None,
 
     context = {}
 
-    file_handle = open(context_file)
     try:
-        obj = json.load(file_handle, object_pairs_hook=OrderedDict)
+        with open(context_file) as file_handle:
+            obj = json.load(file_handle, object_pairs_hook=OrderedDict)
     except ValueError as e:
         # JSON decoding error.  Let's throw a new exception that is more
         # friendly for the developer or user.


Test patch:
Repository: cookiecutter/cookiecutter

Issue:
Drop distutils support
I feel it's about time to drop **distutils** support as we rely on [extras_require of setuptools](https://pythonhosted.org/setuptools/setuptools.html#declaring-extras-optional-features-with-their-own-dependencies) to handle **yaml** dependencies..

What's your opinion on this matter?



Discussion:
Also see #605 

:+1: 


Resolving patch:
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -3,10 +3,7 @@
 import os
 import sys
 
-try:
-    from setuptools import setup
-except ImportError:
-    from distutils.core import setup
+from setuptools import setup
 
 version = "1.3.0"
 


Test patch: