prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Add flag to build environment.yml without build strings
  https://gitter.im/conda/conda?at=59ef54ebe44c43700a70e9a4
  https://twitter.com/drvinceknight/status/922837449092542464?ref_src=twsrc%5Etfw
  
  > Due to hashes of packages being introduced in `envinronment.yml` I'm getting all sorts of issues with building envs from file. (Very new problem)
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `conda_env/env.py`
  Content:
  ```
  1 from __future__ import absolute_import, print_function
  2 
  3 import os
  4 from collections import OrderedDict
  5 from conda.base.context import context
  6 from conda.cli import common  # TODO: this should never have to import form conda.cli
  7 from conda.core.linked_data import linked
  8 from copy import copy
  9 from itertools import chain
  10 
  11 from . import compat, exceptions, yaml
  12 from .pip_util import add_pip_installed
  13 
  14 def load_from_directory(directory):
  15     """Load and return an ``Environment`` from a given ``directory``"""
  16     files = ['environment.yml', 'environment.yaml']
  17     while True:
  18         for f in files:
  19             try:
  20                 return from_file(os.path.join(directory, f))
  21             except exceptions.EnvironmentFileNotFound:
  22                 pass
  23         old_directory = directory
  24         directory = os.path.dirname(directory)
  25         if directory == old_directory:
  26             break
  27     raise exceptions.EnvironmentFileNotFound(files[0])
  28 
  29 
  30 # TODO This should lean more on conda instead of divining it from the outside
  31 # TODO tests!!!
  32 def from_environment(name, prefix, no_builds=False, ignore_channels=False):
  33     """
  34         Get environment object from prefix
  35     Args:
  36         name: The name of environment
  37         prefix: The path of prefix
  38         no_builds: Whether has build requirement
  39         ignore_channels: whether ignore_channels
  40 
  41     Returns:     Environment object
  42     """
  43     installed = linked(prefix, ignore_channels=ignore_channels)
  44     conda_pkgs = copy(installed)
  45     # json=True hides the output, data is added to installed
  46     add_pip_installed(prefix, installed, json=True)
  47 
  48     pip_pkgs = sorted(installed - conda_pkgs)
  49 
  50     if no_builds:
  51         dependencies = ['='.join(a.quad[0:3]) for a in sorted(conda_pkgs)]
  52     else:
  53         dependencies = ['='.join(a.quad[0:3]) for a in sorted(conda_pkgs)]
  54     if len(pip_pkgs) > 0:
  55         dependencies.append({'pip': ['=='.join(a.rsplit('-', 2)[:2]) for a in pip_pkgs]})
  56     # conda uses ruamel_yaml which returns a ruamel_yaml.comments.CommentedSeq
  57     # this doesn't dump correctly using pyyaml
  58     channels = list(context.channels)
  59     if not ignore_channels:
  60         for dist in conda_pkgs:
  61             if dist.channel not in channels:
  62                 channels.insert(0, dist.channel)
  63     return Environment(name=name, dependencies=dependencies, channels=channels, prefix=prefix)
  64 
  65 
  66 def from_yaml(yamlstr, **kwargs):
  67     """Load and return a ``Environment`` from a given ``yaml string``"""
  68     data = yaml.load(yamlstr)
  69     if kwargs is not None:
  70         for key, value in kwargs.items():
  71             data[key] = value
  72     return Environment(**data)
  73 
  74 
  75 def from_file(filename):
  76     if not os.path.exists(filename):
  77         raise exceptions.EnvironmentFileNotFound(filename)
  78     with open(filename, 'r') as fp:
  79         yamlstr = fp.read()
  80         return from_yaml(yamlstr, filename=filename)
  81 
  82 
  83 # TODO test explicitly
  84 class Dependencies(OrderedDict):
  85     def __init__(self, raw, *args, **kwargs):
  86         super(Dependencies, self).__init__(*args, **kwargs)
  87         self.raw = raw
  88         self.parse()
  89 
  90     def parse(self):
  91         if not self.raw:
  92             return
  93 
  94         self.update({'conda': []})
  95 
  96         for line in self.raw:
  97             if isinstance(line, dict):
  98                 self.update(line)
  99             else:
  100                 self['conda'].append(common.arg2spec(line))
  101 
  102     # TODO only append when it's not already present
  103     def add(self, package_name):
  104         self.raw.append(package_name)
  105         self.parse()
  106 
  107 
  108 def unique(seq, key=None):
  109     """ Return only unique elements of a sequence
  110     >>> tuple(unique((1, 2, 3)))
  111     (1, 2, 3)
  112     >>> tuple(unique((1, 2, 1, 3)))
  113     (1, 2, 3)
  114     Uniqueness can be defined by key keyword
  115     >>> tuple(unique(['cat', 'mouse', 'dog', 'hen'], key=len))
  116     ('cat', 'mouse')
  117     """
  118     seen = set()
  119     seen_add = seen.add
  120     if key is None:
  121         for item in seq:
  122             if item not in seen:
  123                 seen_add(item)
  124                 yield item
  125     else:  # calculate key
  126         for item in seq:
  127             val = key(item)
  128             if val not in seen:
  129                 seen_add(val)
  130                 yield item
  131 
  132 
  133 class Environment(object):
  134     def __init__(self, name=None, filename=None, channels=None,
  135                  dependencies=None, prefix=None):
  136         self.name = name
  137         self.filename = filename
  138         self.prefix = prefix
  139         self.dependencies = Dependencies(dependencies)
  140 
  141         if channels is None:
  142             channels = []
  143         self.channels = channels
  144 
  145     def add_channels(self, channels):
  146         self.channels = list(unique(chain.from_iterable((channels, self.channels))))
  147 
  148     def remove_channels(self):
  149         self.channels = []
  150 
  151     def to_dict(self):
  152         d = yaml.dict([('name', self.name)])
  153         if self.channels:
  154             d['channels'] = self.channels
  155         if self.dependencies:
  156             d['dependencies'] = self.dependencies.raw
  157         if self.prefix:
  158             d['prefix'] = self.prefix
  159         return d
  160 
  161     def to_yaml(self, stream=None):
  162         d = self.to_dict()
  163         out = compat.u(yaml.dump(d, default_flow_style=False))
  164         if stream is None:
  165             return out
  166         stream.write(compat.b(out, encoding="utf-8"))
  167 
  168     def save(self):
  169         with open(self.filename, "wb") as fp:
  170             self.to_yaml(stream=fp)
  171
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/conda_env/env.py b/conda_env/env.py
  --- a/conda_env/env.py
  +++ b/conda_env/env.py
  @@ -48,9 +48,9 @@
       pip_pkgs = sorted(installed - conda_pkgs)
   
       if no_builds:
  -        dependencies = ['='.join(a.quad[0:3]) for a in sorted(conda_pkgs)]
  +        dependencies = ['='.join((a.name, a.version)) for a in sorted(conda_pkgs)]
       else:
  -        dependencies = ['='.join(a.quad[0:3]) for a in sorted(conda_pkgs)]
  +        dependencies = ['='.join((a.name, a.version, a.build)) for a in sorted(conda_pkgs)]
       if len(pip_pkgs) > 0:
           dependencies.append({'pip': ['=='.join(a.rsplit('-', 2)[:2]) for a in pip_pkgs]})
       # conda uses ruamel_yaml which returns a ruamel_yaml.comments.CommentedSeq
  
verification_info: {"golden_diff": "diff --git a/conda_env/env.py b/conda_env/env.py\n--- a/conda_env/env.py\n+++ b/conda_env/env.py\n@@ -48,9 +48,9 @@\n     pip_pkgs = sorted(installed - conda_pkgs)\n \n     if no_builds:\n-        dependencies = ['='.join(a.quad[0:3]) for a in sorted(conda_pkgs)]\n+        dependencies = ['='.join((a.name, a.version)) for a in sorted(conda_pkgs)]\n     else:\n-        dependencies = ['='.join(a.quad[0:3]) for a in sorted(conda_pkgs)]\n+        dependencies = ['='.join((a.name, a.version, a.build)) for a in sorted(conda_pkgs)]\n     if len(pip_pkgs) > 0:\n         dependencies.append({'pip': ['=='.join(a.rsplit('-', 2)[:2]) for a in pip_pkgs]})\n     # conda uses ruamel_yaml which returns a ruamel_yaml.comments.CommentedSeq\n", "issue": "Add flag to build environment.yml without build strings\nhttps://gitter.im/conda/conda?at=59ef54ebe44c43700a70e9a4\r\nhttps://twitter.com/drvinceknight/status/922837449092542464?ref_src=twsrc%5Etfw\r\n\r\n> Due to hashes of packages being introduced in `envinronment.yml` I'm getting all sorts of issues with building envs from file. (Very new problem)\n", "before_files": [{"content": "from __future__ import absolute_import, print_function\n\nimport os\nfrom collections import OrderedDict\nfrom conda.base.context import context\nfrom conda.cli import common  # TODO: this should never have to import form conda.cli\nfrom conda.core.linked_data import linked\nfrom copy import copy\nfrom itertools import chain\n\nfrom . import compat, exceptions, yaml\nfrom .pip_util import add_pip_installed\n\ndef load_from_directory(directory):\n    \"\"\"Load and return an ``Environment`` from a given ``directory``\"\"\"\n    files = ['environment.yml', 'environment.yaml']\n    while True:\n        for f in files:\n            try:\n                return from_file(os.path.join(directory, f))\n            except exceptions.EnvironmentFileNotFound:\n                pass\n        old_directory = directory\n        directory = os.path.dirname(directory)\n        if directory == old_directory:\n            break\n    raise exceptions.EnvironmentFileNotFound(files[0])\n\n\n# TODO This should lean more on conda instead of divining it from the outside\n# TODO tests!!!\ndef from_environment(name, prefix, no_builds=False, ignore_channels=False):\n    \"\"\"\n        Get environment object from prefix\n    Args:\n        name: The name of environment\n        prefix: The path of prefix\n        no_builds: Whether has build requirement\n        ignore_channels: whether ignore_channels\n\n    Returns:     Environment object\n    \"\"\"\n    installed = linked(prefix, ignore_channels=ignore_channels)\n    conda_pkgs = copy(installed)\n    # json=True hides the output, data is added to installed\n    add_pip_installed(prefix, installed, json=True)\n\n    pip_pkgs = sorted(installed - conda_pkgs)\n\n    if no_builds:\n        dependencies = ['='.join(a.quad[0:3]) for a in sorted(conda_pkgs)]\n    else:\n        dependencies = ['='.join(a.quad[0:3]) for a in sorted(conda_pkgs)]\n    if len(pip_pkgs) > 0:\n        dependencies.append({'pip': ['=='.join(a.rsplit('-', 2)[:2]) for a in pip_pkgs]})\n    # conda uses ruamel_yaml which returns a ruamel_yaml.comments.CommentedSeq\n    # this doesn't dump correctly using pyyaml\n    channels = list(context.channels)\n    if not ignore_channels:\n        for dist in conda_pkgs:\n            if dist.channel not in channels:\n                channels.insert(0, dist.channel)\n    return Environment(name=name, dependencies=dependencies, channels=channels, prefix=prefix)\n\n\ndef from_yaml(yamlstr, **kwargs):\n    \"\"\"Load and return a ``Environment`` from a given ``yaml string``\"\"\"\n    data = yaml.load(yamlstr)\n    if kwargs is not None:\n        for key, value in kwargs.items():\n            data[key] = value\n    return Environment(**data)\n\n\ndef from_file(filename):\n    if not os.path.exists(filename):\n        raise exceptions.EnvironmentFileNotFound(filename)\n    with open(filename, 'r') as fp:\n        yamlstr = fp.read()\n        return from_yaml(yamlstr, filename=filename)\n\n\n# TODO test explicitly\nclass Dependencies(OrderedDict):\n    def __init__(self, raw, *args, **kwargs):\n        super(Dependencies, self).__init__(*args, **kwargs)\n        self.raw = raw\n        self.parse()\n\n    def parse(self):\n        if not self.raw:\n            return\n\n        self.update({'conda': []})\n\n        for line in self.raw:\n            if isinstance(line, dict):\n                self.update(line)\n            else:\n                self['conda'].append(common.arg2spec(line))\n\n    # TODO only append when it's not already present\n    def add(self, package_name):\n        self.raw.append(package_name)\n        self.parse()\n\n\ndef unique(seq, key=None):\n    \"\"\" Return only unique elements of a sequence\n    >>> tuple(unique((1, 2, 3)))\n    (1, 2, 3)\n    >>> tuple(unique((1, 2, 1, 3)))\n    (1, 2, 3)\n    Uniqueness can be defined by key keyword\n    >>> tuple(unique(['cat', 'mouse', 'dog', 'hen'], key=len))\n    ('cat', 'mouse')\n    \"\"\"\n    seen = set()\n    seen_add = seen.add\n    if key is None:\n        for item in seq:\n            if item not in seen:\n                seen_add(item)\n                yield item\n    else:  # calculate key\n        for item in seq:\n            val = key(item)\n            if val not in seen:\n                seen_add(val)\n                yield item\n\n\nclass Environment(object):\n    def __init__(self, name=None, filename=None, channels=None,\n                 dependencies=None, prefix=None):\n        self.name = name\n        self.filename = filename\n        self.prefix = prefix\n        self.dependencies = Dependencies(dependencies)\n\n        if channels is None:\n            channels = []\n        self.channels = channels\n\n    def add_channels(self, channels):\n        self.channels = list(unique(chain.from_iterable((channels, self.channels))))\n\n    def remove_channels(self):\n        self.channels = []\n\n    def to_dict(self):\n        d = yaml.dict([('name', self.name)])\n        if self.channels:\n            d['channels'] = self.channels\n        if self.dependencies:\n            d['dependencies'] = self.dependencies.raw\n        if self.prefix:\n            d['prefix'] = self.prefix\n        return d\n\n    def to_yaml(self, stream=None):\n        d = self.to_dict()\n        out = compat.u(yaml.dump(d, default_flow_style=False))\n        if stream is None:\n            return out\n        stream.write(compat.b(out, encoding=\"utf-8\"))\n\n    def save(self):\n        with open(self.filename, \"wb\") as fp:\n            self.to_yaml(stream=fp)\n", "path": "conda_env/env.py"}], "after_files": [{"content": "from __future__ import absolute_import, print_function\n\nimport os\nfrom collections import OrderedDict\nfrom conda.base.context import context\nfrom conda.cli import common  # TODO: this should never have to import form conda.cli\nfrom conda.core.linked_data import linked\nfrom copy import copy\nfrom itertools import chain\n\nfrom . import compat, exceptions, yaml\nfrom .pip_util import add_pip_installed\n\ndef load_from_directory(directory):\n    \"\"\"Load and return an ``Environment`` from a given ``directory``\"\"\"\n    files = ['environment.yml', 'environment.yaml']\n    while True:\n        for f in files:\n            try:\n                return from_file(os.path.join(directory, f))\n            except exceptions.EnvironmentFileNotFound:\n                pass\n        old_directory = directory\n        directory = os.path.dirname(directory)\n        if directory == old_directory:\n            break\n    raise exceptions.EnvironmentFileNotFound(files[0])\n\n\n# TODO This should lean more on conda instead of divining it from the outside\n# TODO tests!!!\ndef from_environment(name, prefix, no_builds=False, ignore_channels=False):\n    \"\"\"\n        Get environment object from prefix\n    Args:\n        name: The name of environment\n        prefix: The path of prefix\n        no_builds: Whether has build requirement\n        ignore_channels: whether ignore_channels\n\n    Returns:     Environment object\n    \"\"\"\n    installed = linked(prefix, ignore_channels=ignore_channels)\n    conda_pkgs = copy(installed)\n    # json=True hides the output, data is added to installed\n    add_pip_installed(prefix, installed, json=True)\n\n    pip_pkgs = sorted(installed - conda_pkgs)\n\n    if no_builds:\n        dependencies = ['='.join((a.name, a.version)) for a in sorted(conda_pkgs)]\n    else:\n        dependencies = ['='.join((a.name, a.version, a.build)) for a in sorted(conda_pkgs)]\n    if len(pip_pkgs) > 0:\n        dependencies.append({'pip': ['=='.join(a.rsplit('-', 2)[:2]) for a in pip_pkgs]})\n    # conda uses ruamel_yaml which returns a ruamel_yaml.comments.CommentedSeq\n    # this doesn't dump correctly using pyyaml\n    channels = list(context.channels)\n    if not ignore_channels:\n        for dist in conda_pkgs:\n            if dist.channel not in channels:\n                channels.insert(0, dist.channel)\n    return Environment(name=name, dependencies=dependencies, channels=channels, prefix=prefix)\n\n\ndef from_yaml(yamlstr, **kwargs):\n    \"\"\"Load and return a ``Environment`` from a given ``yaml string``\"\"\"\n    data = yaml.load(yamlstr)\n    if kwargs is not None:\n        for key, value in kwargs.items():\n            data[key] = value\n    return Environment(**data)\n\n\ndef from_file(filename):\n    if not os.path.exists(filename):\n        raise exceptions.EnvironmentFileNotFound(filename)\n    with open(filename, 'r') as fp:\n        yamlstr = fp.read()\n        return from_yaml(yamlstr, filename=filename)\n\n\n# TODO test explicitly\nclass Dependencies(OrderedDict):\n    def __init__(self, raw, *args, **kwargs):\n        super(Dependencies, self).__init__(*args, **kwargs)\n        self.raw = raw\n        self.parse()\n\n    def parse(self):\n        if not self.raw:\n            return\n\n        self.update({'conda': []})\n\n        for line in self.raw:\n            if isinstance(line, dict):\n                self.update(line)\n            else:\n                self['conda'].append(common.arg2spec(line))\n\n    # TODO only append when it's not already present\n    def add(self, package_name):\n        self.raw.append(package_name)\n        self.parse()\n\n\ndef unique(seq, key=None):\n    \"\"\" Return only unique elements of a sequence\n    >>> tuple(unique((1, 2, 3)))\n    (1, 2, 3)\n    >>> tuple(unique((1, 2, 1, 3)))\n    (1, 2, 3)\n    Uniqueness can be defined by key keyword\n    >>> tuple(unique(['cat', 'mouse', 'dog', 'hen'], key=len))\n    ('cat', 'mouse')\n    \"\"\"\n    seen = set()\n    seen_add = seen.add\n    if key is None:\n        for item in seq:\n            if item not in seen:\n                seen_add(item)\n                yield item\n    else:  # calculate key\n        for item in seq:\n            val = key(item)\n            if val not in seen:\n                seen_add(val)\n                yield item\n\n\nclass Environment(object):\n    def __init__(self, name=None, filename=None, channels=None,\n                 dependencies=None, prefix=None):\n        self.name = name\n        self.filename = filename\n        self.prefix = prefix\n        self.dependencies = Dependencies(dependencies)\n\n        if channels is None:\n            channels = []\n        self.channels = channels\n\n    def add_channels(self, channels):\n        self.channels = list(unique(chain.from_iterable((channels, self.channels))))\n\n    def remove_channels(self):\n        self.channels = []\n\n    def to_dict(self):\n        d = yaml.dict([('name', self.name)])\n        if self.channels:\n            d['channels'] = self.channels\n        if self.dependencies:\n            d['dependencies'] = self.dependencies.raw\n        if self.prefix:\n            d['prefix'] = self.prefix\n        return d\n\n    def to_yaml(self, stream=None):\n        d = self.to_dict()\n        out = compat.u(yaml.dump(d, default_flow_style=False))\n        if stream is None:\n            return out\n        stream.write(compat.b(out, encoding=\"utf-8\"))\n\n    def save(self):\n        with open(self.filename, \"wb\") as fp:\n            self.to_yaml(stream=fp)\n", "path": "conda_env/env.py"}]}