from .compat import parse_http_list as _parse_list_header from .compat import quote, urlparse, bytes, str, OrderedDict, urlunparse from .cookies import RequestsCookieJar, cookiejar_from_dict<ins>from .structures import CaseInsensitiveDict</ins>  _hush_pyflakes = (RequestsCookieJar,)


def default_headers():    return {    return CaseInsensitiveDict({         'User-Agent': default_user_agent(),         'Accept-Encoding': ', '.join(('gzip', 'deflate', 'compress')),         'Accept': '*/*'    }    })   def parse_header_links(value):


val = [val]             for v in val:                 if v is not None:<ins>                    # Don't call str() on bytestrings: in Py3 it all goes wrong.                    if not isinstance(v, bytes):                        v = str(v)</ins>                     new_fields.append(                         (field.decode('utf-8') if isinstance(field, bytes) else field,                          v.encode('utf-8') if isinstance(v, str) else v))


return c  def cookiejar_from_dict(cookie_dict, cookiejar=None):def cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True):     """Returns a CookieJar from a key/value dictionary.      :param cookie_dict: Dict of key/values to insert into CookieJar.    :param cookiejar: (optional) A cookiejar to add the cookies to.    :param overwrite: (optional) If False, will not replace cookies        already in the jar with new ones.     """     if cookiejar is None:         cookiejar = RequestsCookieJar()      if cookie_dict is not None:        names_from_jar = [cookie.name for cookie in cookiejar]         for name in cookie_dict:            cookiejar.set_cookie(create_cookie(name, cookie_dict[name]))            if overwrite or (name not in names_from_jar):                cookiejar.set_cookie(create_cookie(name, cookie_dict[name]))     return cookiejardiff --git a/requests/models.py b/requests/models.py-- a/requests/models.py++ b/requests/models.py


p = PreparedRequest()         p.method = self.method         p.url = self.url        p.headers = self.headers        p.headers = self.headers.copy()         p.body = self.body         p.hooks = self.hooks         return pdiff --git a/requests/sessions.py b/requests/sessions.py-- a/requests/sessions.py++ b/requests/sessions.py


)         prep = self.prepare_request(req) <ins>        # Add param cookies to session cookies        self.cookies = cookiejar_from_dict(cookies, cookiejar=self.cookies, overwrite=False)</ins>         proxies = proxies or {}          # Gather clues from the surrounding environment.


return merged_setting  <ins>def merge_hooks(request_hooks, session_hooks, dict_class=OrderedDict):    """    Properly merges both requests and session hooks.    This is necessary because when request_hooks == {'response': []}, the    merge breaks Session hooks entirely.    """    if session_hooks is None or session_hooks.get('response') == []:        return request_hooks    if request_hooks is None or request_hooks.get('response') == []:        return session_hooks    return merge_setting(request_hooks, session_hooks, dict_class)</ins> class SessionRedirectMixin(object):     def resolve_redirects(self, resp, req, stream=False, timeout=None,                           verify=True, cert=None, proxies=None):


params=merge_setting(request.params, self.params),             auth=merge_setting(auth, self.auth),             cookies=merged_cookies,            hooks=merge_setting(request.hooks, self.hooks),            hooks=merge_hooks(request.hooks, self.hooks),         )         return p


raise NotImplementedError('Streamed bodies and files are mutually exclusive.')              if length is not None:                self.headers['Content-Length'] = str(length)                self.headers['Content-Length'] = builtin_str(length)             else:                 self.headers['Transfer-Encoding'] = 'chunked'         else:


def prepare_content_length(self, body):         if hasattr(body, 'seek') and hasattr(body, 'tell'):             body.seek(0, 2)            self.headers['Content-Length'] = str(body.tell())            self.headers['Content-Length'] = builtin_str(body.tell())             body.seek(0, 0)         elif body is not None:             l = super_len(body)             if l:                self.headers['Content-Length'] = str(l)                self.headers['Content-Length'] = builtin_str(l)         elif self.method not in ('GET', 'HEAD'):             self.headers['Content-Length'] = '0'


cookiejar.set_cookie(create_cookie(name, cookie_dict[name]))      return cookiejardef merge_cookies(cookiejar, cookies):    """Add cookies to cookiejar and returns a merged CookieJar.    :param cookiejar: CookieJar object to add the cookies to.    :param cookies: Dictionary or CookieJar object to be added.    """    if not isinstance(cookiejar, cookielib.CookieJar):        raise ValueError('You can only merge into CookieJar')        if isinstance(cookies, dict):        cookiejar = cookiejar_from_dict(            cookies, cookiejar=cookiejar, overwrite=False)    elif isinstance(cookies, cookielib.CookieJar):        try:            cookiejar.update(cookies)        except AttributeError:            for cookie_in_jar in cookies:                cookiejar.set_cookie(cookie_in_jar)    return cookiejardiff --git a/requests/sessions.py b/requests/sessions.py-- a/requests/sessions.py++ b/requests/sessions.py


from datetime import datetime  from .compat import cookielib, OrderedDict, urljoin, urlparse, builtin_strfrom .cookies import cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJarfrom .cookies import (    cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies) from .models import Request, PreparedRequest from .hooks import default_hooks, dispatch_hook from .utils import to_key_val_list, default_headers


cookies = cookiejar_from_dict(cookies)          # Merge with session cookies        merged_cookies = RequestsCookieJar()        merged_cookies.update(self.cookies)        merged_cookies.update(cookies)        merged_cookies = merge_cookies(            merge_cookies(RequestsCookieJar(), self.cookies), cookies)           # Set environment's basic authentication if not explicitly set.


prep = self.prepare_request(req)          # Add param cookies to session cookies        self.cookies = cookiejar_from_dict(cookies, cookiejar=self.cookies, overwrite=False)        self.cookies = merge_cookies(self.cookies, cookies)          proxies = proxies or {}


from collections import Mapping from datetime import datetime from .compat import cookielib, OrderedDict, urljoin, urlparse, urlunparsefrom .compat import cookielib, OrderedDict, urljoin, urlparse, urlunparse, builtin_str from .cookies import cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar from .models import Request, PreparedRequest from .hooks import default_hooks, dispatch_hook


:param cert: (optional) if String, path to ssl client cert file (.pem).             If Tuple, ('cert', 'key') pair.         """<ins>        method = builtin_str(method)</ins>         # Create the Request.         req = Request(             method = method.upper(),


A1 = '%s:%s:%s' % (self.username, realm, self.password)         A2 = '%s:%s' % (method, path)<del>        </del><ins></ins>         HA1 = hash_utf8(A1)         HA2 = hash_utf8(A2)


if entdig:             base += ', digest="%s"' % entdig         if qop:            base += ', qop=auth, nc=%s, cnonce="%s"' % (ncvalue, cnonce)            base += ', qop="auth", nc=%s, cnonce="%s"' % (ncvalue, cnonce)          return 'Digest %s' % (base)


from . import __version__ from . import certs from .compat import parse_http_list as _parse_list_headerfrom .compat import (quote, urlparse, bytes, str, OrderedDict, urlunparse,                     is_py2, is_py3, builtin_str, getproxies, proxy_bypass)from .compat import (quote, urlparse, bytes, str, OrderedDict, unquote, is_py2,                     builtin_str, getproxies, proxy_bypass) from .cookies import RequestsCookieJar, cookiejar_from_dict from .structures import CaseInsensitiveDict from .exceptions import MissingSchema, InvalidURL


"""Given a url with authentication components, extract them into a tuple of     username,password."""     if url:<ins>        url = unquote(url)</ins>         parsed = urlparse(url)         return (parsed.username, parsed.password)     else:


from base64 import b64encode  from .compat import urlparse, str<ins>from .cookies import extract_cookies_to_jar</ins> from .utils import parse_dict_header  log = logging.getLogger(__name__)


r.content             r.raw.release_conn()             prep = r.request.copy()            prep.prepare_cookies(r.cookies)            extract_cookies_to_jar(prep._cookies, r.request, r.raw)            prep.prepare_cookies(prep._cookies)              prep.headers['Authorization'] = self.build_digest_header(                 prep.method, prep.url)diff --git a/requests/models.py b/requests/models.py-- a/requests/models.py++ b/requests/models.py


self.url = None         #: dictionary of HTTP headers.         self.headers = None<ins>        # The `CookieJar` used to create the Cookie header will be stored here        # after prepare_cookies is called        self._cookies = None</ins>         #: request body to send to the server.         self.body = None         #: dictionary of callback hooks, for internal usage.


p.method = self.method         p.url = self.url         p.headers = self.headers.copy()<ins>        p._cookies = self._cookies.copy()</ins>         p.body = self.body         p.hooks = self.hooks         return p


"""Prepares the given HTTP cookie data."""          if isinstance(cookies, cookielib.CookieJar):            cookies = cookies            self._cookies = cookies         else:            cookies = cookiejar_from_dict(cookies)            self._cookies = cookiejar_from_dict(cookies)         if 'cookie' not in self.headers:            cookie_header = get_cookie_header(cookies, self)            if cookie_header is not None:                self.headers['Cookie'] = cookie_header        cookie_header = get_cookie_header(self._cookies, self)        if cookie_header is not None:            self.headers['Cookie'] = cookie_header      def prepare_hooks(self, hooks):         """Prepares the given hooks."""diff --git a/requests/sessions.py b/requests/sessions.py-- a/requests/sessions.py++ b/requests/sessions.py


except KeyError:                 pass             prepared_request.prepare_cookies(self.cookies)            extract_cookies_to_jar(prepared_request._cookies,                                   prepared_request, resp.raw)            prepared_request.prepare_cookies(prepared_request._cookies)              resp = self.send(                 prepared_request,


)         prep = self.prepare_request(req) <del>        # Add param cookies to session cookies        self.cookies = merge_cookies(self.cookies, cookies)</del>         proxies = proxies or {}          # Gather clues from the surrounding environment.


cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies) from .models import Request, PreparedRequest from .hooks import default_hooks, dispatch_hookfrom .utils import to_key_val_list, default_headersfrom .utils import to_key_val_list, default_headers, to_native_string from .exceptions import TooManyRedirects, InvalidSchema from .structures import CaseInsensitiveDict


else:                 url = requote_uri(url)             prepared_request.url = url            prepared_request.url = to_native_string(url)              # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4             if (resp.status_code == codes.see_other and


if v is None:             del merged_setting[k] <ins>    merged_setting = dict((k, v) for (k, v) in merged_setting.items() if v is not None)</ins>     return merged_setting


else:                 raise         r = self.build_response(request, resp)        if not stream:            r.content        return r        return self.build_response(request, resp)diff --git a/requests/sessions.py b/requests/sessions.py-- a/requests/sessions.py++ b/requests/sessions.py


from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT from .hooks import default_hooks, dispatch_hook from .utils import to_key_val_list, default_headers, to_native_stringfrom .exceptions import TooManyRedirects, InvalidSchemafrom .exceptions import (    TooManyRedirects, InvalidSchema, ChunkedEncodingError, ContentDecodingError) from .structures import CaseInsensitiveDict  from .adapters import HTTPAdapter


while resp.is_redirect:             prepared_request = req.copy()             resp.content  # Consume socket so it can be released            try:                resp.content  # Consume socket so it can be released            except (ChunkedEncodingError, ContentDecodingError, RuntimeError):                resp.raw.read(decode_content=False)              if i >= self.max_redirects:                 raise TooManyRedirects('Exceeded %s redirects.' % self.max_redirects)


r = history.pop()             r.history = history <ins>        if not stream:            r.content</ins>         return r      def get_adapter(self, url):


history.insert(0, r)             # Get the last request made             r = history.pop()            r.history = tuple(history)            r.history = history          return r


if new_auth is not None:                 prepared_request.prepare_auth(new_auth)             # Override the original request.            req = prepared_request             resp = self.send(                prepared_request,                req,                 stream=stream,                 timeout=timeout,                 verify=verify,


import collections import datetime<ins>import socket</ins>  from io import BytesIO, UnsupportedOperation from .hooks import default_hooks


from .packages.urllib3.exceptions import DecodeError from .exceptions import (     HTTPError, RequestException, MissingSchema, InvalidURL,    ChunkedEncodingError, ContentDecodingError)    ChunkedEncodingError, ContentDecodingError, ConnectionError) from .utils import (     guess_filename, get_auth_from_url, requote_uri,     stream_decode_response_unicode, to_key_val_list, parse_header_links,


raise ChunkedEncodingError(e)                 except DecodeError as e:                     raise ContentDecodingError(e)<ins>                except socket.error as e:                    raise ConnectionError(e)</ins>             except AttributeError:                 # Standard file-like object.                 while True:


from Cookie import Morsel     from StringIO import StringIO     from .packages.urllib3.packages.ordered_dict import OrderedDict<del>    from httplib import IncompleteRead</del>      builtin_str = str     bytes = str


from http.cookies import Morsel     from io import StringIO     from collections import OrderedDict    from http.client import IncompleteRead      builtin_str = str     str = strdiff --git a/requests/models.py b/requests/models.py-- a/requests/models.py++ b/requests/models.py


import collections import datetime<del>import socket</del>  from io import BytesIO, UnsupportedOperation from .hooks import default_hooks


from .packages.urllib3.fields import RequestField from .packages.urllib3.filepost import encode_multipart_formdata from .packages.urllib3.util import parse_urlfrom .packages.urllib3.exceptions import DecodeErrorfrom .packages.urllib3.exceptions import (    DecodeError, ReadTimeoutError, ProtocolError) from .exceptions import (     HTTPError, RequestException, MissingSchema, InvalidURL,     ChunkedEncodingError, ContentDecodingError, ConnectionError)


iter_slices, guess_json_utf, super_len, to_native_string) from .compat import (     cookielib, urlunparse, urlsplit, urlencode, str, bytes, StringIO,    is_py2, chardet, json, builtin_str, basestring, IncompleteRead)    is_py2, chardet, json, builtin_str, basestring) from .status_codes import codes  #: The set of HTTP status codes that indicate an automatically


try:                     for chunk in self.raw.stream(chunk_size, decode_content=True):                         yield chunk                except IncompleteRead as e:                except ProtocolError as e:                     raise ChunkedEncodingError(e)                 except DecodeError as e:                     raise ContentDecodingError(e)                except socket.error as e:                except ReadTimeoutError as e:                     raise ConnectionError(e)             except AttributeError:                 # Standard file-like object.


from datetime import datetime  from .auth import _basic_auth_strfrom .compat import cookielib, OrderedDict, urljoin, urlparse, builtin_strfrom .compat import cookielib, OrderedDict, urljoin, urlparse from .cookies import (     cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies) from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT


If Tuple, ('cert', 'key') pair.         """         method = builtin_str(method)        method = to_native_string(method)          # Create the Request.         req = Request(


This function passes the given URI through an unquote/quote cycle to     ensure that it is fully and consistently quoted.     """    # Unquote only the unreserved characters    # Then quote only illegal characters (do not quote reserved, unreserved,    # or '%')    return quote(unquote_unreserved(uri), safe="!#$%&'()*+,/:;=?@[]~")    safe_with_percent = "!#$%&'()*+,/:;=?@[]~"    safe_without_percent = "!#$&'()*+,/:;=?@[]~"    try:        # Unquote only the unreserved characters        # Then quote only illegal characters (do not quote reserved,        # unreserved, or '%')        return quote(unquote_unreserved(uri), safe=safe_with_percent)    except InvalidURL:        # We couldn't unquote the given URI, so let's try quoting it, but        # there may be unquoted '%'s in the URI. We need to make sure they're        # properly quoted so they do not cause issues elsewhere.        return quote(uri, safe=safe_without_percent)   def address_in_network(ip, net):


basestring = basestring     numeric_types = (int, long, float)  elif is_py3:     from urllib.parse import urlparse, urlunparse, urljoin, urlsplit, urlencode, quote, unquote, quote_plus, unquote_plus, urldefrag     from urllib.request import parse_http_list, getproxies, proxy_bypassdiff --git a/requests/utils.py b/requests/utils.py-- a/requests/utils.py++ b/requests/utils.py


from . import certs from .compat import parse_http_list as _parse_list_header from .compat import (quote, urlparse, bytes, str, OrderedDict, unquote, is_py2,                     builtin_str, getproxies, proxy_bypass, urlunparse)                     builtin_str, getproxies, proxy_bypass, urlunparse,                     basestring) from .cookies import RequestsCookieJar, cookiejar_from_dict from .structures import CaseInsensitiveDict from .exceptions import InvalidURL


def guess_filename(obj):     """Tries to guess the filename of the given object."""     name = getattr(obj, 'name', None)    if name and isinstance(name, builtin_str) and name[0] != '<' and name[-1] != '>':    if (name and isinstance(name, basestring) and name[0] != '<' and            name[-1] != '>'):         return os.path.basename(name)


class VendorAlias(object):     def __init__(self):    def __init__(self, package_names):        self._package_names = package_names         self._vendor_name = __name__         self._vendor_pkg = self._vendor_name + "."        self._vendor_pkgs = [            self._vendor_pkg + name for name in self._package_names        ]      def find_module(self, fullname, path=None):         if fullname.startswith(self._vendor_pkg):


)             ) <ins>        if not (name == self._vendor_name or                any(name.startswith(pkg) for pkg in self._vendor_pkgs)):            raise ImportError(                "Cannot import %s, must be one of %s." % (                    name, self._vendor_pkgs                )            )</ins>         # Check to see if we already have this item in sys.modules, if we do         # then simply return that.         if name in sys.modules:


return module  sys.meta_path.append(VendorAlias())sys.meta_path.append(VendorAlias(["urllib3", "chardet"]))


def prepare_method(self, method):         """Prepares the given HTTP method."""         self.method = method        if self.method is not None:            self.method = self.method.upper()        if self.method is None:            raise ValueError('Request method cannot be "None"')        self.method = to_native_string(self.method).upper()      def prepare_url(self, url, params):         """Prepares the given HTTP URL."""diff --git a/requests/sessions.py b/requests/sessions.py-- a/requests/sessions.py++ b/requests/sessions.py


:param cert: (optional) if String, path to ssl client cert file (.pem).             If Tuple, ('cert', 'key') pair.         """<del>        method = to_native_string(method)</del>         # Create the Request.         req = Request(             method = method.upper(),


from .utils import (DEFAULT_CA_BUNDLE_PATH, get_encoding_from_headers,                     prepend_scheme_if_needed, get_auth_from_url, urldefragauth) from .structures import CaseInsensitiveDict<ins>from .packages.urllib3.exceptions import ClosedPoolError</ins> from .packages.urllib3.exceptions import ConnectTimeoutError from .packages.urllib3.exceptions import HTTPError as _HTTPError from .packages.urllib3.exceptions import MaxRetryError


raise ConnectionError(e, request=request) <ins>        except ClosedPoolError as e:            raise ConnectionError(e, request=request)</ins>         except _ProxyError as e:             raise ProxyError(e)


from datetime import datetime  from .auth import _basic_auth_strfrom .compat import cookielib, OrderedDict, urljoin, urlparsefrom .compat import cookielib, OrderedDict, urljoin, urlparse, is_py3, str from .cookies import (     cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies) from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT


parsed = urlparse(location_url)             location_url = parsed.geturl()             # On Python 3, the location header was decoded using Latin 1, but            # urlparse in requote_uri will encode it with UTF-8 before quoting.            # Because of this insanity, we need to fix it up ourselves by            # sending the URL back to bytes ourselves.            if is_py3 and isinstance(location_url, str):                location_url = location_url.encode('latin1')             # Facilitate relative 'location' headers, as allowed by RFC 7231.             # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource')             # Compliant with RFC3986, we percent encode the url.diff --git a/requests/utils.py b/requests/utils.py-- a/requests/utils.py++ b/requests/utils.py


from .compat import parse_http_list as _parse_list_header from .compat import (quote, urlparse, bytes, str, OrderedDict, unquote, is_py2,                      builtin_str, getproxies, proxy_bypass, urlunparse,                     basestring)                     basestring, is_py3) from .cookies import RequestsCookieJar, cookiejar_from_dict from .structures import CaseInsensitiveDict from .exceptions import InvalidURL, FileModeWarning


"""Un-escape any percent-escape sequences in a URI that are unreserved     characters. This leaves all reserved, illegal and non-ASCII bytes encoded.     """    parts = uri.split('%')    # This convert function is used to optionally convert the output of `chr`.    # In Python 3, `chr` returns a unicode string, while in Python 2 it returns    # a bytestring. Here we deal with that by optionally converting.    def convert(is_bytes, c):        if is_py2 and not is_bytes:            return c.decode('ascii')        elif is_py3 and is_bytes:            return c.encode('ascii')        else:            return c    # Handle both bytestrings and unicode strings.    is_bytes = isinstance(uri, bytes)    splitchar = u'%'    base = u''    if is_bytes:        splitchar = splitchar.encode('ascii')        base = base.encode('ascii')    parts = uri.split(splitchar)     for i in range(1, len(parts)):         h = parts[i][0:2]         if len(h) == 2 and h.isalnum():


raise InvalidURL("Invalid percent-escape sequence: '%s'" % h)              if c in UNRESERVED_SET:                parts[i] = c + parts[i][2:]                parts[i] = convert(is_bytes, c) + parts[i][2:]             else:                parts[i] = '%' + parts[i]                parts[i] = splitchar + parts[i]         else:            parts[i] = '%' + parts[i]    return ''.join(parts)            parts[i] = splitchar + parts[i]    return base.join(parts)   def requote_uri(uri):


"""Prepares the given HTTP method."""         self.method = method         if self.method is not None:            self.method = self.method.upper()            self.method = to_native_string(self.method.upper())      def prepare_url(self, url, params):         """Prepares the given HTTP URL."""diff --git a/requests/sessions.py b/requests/sessions.py-- a/requests/sessions.py++ b/requests/sessions.py


def super_len(o):    total_length = 0    current_position = 0     if hasattr(o, '__len__'):        return len(o)        total_length = len(o)    elif hasattr(o, 'len'):        total_length = o.len     if hasattr(o, 'len'):        return o.len    elif hasattr(o, 'getvalue'):        # e.g. BytesIO, cStringIO.StringIO        total_length = len(o.getvalue())     if hasattr(o, 'fileno'):    elif hasattr(o, 'fileno'):         try:             fileno = o.fileno()         except io.UnsupportedOperation:             pass         else:            filesize = os.fstat(fileno).st_size            total_length = os.fstat(fileno).st_size              # Having used fstat to determine the file length, we need to             # confirm that this file was opened up in binary mode.


FileModeWarning                 )             return filesize    if hasattr(o, 'tell'):        current_position = o.tell()     if hasattr(o, 'getvalue'):        # e.g. BytesIO, cStringIO.StringIO        return len(o.getvalue())    return max(0, total_length - current_position)   def get_netrc_auth(url, raise_errors=False):


"""          if isinstance(data, (str, bytes)):            return to_native_string(data)            return data         elif hasattr(data, 'read'):             return data         elif hasattr(data, '__iter__'):


if isinstance(fragment, str):                 fragment = fragment.encode('utf-8') <ins>        if isinstance(params, (str, bytes)):            params = to_native_string(params)</ins>         enc_params = self._encode_params(params)         if enc_params:             if query:


def stream_decode_response_unicode(iterator, r):     """Stream decodes a iterator."""    encoding = r.encoding     if r.encoding is None:        for item in iterator:            yield item        return    if encoding is None:        encoding = r.apparent_encoding    try:        decoder = codecs.getincrementaldecoder(encoding)(errors='replace')    except (LookupError, TypeError):        # A LookupError is raised if the encoding was not found which could        # indicate a misspelling or similar mistake.        #        # A TypeError can be raised if encoding is None        raise UnicodeError("Unable to decode contents with encoding %s." % encoding)     decoder = codecs.getincrementaldecoder(r.encoding)(errors='replace')     for chunk in iterator:         rv = decoder.decode(chunk)         if rv:


raise RuntimeError(                     'The content for this response was already consumed')             if self.status_code == 0:            if self.status_code == 0 or self.raw is None:                 self._content = None             else:                 self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()


url = url.lstrip()          # Don't do any URL preparation for non-HTTP schemes like `mailto`,        # `data`, `http+unix` etc to work around exceptions from `url_parse`,        # which handles RFC 3986 only.        if ':' in url and not url.lower().startswith(('http://', 'https://')):        # `data` etc to work around exceptions from `url_parse`, which        # handles RFC 3986 only.        if ':' in url and not url.lower().startswith('http'):             self.url = url             return


# I don't like it either. Just look the other way. :)  for package in ('urllib3', 'idna', 'chardet'):    __import__(package)    locals()[package] = __import__(package)     # This traversal is apparently necessary such that the identities are     # preserved (requests.packages.urllib3.* is urllib3.*)     for mod in list(sys.modules):


from urllib3.poolmanager import PoolManager, proxy_from_url from urllib3.response import HTTPResponse<ins>from urllib3.util import parse_url</ins> from urllib3.util import Timeout as TimeoutSauce from urllib3.util.retry import Retry from urllib3.exceptions import ClosedPoolError


from .structures import CaseInsensitiveDict from .cookies import extract_cookies_to_jar from .exceptions import (ConnectionError, ConnectTimeout, ReadTimeout, SSLError,                         ProxyError, RetryError, InvalidSchema)                         ProxyError, RetryError, InvalidSchema, InvalidProxyURL) from .auth import _basic_auth_str  try:


if proxy:             proxy = prepend_scheme_if_needed(proxy, 'http')            proxy_url = parse_url(proxy)            if not proxy_url.host:                raise InvalidProxyURL("Please check proxy URL. It is malformed"                                      " and could be missing the host.")             proxy_manager = self.proxy_manager_for(proxy)             conn = proxy_manager.connection_from_url(url)         else:diff --git a/requests/exceptions.py b/requests/exceptions.py-- a/requests/exceptions.py++ b/requests/exceptions.py


"""The header value provided was somehow invalid."""  <ins>class InvalidProxyURL(InvalidURL):    """The proxy URL provided is invalid."""</ins> class ChunkedEncodingError(RequestException):     """The server declared chunked encoding but sent an invalid chunk."""


return to_native_string(location, 'utf8')         return None <ins>    def should_strip_auth(self, old_url, new_url):        """Decide whether Authorization header should be removed when redirecting"""        old_parsed = urlparse(old_url)        new_parsed = urlparse(new_url)        if old_parsed.hostname != new_parsed.hostname:            return True        # Special case: allow http -> https redirect when using the standard        # ports. This isn't specified by RFC 7235, but is kept to avoid        # breaking backwards compatibility with older versions of requests        # that allowed any redirects on the same host.        if (old_parsed.scheme == 'http' and old_parsed.port in (80, None)                and new_parsed.scheme == 'https' and new_parsed.port in (443, None)):            return False        # Standard case: root URI must match        return old_parsed.port != new_parsed.port or old_parsed.scheme != new_parsed.scheme</ins>     def resolve_redirects(self, resp, req, stream=False, timeout=None,                           verify=True, cert=None, proxies=None, yield_requests=False, **adapter_kwargs):         """Receives a Response. Returns a generator of Responses or Requests."""


headers = prepared_request.headers         url = prepared_request.url         if 'Authorization' in headers:        if 'Authorization' in headers and self.should_strip_auth(response.request.url, url):             # If we get redirected to a new host, we should strip out any             # authentication headers.            original_parsed = urlparse(response.request.url)            redirect_parsed = urlparse(url)            if (original_parsed.hostname != redirect_parsed.hostname):                del headers['Authorization']            del headers['Authorization']          # .netrc might have more auth for us on our new host.         new_auth = get_netrc_auth(url) if self.trust_env else None


#: is a response.         self.request = None <ins>        #: If there was an error in the processing of content,        #: then save the error that would return the same error when you re-appeal.        self._error = None</ins>     def __enter__(self):         return self


try:                     for chunk in self.raw.stream(chunk_size, decode_content=True):                         yield chunk                 except ProtocolError as e:                    raise ChunkedEncodingError(e)                    self._error = ChunkedEncodingError(e)                 except DecodeError as e:                    raise ContentDecodingError(e)                    self._error = ContentDecodingError(e)                 except ReadTimeoutError as e:                    raise ConnectionError(e)                    self._error = ConnectionError(e)                finally:                    # if we had an error - throw the saved error                    if self._error:                        raise self._error             else:                 # Standard file-like object.                 while True:


else:                 self._content = b''.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b'' <ins>        # if we had an error - throw the saved error        if self._error is not None:            raise self._error</ins>         self._content_consumed = True         # don't need to release the connection; that's been handled by urllib3         # since we exhausted the data.


host = self._get_idna_encoded_host(host)             except UnicodeError:                 raise InvalidURL('URL has an invalid label.')        elif host.startswith(u'*'):        elif host.startswith((u'*', u'.')):             raise InvalidURL('URL has an invalid label.')          # Carefully reconstruct the network location


if not netloc:         netloc, path = path, netloc <ins>    if auth:        # parse_url doesn't provide the netloc with auth        # so we'll add it ourselves.        netloc = '@'.join([auth, netloc])</ins>     if scheme is None:         scheme = new_scheme     if path is None:


if not scheme in SCHEMAS:             raise InvalidSchema("Invalid scheme %r" % scheme)         netloc = netloc.encode('idna').decode('utf-8')        try:            netloc = netloc.encode('idna').decode('utf-8')        except UnicodeError:            raise InvalidURL('URL has an invalid label.')          if not path:             path = '/'


def register_hook(self, event, hook):         """Properly register a hook."""        self.hooks[event].append(hook)        if isinstance(hook, (list, tuple, set)):            self.hooks[event].extend(hook)        else:            self.hooks[event].append(hook)      def deregister_hook(self, event, hook):         """Deregister a previously registered hook.


data = np.timedelta64(getattr(data, "value", data), "ns")      # we don't want nested self-described arrays    data = getattr(data, "values", data)    if isinstance(data, (pd.Series, pd.Index, pd.DataFrame)):        data = data.values      if isinstance(data, np.ma.MaskedArray):         mask = np.ma.getmaskarray(data)


},         )     def weighted(self, weights):        """        Weighted operations.        Parameters        ----------        weights : DataArray            An array of weights associated with the values in this Dataset.            Each value in the data contributes to the reduction operation            according to its associated weight.        Notes        -----        ``weights`` must be a DataArray and cannot contain missing values.        Missing values can be replaced by ``weights.fillna(0)``.        """        return self._weighted_cls(self, weights)     def rolling(         self,         dim: Mapping[Hashable, int] = None,diff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py-- a/xarray/core/dataarray.py++ b/xarray/core/dataarray.py


resample,     rolling,     utils,<ins>    weighted,</ins> ) from .accessor_dt import CombinedDatetimelikeAccessor from .accessor_str import StringAccessor


_rolling_cls = rolling.DataArrayRolling     _coarsen_cls = rolling.DataArrayCoarsen     _resample_cls = resample.DataArrayResample    _weighted_cls = weighted.DataArrayWeighted      dt = property(CombinedDatetimelikeAccessor) diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py-- a/xarray/core/dataset.py++ b/xarray/core/dataset.py


resample,     rolling,     utils,<ins>    weighted,</ins> ) from .alignment import _broadcast_helper, _get_broadcast_dims_map_common_coords, align from .common import (


_rolling_cls = rolling.DatasetRolling     _coarsen_cls = rolling.DatasetCoarsen     _resample_cls = resample.DatasetResample    _weighted_cls = weighted.DatasetWeighted      def __init__(         self,diff --git a/xarray/core/weighted.py b/xarray/core/weighted.pynew file mode 100644-- /dev/null++ b/xarray/core/weighted.py


<ins>from typing import TYPE_CHECKING, Hashable, Iterable, Optional, Union, overloadfrom .computation import dotfrom .options import _get_keep_attrsif TYPE_CHECKING:    from .dataarray import DataArray, Dataset_WEIGHTED_REDUCE_DOCSTRING_TEMPLATE = """    Reduce this {cls}'s data by a weighted ``{fcn}`` along some dimension(s).    Parameters    ----------    dim : str or sequence of str, optional        Dimension(s) over which to apply the weighted ``{fcn}``.    skipna : bool, optional        If True, skip missing values (as marked by NaN). By default, only        skips missing values for float dtypes; other dtypes either do not        have a sentinel missing value (int) or skipna=True has not been        implemented (object, datetime64 or timedelta64).    keep_attrs : bool, optional        If True, the attributes (``attrs``) will be copied from the original        object to the new one.  If False (default), the new object will be        returned without attributes.    Returns    -------    reduced : {cls}        New {cls} object with weighted ``{fcn}`` applied to its data and        the indicated dimension(s) removed.    Notes    -----        Returns {on_zero} if the ``weights`` sum to 0.0 along the reduced        dimension(s).    """_SUM_OF_WEIGHTS_DOCSTRING = """    Calculate the sum of weights, accounting for missing values in the data    Parameters    ----------    dim : str or sequence of str, optional        Dimension(s) over which to sum the weights.    keep_attrs : bool, optional        If True, the attributes (``attrs``) will be copied from the original        object to the new one.  If False (default), the new object will be        returned without attributes.    Returns    -------    reduced : {cls}        New {cls} object with the sum of the weights over the given dimension.    """class Weighted:    """An object that implements weighted operations.    You should create a Weighted object by using the ``DataArray.weighted`` or    ``Dataset.weighted`` methods.    See Also    --------    Dataset.weighted    DataArray.weighted    """    __slots__ = ("obj", "weights")    @overload    def __init__(self, obj: "DataArray", weights: "DataArray") -> None:        ...    @overload  # noqa: F811    def __init__(self, obj: "Dataset", weights: "DataArray") -> None:  # noqa: F811        ...    def __init__(self, obj, weights):  # noqa: F811        """        Create a Weighted object        Parameters        ----------        obj : DataArray or Dataset            Object over which the weighted reduction operation is applied.        weights : DataArray            An array of weights associated with the values in the obj.            Each value in the obj contributes to the reduction operation            according to its associated weight.        Notes        -----        ``weights`` must be a ``DataArray`` and cannot contain missing values.        Missing values can be replaced by ``weights.fillna(0)``.        """        from .dataarray import DataArray        if not isinstance(weights, DataArray):            raise ValueError("`weights` must be a DataArray")        if weights.isnull().any():            raise ValueError(                "`weights` cannot contain missing values. "                "Missing values can be replaced by `weights.fillna(0)`."            )        self.obj = obj        self.weights = weights    @staticmethod    def _reduce(        da: "DataArray",        weights: "DataArray",        dim: Optional[Union[Hashable, Iterable[Hashable]]] = None,        skipna: Optional[bool] = None,    ) -> "DataArray":        """reduce using dot; equivalent to (da * weights).sum(dim, skipna)            for internal use only        """        # need to infer dims as we use `dot`        if dim is None:            dim = ...        # need to mask invalid values in da, as `dot` does not implement skipna        if skipna or (skipna is None and da.dtype.kind in "cfO"):            da = da.fillna(0.0)        # `dot` does not broadcast arrays, so this avoids creating a large        # DataArray (if `weights` has additional dimensions)        # maybe add fasttrack (`(da * weights).sum(dims=dim, skipna=skipna)`)        return dot(da, weights, dims=dim)    def _sum_of_weights(        self, da: "DataArray", dim: Optional[Union[Hashable, Iterable[Hashable]]] = None    ) -> "DataArray":        """ Calculate the sum of weights, accounting for missing values """        # we need to mask data values that are nan; else the weights are wrong        mask = da.notnull()        sum_of_weights = self._reduce(mask, self.weights, dim=dim, skipna=False)        # 0-weights are not valid        valid_weights = sum_of_weights != 0.0        return sum_of_weights.where(valid_weights)    def _weighted_sum(        self,        da: "DataArray",        dim: Optional[Union[Hashable, Iterable[Hashable]]] = None,        skipna: Optional[bool] = None,    ) -> "DataArray":        """Reduce a DataArray by a by a weighted ``sum`` along some dimension(s)."""        return self._reduce(da, self.weights, dim=dim, skipna=skipna)    def _weighted_mean(        self,        da: "DataArray",        dim: Optional[Union[Hashable, Iterable[Hashable]]] = None,        skipna: Optional[bool] = None,    ) -> "DataArray":        """Reduce a DataArray by a weighted ``mean`` along some dimension(s)."""        weighted_sum = self._weighted_sum(da, dim=dim, skipna=skipna)        sum_of_weights = self._sum_of_weights(da, dim=dim)        return weighted_sum / sum_of_weights    def _implementation(self, func, dim, **kwargs):        raise NotImplementedError("Use `Dataset.weighted` or `DataArray.weighted`")    def sum_of_weights(        self,        dim: Optional[Union[Hashable, Iterable[Hashable]]] = None,        keep_attrs: Optional[bool] = None,    ) -> Union["DataArray", "Dataset"]:        return self._implementation(            self._sum_of_weights, dim=dim, keep_attrs=keep_attrs        )    def sum(        self,        dim: Optional[Union[Hashable, Iterable[Hashable]]] = None,        skipna: Optional[bool] = None,        keep_attrs: Optional[bool] = None,    ) -> Union["DataArray", "Dataset"]:        return self._implementation(            self._weighted_sum, dim=dim, skipna=skipna, keep_attrs=keep_attrs        )    def mean(        self,        dim: Optional[Union[Hashable, Iterable[Hashable]]] = None,        skipna: Optional[bool] = None,        keep_attrs: Optional[bool] = None,    ) -> Union["DataArray", "Dataset"]:        return self._implementation(            self._weighted_mean, dim=dim, skipna=skipna, keep_attrs=keep_attrs        )    def __repr__(self):        """provide a nice str repr of our Weighted object"""        klass = self.__class__.__name__        weight_dims = ", ".join(self.weights.dims)        return f"{klass} with weights along dimensions: {weight_dims}"class DataArrayWeighted(Weighted):    def _implementation(self, func, dim, **kwargs):        keep_attrs = kwargs.pop("keep_attrs")        if keep_attrs is None:            keep_attrs = _get_keep_attrs(default=False)        weighted = func(self.obj, dim=dim, **kwargs)        if keep_attrs:            weighted.attrs = self.obj.attrs        return weightedclass DatasetWeighted(Weighted):    def _implementation(self, func, dim, **kwargs) -> "Dataset":        return self.obj.map(func, dim=dim, **kwargs)def _inject_docstring(cls, cls_name):    cls.sum_of_weights.__doc__ = _SUM_OF_WEIGHTS_DOCSTRING.format(cls=cls_name)    cls.sum.__doc__ = _WEIGHTED_REDUCE_DOCSTRING_TEMPLATE.format(        cls=cls_name, fcn="sum", on_zero="0"    )    cls.mean.__doc__ = _WEIGHTED_REDUCE_DOCSTRING_TEMPLATE.format(        cls=cls_name, fcn="mean", on_zero="NaN"    )_inject_docstring(DataArrayWeighted, "DataArray")_inject_docstring(DatasetWeighted, "Dataset")</ins>


from collections import defaultdict from contextlib import suppress from datetime import timedeltafrom typing import Sequencefrom typing import Any, Tuple, Sequence, Union  import numpy as np import pandas as pd  from . import duck_array_ops, nputils, utilsfrom .npcompat import DTypeLike from .pycompat import dask_array_type, integer_types from .utils import is_dict_like


class PandasIndexAdapter(ExplicitlyIndexedNDArrayMixin):    """Wrap a pandas.Index to preserve dtypes and handle explicit indexing."""    """Wrap a pandas.Index to preserve dtypes and handle explicit indexing.    """     def __init__(self, array, dtype=None):    def __init__(self, array: Any, dtype: DTypeLike = None):         self.array = utils.safe_cast_to_index(array)         if dtype is None:             if isinstance(array, pd.PeriodIndex):


dtype = np.dtype('O')             else:                 dtype = array.dtype        else:            dtype = np.dtype(dtype)         self._dtype = dtype      @property    def dtype(self):    def dtype(self) -> np.dtype:         return self._dtype     def __array__(self, dtype=None):    def __array__(self, dtype: DTypeLike = None) -> np.ndarray:         if dtype is None:             dtype = self.dtype         array = self.array


return np.asarray(array.values, dtype=dtype)      @property    def shape(self):    def shape(self) -> Tuple[int]:         # .shape is broken on pandas prior to v0.15.2         return (len(self.array),)     def __getitem__(self, indexer):    def __getitem__(            self, indexer    ) -> Union[        NumpyIndexingAdapter,        np.ndarray,        np.datetime64,        np.timedelta64,    ]:         key = indexer.tuple         if isinstance(key, tuple) and len(key) == 1:             # unpack key so it can index a pandas.Index object (pandas.Index


return result     def transpose(self, order):    def transpose(self, order) -> pd.Index:         return self.array  # self.array should be always one-dimensional     def __repr__(self):    def __repr__(self) -> str:         return ('%s(array=%r, dtype=%r)'                 % (type(self).__name__, self.array, self.dtype))    def copy(self, deep: bool = True) -> 'PandasIndexAdapter':        # Not the same as just writing `self.array.copy(deep=deep)`, as        # shallow copies of the underlying numpy.ndarrays become deep ones        # upon pickling        # >>> len(pickle.dumps((self.array, self.array)))        # 4000281        # >>> len(pickle.dumps((self.array, self.array.copy(deep=False))))        # 8000341        array = self.array.copy(deep=True) if deep else self.array        return PandasIndexAdapter(array, self._dtype)diff --git a/xarray/core/variable.py b/xarray/core/variable.py-- a/xarray/core/variable.py++ b/xarray/core/variable.py


data copied from original.         """         if data is None:            if deep:                # self._data should be a `PandasIndexAdapter` instance at this                # point, which doesn't have a copy method, so make a deep copy                # of the underlying `pandas.MultiIndex` and create a new                # `PandasIndexAdapter` instance with it.                data = PandasIndexAdapter(self._data.array.copy(deep=True))            else:                data = self._data            data = self._data.copy(deep=deep)         else:             data = as_compatible_data(data)             if self.shape != data.shape:


Mapping[Hashable, Any]] = None,                     axis=None, **dim_kwargs: Any) -> 'DataArray':         """Return a new object with an additional axis (or axes) inserted at        the corresponding position in the array shape.        the corresponding position in the array shape. The new object is a        view into the underlying array, not a copy.          If dim is already a scalar coordinate, it will be promoted to a 1D         coordinate consisting of a single value.diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py-- a/xarray/core/dataset.py++ b/xarray/core/dataset.py


def expand_dims(self, dim=None, axis=None, **dim_kwargs):         """Return a new object with an additional axis (or axes) inserted at        the corresponding position in the array shape.        the corresponding position in the array shape.  The new object is a        view into the underlying array, not a copy.          If dim is already a scalar coordinate, it will be promoted to a 1D         coordinate consisting of a single value.diff --git a/xarray/core/indexing.py b/xarray/core/indexing.py-- a/xarray/core/indexing.py++ b/xarray/core/indexing.py


def __setitem__(self, key, value):         array, key = self._indexing_array_and_key(key)        array[key] = value        try:            array[key] = value        except ValueError:            # More informative exception if read-only view            if not array.flags.writeable and not array.flags.owndata:                raise ValueError("Assignment destination is a view.  "                                 "Do you want to .copy() array first?")            else:                raise   class DaskIndexingAdapter(ExplicitlyIndexedNDArrayMixin):


fill_value=fill_value)          # Check the overall coordinates are monotonically increasing        for dim in concatenated.dims:            if dim in concatenated:                indexes = concatenated.indexes.get(dim)                if not (indexes.is_monotonic_increasing                        or indexes.is_monotonic_decreasing):                    raise ValueError("Resulting object does not have monotonic"                                     " global indexes along dimension {}"                                     .format(dim))        for dim in concat_dims:            indexes = concatenated.indexes.get(dim)            if not (indexes.is_monotonic_increasing                    or indexes.is_monotonic_decreasing):                raise ValueError("Resulting object does not have monotonic"                                 " global indexes along dimension {}"                                 .format(dim))         concatenated_grouped_by_data_vars.append(concatenated)      return merge(concatenated_grouped_by_data_vars, compat=compat,


raise TypeError('`group` must be an xarray.DataArray or the '                                 'name of an xarray variable or dimension')             group = obj[group]<ins>            if len(group) == 0:                raise ValueError("{} must not be empty".format(group.name))</ins>             if group.name not in obj.coords and group.name in obj.dims:                 # DummyGroups should not appear on groupby results                 group = _DummyGroup(obj, group.name, group.coords)


return new_coords, dims  <ins>def _check_data_shape(data, coords, dims):    if data is dtypes.NA:        data = np.nan    if coords is not None and utils.is_scalar(data, include_0d=False):        if utils.is_dict_like(coords):            if dims is None:                return data            else:                data_shape = tuple(                    as_variable(coords[k], k).size if k in coords.keys() else 1                    for k in dims                )        else:            data_shape = tuple(as_variable(coord, "foo").size for coord in coords)        data = np.full(data_shape, data)    return data</ins> class _LocIndexer:     def __init__(self, data_array: "DataArray"):         self.data_array = data_array


def __init__(         self,        data: Any,        data: Any = dtypes.NA,         coords: Union[Sequence[Tuple], Mapping[Hashable, Any], None] = None,         dims: Union[Hashable, Sequence[Hashable], None] = None,         name: Hashable = None,


if encoding is None:                 encoding = getattr(data, "encoding", None)             data = _check_data_shape(data, coords, dims)             data = as_compatible_data(data)             coords, dims = _infer_coords_and_dims(data.shape, coords, dims)             variable = Variable(dims, data, attrs, encoding, fastpath=True)diff --git a/xarray/core/utils.py b/xarray/core/utils.py-- a/xarray/core/utils.py++ b/xarray/core/utils.py


import numpy as np import pandas as pd <del>from .pycompat import dask_array_type</del> K = TypeVar("K") V = TypeVar("V") T = TypeVar("T")


return cast(Mapping[Hashable, T], kw_kwargs)  def is_scalar(value: Any) -> bool:def is_scalar(value: Any, include_0d: bool = True) -> bool:     """Whether to treat a value as a scalar.      Any non-iterable, string, or 0-D array     """    from .variable import NON_NUMPY_SUPPORTED_ARRAY_TYPES    if include_0d:        include_0d = getattr(value, "ndim", None) == 0     return (        getattr(value, "ndim", None) == 0        include_0d         or isinstance(value, (str, bytes))         or not (            isinstance(value, (Iterable,) + dask_array_type)            isinstance(value, (Iterable,) + NON_NUMPY_SUPPORTED_ARRAY_TYPES)             or hasattr(value, "__array_function__")         )     )


# the former is often more efficient                             reduce_dims = None                         variables[name] = var.quantile(                            q, dim=reduce_dims, interpolation=interpolation                            q,                            dim=reduce_dims,                            interpolation=interpolation,                            keep_attrs=keep_attrs,                         )              else:diff --git a/xarray/core/variable.py b/xarray/core/variable.py-- a/xarray/core/variable.py++ b/xarray/core/variable.py


"""         return self.broadcast_equals(other, equiv=duck_array_ops.array_notnull_equiv)     def quantile(self, q, dim=None, interpolation="linear"):    def quantile(self, q, dim=None, interpolation="linear", keep_attrs=None):         """Compute the qth quantile of the data along the specified dimension.          Returns the qth quantiles(s) of the array elements.


* higher: ``j``.                 * nearest: ``i`` or ``j``, whichever is nearest.                 * midpoint: ``(i + j) / 2``.<ins>        keep_attrs : bool, optional            If True, the variable's attributes (`attrs`) will be copied from            the original object to the new one.  If False (default), the new            object will be returned without attributes.</ins>          Returns         -------


is a scalar. If multiple percentiles are given, first axis of             the result corresponds to the quantile and a quantile dimension             is added to the return array. The other dimensions are the             dimensions that remain after the reduction of the array.            dimensions that remain after the reduction of the array.          See Also         --------


axis = None             new_dims = []         # only add the quantile dimension if q is array like        # Only add the quantile dimension if q is array-like         if q.ndim != 0:             new_dims = ["quantile"] + new_dims          qs = np.nanpercentile(             self.data, q * 100.0, axis=axis, interpolation=interpolation         )        return Variable(new_dims, qs)        if keep_attrs is None:            keep_attrs = _get_keep_attrs(default=False)        attrs = self._attrs if keep_attrs else None        return Variable(new_dims, qs, attrs)      def rank(self, dim, pct=False):         """Ranks the data.


to_merge = {var: [] for var in variables_to_merge}          for ds in datasets:            absent_merge_vars = variables_to_merge - set(ds.variables)            if absent_merge_vars:                raise ValueError(                    "variables %r are present in some datasets but not others. "                    % absent_merge_vars                )             for var in variables_to_merge:                to_merge[var].append(ds.variables[var])                if var in ds:                    to_merge[var].append(ds.variables[var])          for var in variables_to_merge:             result_vars[var] = unique_variable(


group_indices = [slice(i, i + 1) for i in group_indices]             unique_coord = group         else:<ins>            if group.isnull().any():                # drop any NaN valued groups.                # also drop obj values where group was NaN                # Use where instead of reindex to account for duplicate coordinate labels.                obj = obj.where(group.notnull(), drop=True)                group = group.dropna(group_dim)</ins>             # look through group to find the unique values             unique_values, group_indices = unique_value_groups(                 safe_cast_to_index(group), sort=(bins is None)


assert_coordinate_consistent,     remap_label_indexers, )from .dataset import Dataset, merge_indexes, split_indexesfrom .dataset import Dataset, split_indexes from .formatting import format_item from .indexes import Indexes, default_indexes from .merge import PANDAS_TYPES


--------         DataArray.reset_index         """        _check_inplace(inplace)        indexes = either_dict_or_kwargs(indexes, indexes_kwargs, "set_index")        coords, _ = merge_indexes(indexes, self._coords, set(), append=append)        return self._replace(coords=coords)        ds = self._to_temp_dataset().set_index(            indexes, append=append, inplace=inplace, **indexes_kwargs        )        return self._from_temp_dataset(ds)      def reset_index(         self,diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py-- a/xarray/core/dataset.py++ b/xarray/core/dataset.py


"""     vars_to_replace: Dict[Hashable, Variable] = {}     vars_to_remove: List[Hashable] = []<ins>    dims_to_replace: Dict[Hashable, Hashable] = {}</ins>     error_msg = "{} is not the name of an existing variable."      for dim, var_names in indexes.items():


if not len(names) and len(var_names) == 1:             idx = pd.Index(variables[var_names[0]].values)         else:        else:  # MultiIndex             for n in var_names:                 try:                     var = variables[n]


levels.append(cat.categories)              idx = pd.MultiIndex(levels, codes, names=names)            for n in names:                dims_to_replace[n] = dim          vars_to_replace[dim] = IndexVariable(dim, idx)         vars_to_remove.extend(var_names)      new_variables = {k: v for k, v in variables.items() if k not in vars_to_remove}     new_variables.update(vars_to_replace)    # update dimensions if necessary  GH: 3512    for k, v in new_variables.items():        if any(d in dims_to_replace for d in v.dims):            new_dims = [dims_to_replace.get(d, d) for d in v.dims]            new_variables[k] = v._replace(dims=new_dims)     new_coord_names = coord_names | set(vars_to_replace)     new_coord_names -= set(vars_to_remove)     return new_variables, new_coord_names


out = ops.fillna(self, value)         return out <ins>    def quantile(self, q, dim=None, interpolation="linear", keep_attrs=None):        """Compute the qth quantile over each array in the groups and        concatenate them together into a new array.        Parameters        ----------        q : float in range of [0,1] (or sequence of floats)            Quantile to compute, which must be between 0 and 1            inclusive.        dim : `...`, str or sequence of str, optional            Dimension(s) over which to apply quantile.            Defaults to the grouped dimension.        interpolation : {'linear', 'lower', 'higher', 'midpoint', 'nearest'}            This optional parameter specifies the interpolation method to            use when the desired quantile lies between two data points            ``i < j``:                * linear: ``i + (j - i) * fraction``, where ``fraction`` is                  the fractional part of the index surrounded by ``i`` and                  ``j``.                * lower: ``i``.                * higher: ``j``.                * nearest: ``i`` or ``j``, whichever is nearest.                * midpoint: ``(i + j) / 2``.        Returns        -------        quantiles : Variable            If `q` is a single quantile, then the result is a            scalar. If multiple percentiles are given, first axis of            the result corresponds to the quantile. In either case a            quantile dimension is added to the return array. The other            dimensions are the dimensions that remain after the            reduction of the array.        See Also        --------        numpy.nanpercentile, pandas.Series.quantile, Dataset.quantile,        DataArray.quantile        """        if dim is None:            dim = self._group_dim        out = self.map(            self._obj.__class__.quantile,            shortcut=False,            q=q,            dim=dim,            interpolation=interpolation,            keep_attrs=keep_attrs,        )        return out</ins>     def where(self, cond, other=dtypes.NA):         """Return elements from `self` or `other` depending on `cond`.


combined = self._maybe_unstack(combined)         return combined <del>    def quantile(self, q, dim=None, interpolation="linear", keep_attrs=None):        """Compute the qth quantile over each array in the groups and        concatenate them together into a new array.        Parameters        ----------        q : float in range of [0,1] (or sequence of floats)            Quantile to compute, which must be between 0 and 1            inclusive.        dim : `...`, str or sequence of str, optional            Dimension(s) over which to apply quantile.            Defaults to the grouped dimension.        interpolation : {'linear', 'lower', 'higher', 'midpoint', 'nearest'}            This optional parameter specifies the interpolation method to            use when the desired quantile lies between two data points            ``i < j``:                * linear: ``i + (j - i) * fraction``, where ``fraction`` is                  the fractional part of the index surrounded by ``i`` and                  ``j``.                * lower: ``i``.                * higher: ``j``.                * nearest: ``i`` or ``j``, whichever is nearest.                * midpoint: ``(i + j) / 2``.        Returns        -------        quantiles : Variable            If `q` is a single quantile, then the result            is a scalar. If multiple percentiles are given, first axis of            the result corresponds to the quantile and a quantile dimension            is added to the return array. The other dimensions are the            dimensions that remain after the reduction of the array.        See Also        --------        numpy.nanpercentile, pandas.Series.quantile, Dataset.quantile,        DataArray.quantile        """        if dim is None:            dim = self._group_dim        out = self.map(            self._obj.__class__.quantile,            shortcut=False,            q=q,            dim=dim,            interpolation=interpolation,            keep_attrs=keep_attrs,        )        if np.asarray(q, dtype=np.float64).ndim == 0:            out = out.drop_vars("quantile")        return out</del>     def reduce(         self, func, dim=None, axis=None, keep_attrs=None, shortcut=True, **kwargs     ):


scalar = utils.is_scalar(q)         q = np.atleast_1d(np.asarray(q, dtype=np.float64)) <ins>        # TODO: remove once numpy >= 1.15.0 is the minimum requirement        if np.count_nonzero(q < 0.0) or np.count_nonzero(q > 1.0):            raise ValueError("Quantiles must be in the range [0, 1]")</ins>         if dim is None:             dim = self.dims


def _wrapper(npa, **kwargs):             # move quantile axis to end. required for apply_ufunc<ins>            # TODO: use np.nanquantile once numpy >= 1.15.0 is the minimum requirement</ins>             return np.moveaxis(np.nanpercentile(npa, **kwargs), 0, -1)          axis = np.arange(-1, -1 * len(dim) - 1, -1)


those of the first object with that dimension. Indexes for the same           dimension must have the same size in all objects.     indexers, mode, concat_over : deprecated     Returns     -------     concatenated : type of objs     Notes    -----    Each concatenated Variable preserves corresponding ``attrs`` from the first element of ``objs``.     See also     --------     mergediff --git a/xarray/core/variable.py b/xarray/core/variable.py-- a/xarray/core/variable.py++ b/xarray/core/variable.py


if not shortcut:             for var in variables:                 if var.dims != first_var.dims:                    raise ValueError("inconsistent dimensions")                utils.remove_incompatible_items(attrs, var.attrs)                    raise ValueError(                        f"Variable has dimensions {list(var.dims)} but first Variable has dimensions {list(first_var.dims)}"                    )          return cls(dims, data, attrs, encoding)


return combined_ids, concat_dims  def _check_shape_tile_ids(combined_tile_ids):def _check_dimension_depth_tile_ids(combined_tile_ids):    """    Check all tuples are the same length, i.e. check that all lists are    nested to the same depth.    """     tile_ids = combined_tile_ids.keys()    # Check all tuples are the same length    # i.e. check that all lists are nested to the same depth     nesting_depths = [len(tile_id) for tile_id in tile_ids]     if not nesting_depths:         nesting_depths = [0]


"The supplied objects do not form a hypercube because"             " sub-lists do not have consistent depths"         )    # return these just to be reused in _check_shape_tile_ids    return tile_ids, nesting_depths     # Check all lists along one dimension are same lengthdef _check_shape_tile_ids(combined_tile_ids):    """Check all lists along one dimension are same length."""    tile_ids, nesting_depths = _check_dimension_depth_tile_ids(combined_tile_ids)     for dim in range(nesting_depths[0]):         indices_along_dim = [tile_id[dim] for tile_id in tile_ids]         occurrences = Counter(indices_along_dim)


coords : {'minimal', 'different', 'all' or list of str}, optional         As per the 'data_vars' kwarg, but for coordinate variables.     fill_value : scalar, optional        Value to use for newly missing values        Value to use for newly missing values. If None, raises a ValueError if        the passed Datasets do not create a complete hypercube.     join : {'outer', 'inner', 'left', 'right', 'exact'}, optional         String indicating how to combine differing indexes         (excluding concat_dim) in objects


temperature    (y, x) float64 1.654 10.63 7.015 2.543 ... 12.46 2.22 15.96     precipitation  (y, x) float64 0.2136 0.9974 0.7603 ... 0.6125 0.4654 0.5953 <ins>    >>> xr.combine_by_coords([x1, x2, x3])    <xarray.Dataset>    Dimensions:        (x: 6, y: 4)    Coordinates:    * x              (x) int64 10 20 30 40 50 60    * y              (y) int64 0 1 2 3    Data variables:    temperature    (y, x) float64 1.654 10.63 7.015 nan ... 12.46 2.22 15.96    precipitation  (y, x) float64 0.2136 0.9974 0.7603 ... 0.6125 0.4654 0.5953</ins>     """      # Group by data vars


list(datasets_with_same_vars)         )         _check_shape_tile_ids(combined_ids)        if fill_value is None:            # check that datasets form complete hypercube            _check_shape_tile_ids(combined_ids)        else:            # check only that all datasets have same dimension depth for these            # vars            _check_dimension_depth_tile_ids(combined_ids)          # Concatenate along all of concat_dims one by one to create single ds         concatenated = _combine_nd(


If any variables conflict (see ``compat``).         """         _check_inplace(inplace)<ins>        other = other.to_dataset() if isinstance(other, xr.DataArray) else other</ins>         merge_result = dataset_merge_method(             self,             other,


from .core.alignment import align, broadcast from .core.combine import auto_combine, combine_by_coords, combine_nested from .core.common import ALL_DIMS, full_like, ones_like, zeros_likefrom .core.computation import apply_ufunc, dot, wherefrom .core.computation import apply_ufunc, dot, polyval, where from .core.concat import concat from .core.dataarray import DataArray from .core.dataset import Dataset


"open_mfdataset",     "open_rasterio",     "open_zarr",    "polyval",     "register_dataarray_accessor",     "register_dataset_accessor",     "save_mfdataset",diff --git a/xarray/core/computation.py b/xarray/core/computation.py-- a/xarray/core/computation.py++ b/xarray/core/computation.py


dataset_join="exact",         dask="allowed",     )def polyval(coord, coeffs, degree_dim="degree"):    """Evaluate a polynomial at specific values    Parameters    ----------    coord : DataArray        The 1D coordinate along which to evaluate the polynomial.    coeffs : DataArray        Coefficients of the polynomials.    degree_dim : str, default "degree"        Name of the polynomial degree dimension in `coeffs`.    See also    --------    xarray.DataArray.polyfit    numpy.polyval    """    from .dataarray import DataArray    from .missing import get_clean_interp_index    x = get_clean_interp_index(coord, coord.name)    deg_coord = coeffs[degree_dim]    lhs = DataArray(        np.vander(x, int(deg_coord.max()) + 1),        dims=(coord.name, degree_dim),        coords={coord.name: coord, degree_dim: np.arange(deg_coord.max() + 1)[::-1]},    )    return (lhs * coeffs).sum(degree_dim)diff --git a/xarray/core/dask_array_ops.py b/xarray/core/dask_array_ops.py-- a/xarray/core/dask_array_ops.py++ b/xarray/core/dask_array_ops.py


# crop boundary.     index = (slice(None),) * axis + (slice(drop_size, drop_size + orig_shape[axis]),)     return out[index]def least_squares(lhs, rhs, rcond=None, skipna=False):    import dask.array as da    lhs_da = da.from_array(lhs, chunks=(rhs.chunks[0], lhs.shape[1]))    if skipna:        added_dim = rhs.ndim == 1        if added_dim:            rhs = rhs.reshape(rhs.shape[0], 1)        results = da.apply_along_axis(            nputils._nanpolyfit_1d,            0,            rhs,            lhs_da,            dtype=float,            shape=(lhs.shape[1] + 1,),            rcond=rcond,        )        coeffs = results[:-1, ...]        residuals = results[-1, ...]        if added_dim:            coeffs = coeffs.reshape(coeffs.shape[0])            residuals = residuals.reshape(residuals.shape[0])    else:        coeffs, residuals, _, _ = da.linalg.lstsq(lhs_da, rhs)    return coeffs, residualsdiff --git a/xarray/core/dataarray.py b/xarray/core/dataarray.py-- a/xarray/core/dataarray.py++ b/xarray/core/dataarray.py


return map_blocks(func, self, args, kwargs)     def polyfit(        self,        dim: Hashable,        deg: int,        skipna: bool = None,        rcond: float = None,        w: Union[Hashable, Any] = None,        full: bool = False,        cov: bool = False,    ):        """        Least squares polynomial fit.        This replicates the behaviour of `numpy.polyfit` but differs by skipping        invalid values when `skipna = True`.        Parameters        ----------        dim : hashable            Coordinate along which to fit the polynomials.        deg : int            Degree of the fitting polynomial.        skipna : bool, optional            If True, removes all invalid values before fitting each 1D slices of the array.            Default is True if data is stored in a dask.array or if there is any            invalid values, False otherwise.        rcond : float, optional            Relative condition number to the fit.        w : Union[Hashable, Any], optional            Weights to apply to the y-coordinate of the sample points.            Can be an array-like object or the name of a coordinate in the dataset.        full : bool, optional            Whether to return the residuals, matrix rank and singular values in addition            to the coefficients.        cov : Union[bool, str], optional            Whether to return to the covariance matrix in addition to the coefficients.            The matrix is not scaled if `cov='unscaled'`.        Returns        -------        polyfit_results : Dataset            A single dataset which contains:            polyfit_coefficients                The coefficients of the best fit.            polyfit_residuals                The residuals of the least-square computation (only included if `full=True`)            [dim]_matrix_rank                The effective rank of the scaled Vandermonde coefficient matrix (only included if `full=True`)            [dim]_singular_value                The singular values of the scaled Vandermonde coefficient matrix (only included if `full=True`)            polyfit_covariance                The covariance matrix of the polynomial coefficient estimates (only included if `full=False` and `cov=True`)        See also        --------        numpy.polyfit        """        return self._to_temp_dataset().polyfit(            dim, deg, skipna=skipna, rcond=rcond, w=w, full=full, cov=cov        )     def pad(         self,         pad_width: Mapping[Hashable, Union[int, Tuple[int, int]]] = None,diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py-- a/xarray/core/dataset.py++ b/xarray/core/dataset.py


merge_coordinates_without_align,     merge_data_and_coords, )<ins>from .missing import get_clean_interp_index</ins> from .options import OPTIONS, _get_keep_attrs from .pycompat import dask_array_type from .utils import (


return map_blocks(func, self, args, kwargs)     def polyfit(        self,        dim: Hashable,        deg: int,        skipna: bool = None,        rcond: float = None,        w: Union[Hashable, Any] = None,        full: bool = False,        cov: Union[bool, str] = False,    ):        """        Least squares polynomial fit.        This replicates the behaviour of `numpy.polyfit` but differs by skipping        invalid values when `skipna = True`.        Parameters        ----------        dim : hashable            Coordinate along which to fit the polynomials.        deg : int            Degree of the fitting polynomial.        skipna : bool, optional            If True, removes all invalid values before fitting each 1D slices of the array.            Default is True if data is stored in a dask.array or if there is any            invalid values, False otherwise.        rcond : float, optional            Relative condition number to the fit.        w : Union[Hashable, Any], optional            Weights to apply to the y-coordinate of the sample points.            Can be an array-like object or the name of a coordinate in the dataset.        full : bool, optional            Whether to return the residuals, matrix rank and singular values in addition            to the coefficients.        cov : Union[bool, str], optional            Whether to return to the covariance matrix in addition to the coefficients.            The matrix is not scaled if `cov='unscaled'`.        Returns        -------        polyfit_results : Dataset            A single dataset which contains (for each "var" in the input dataset):            [var]_polyfit_coefficients                The coefficients of the best fit for each variable in this dataset.            [var]_polyfit_residuals                The residuals of the least-square computation for each variable (only included if `full=True`)            [dim]_matrix_rank                The effective rank of the scaled Vandermonde coefficient matrix (only included if `full=True`)            [dim]_singular_values                The singular values of the scaled Vandermonde coefficient matrix (only included if `full=True`)            [var]_polyfit_covariance                The covariance matrix of the polynomial coefficient estimates (only included if `full=False` and `cov=True`)        See also        --------        numpy.polyfit        """        variables = {}        skipna_da = skipna        x = get_clean_interp_index(self, dim)        xname = "{}_".format(self[dim].name)        order = int(deg) + 1        lhs = np.vander(x, order)        if rcond is None:            rcond = x.shape[0] * np.core.finfo(x.dtype).eps        # Weights:        if w is not None:            if isinstance(w, Hashable):                w = self.coords[w]            w = np.asarray(w)            if w.ndim != 1:                raise TypeError("Expected a 1-d array for weights.")            if w.shape[0] != lhs.shape[0]:                raise TypeError("Expected w and {} to have the same length".format(dim))            lhs *= w[:, np.newaxis]        # Scaling        scale = np.sqrt((lhs * lhs).sum(axis=0))        lhs /= scale        degree_dim = utils.get_temp_dimname(self.dims, "degree")        rank = np.linalg.matrix_rank(lhs)        if rank != order and not full:            warnings.warn(                "Polyfit may be poorly conditioned", np.RankWarning, stacklevel=4            )        if full:            rank = xr.DataArray(rank, name=xname + "matrix_rank")            variables[rank.name] = rank            sing = np.linalg.svd(lhs, compute_uv=False)            sing = xr.DataArray(                sing,                dims=(degree_dim,),                coords={degree_dim: np.arange(order)[::-1]},                name=xname + "singular_values",            )            variables[sing.name] = sing        for name, da in self.data_vars.items():            if dim not in da.dims:                continue            if skipna is None:                if isinstance(da.data, dask_array_type):                    skipna_da = True                else:                    skipna_da = np.any(da.isnull())            dims_to_stack = [dimname for dimname in da.dims if dimname != dim]            stacked_coords = {}            if dims_to_stack:                stacked_dim = utils.get_temp_dimname(dims_to_stack, "stacked")                rhs = da.transpose(dim, *dims_to_stack).stack(                    {stacked_dim: dims_to_stack}                )                stacked_coords = {stacked_dim: rhs[stacked_dim]}                scale_da = scale[:, np.newaxis]            else:                rhs = da                scale_da = scale            if w is not None:                rhs *= w[:, np.newaxis]            coeffs, residuals = duck_array_ops.least_squares(                lhs, rhs.data, rcond=rcond, skipna=skipna_da            )            if isinstance(name, str):                name = "{}_".format(name)            else:                # Thus a ReprObject => polyfit was called on a DataArray                name = ""            coeffs = xr.DataArray(                coeffs / scale_da,                dims=[degree_dim] + list(stacked_coords.keys()),                coords={degree_dim: np.arange(order)[::-1], **stacked_coords},                name=name + "polyfit_coefficients",            )            if dims_to_stack:                coeffs = coeffs.unstack(stacked_dim)            variables[coeffs.name] = coeffs            if full or (cov is True):                residuals = xr.DataArray(                    residuals if dims_to_stack else residuals.squeeze(),                    dims=list(stacked_coords.keys()),                    coords=stacked_coords,                    name=name + "polyfit_residuals",                )                if dims_to_stack:                    residuals = residuals.unstack(stacked_dim)                variables[residuals.name] = residuals            if cov:                Vbase = np.linalg.inv(np.dot(lhs.T, lhs))                Vbase /= np.outer(scale, scale)                if cov == "unscaled":                    fac = 1                else:                    if x.shape[0] <= order:                        raise ValueError(                            "The number of data points must exceed order to scale the covariance matrix."                        )                    fac = residuals / (x.shape[0] - order)                covariance = xr.DataArray(Vbase, dims=("cov_i", "cov_j"),) * fac                variables[name + "polyfit_covariance"] = covariance        return Dataset(data_vars=variables, attrs=self.attrs.copy())     def pad(         self,         pad_width: Mapping[Hashable, Union[int, Tuple[int, int]]] = None,diff --git a/xarray/core/duck_array_ops.py b/xarray/core/duck_array_ops.py-- a/xarray/core/duck_array_ops.py++ b/xarray/core/duck_array_ops.py


return dask_array_ops.rolling_window(array, axis, window, center, fill_value)     else:  # np.ndarray         return nputils.rolling_window(array, axis, window, center, fill_value)def least_squares(lhs, rhs, rcond=None, skipna=False):    """Return the coefficients and residuals of a least-squares fit.    """    if isinstance(rhs, dask_array_type):        return dask_array_ops.least_squares(lhs, rhs, rcond=rcond, skipna=skipna)    else:        return nputils.least_squares(lhs, rhs, rcond=rcond, skipna=skipna)diff --git a/xarray/core/nputils.py b/xarray/core/nputils.py-- a/xarray/core/nputils.py++ b/xarray/core/nputils.py


return f  <ins>def _nanpolyfit_1d(arr, x, rcond=None):    out = np.full((x.shape[1] + 1,), np.nan)    mask = np.isnan(arr)    if not np.all(mask):        out[:-1], out[-1], _, _ = np.linalg.lstsq(x[~mask, :], arr[~mask], rcond=rcond)    return outdef least_squares(lhs, rhs, rcond=None, skipna=False):    if skipna:        added_dim = rhs.ndim == 1        if added_dim:            rhs = rhs.reshape(rhs.shape[0], 1)        nan_cols = np.any(np.isnan(rhs), axis=0)        out = np.empty((lhs.shape[1] + 1, rhs.shape[1]))        if np.any(nan_cols):            out[:, nan_cols] = np.apply_along_axis(                _nanpolyfit_1d, 0, rhs[:, nan_cols], lhs            )        if np.any(~nan_cols):            out[:-1, ~nan_cols], out[-1, ~nan_cols], _, _ = np.linalg.lstsq(                lhs, rhs[:, ~nan_cols], rcond=rcond            )        coeffs = out[:-1, :]        residuals = out[-1, :]        if added_dim:            coeffs = coeffs.reshape(coeffs.shape[0])            residuals = residuals.reshape(residuals.shape[0])    else:        coeffs, residuals, _, _ = np.linalg.lstsq(lhs, rhs, rcond=rcond)    return coeffs, residuals</ins> nanmin = _create_bottleneck_method("nanmin") nanmax = _create_bottleneck_method("nanmax") nanmean = _create_bottleneck_method("nanmean")


CMAP_SEQUENTIAL: "viridis",     CMAP_DIVERGENT: "RdBu_r",     KEEP_ATTRS: "default",    DISPLAY_STYLE: "text",    DISPLAY_STYLE: "html", }  _JOIN_OPTIONS = frozenset(["inner", "outer", "left", "right", "exact"])


import contextlib import functools from datetime import datetime, timedeltafrom itertools import zip_longestfrom itertools import chain, zip_longest from typing import Hashable  import numpy as np


np.set_printoptions(**original)  <ins>def limit_lines(string: str, *, limit: int):    """    If the string is more lines than the limit,    this returns the middle lines replaced by an ellipsis    """    lines = string.splitlines()    if len(lines) > limit:        string = "\n".join(chain(lines[: limit // 2], ["..."], lines[-limit // 2 :]))    return string</ins> def short_numpy_repr(array):     array = np.asarray(array)


elif hasattr(internal_data, "__array_function__") or isinstance(         internal_data, dask_array_type     ):        return repr(array.data)        return limit_lines(repr(array.data), limit=40)     elif array._in_memory or array.size < 1e5:         return short_numpy_repr(array)     else:


from .formatting import format_item from .indexes import Indexes, default_indexes, propagate_indexes from .indexing import is_fancy_indexerfrom .merge import PANDAS_TYPES, _extract_indexes_from_coordsfrom .merge import PANDAS_TYPES, MergeError, _extract_indexes_from_coords from .options import OPTIONS from .utils import Default, ReprObject, _check_inplace, _default, either_dict_or_kwargs from .variable import (


# don't support automatic alignment with in-place arithmetic.             other_coords = getattr(other, "coords", None)             other_variable = getattr(other, "variable", other)            with self.coords._merge_inplace(other_coords):                f(self.variable, other_variable)            try:                with self.coords._merge_inplace(other_coords):                    f(self.variable, other_variable)            except MergeError as exc:                raise MergeError(                    "Automatic alignment is not supported for in-place operations.\n"                    "Consider aligning the indices manually or using a not-in-place operation.\n"                    "See https://github.com/pydata/xarray/issues/3910 for more explanations."                ) from exc             return self          return func


from .options import OPTIONS, _get_keep_attrs from .pycompat import dask_array_type from .rolling_exp import RollingExpfrom .utils import Frozen, either_dict_or_kwargsfrom .utils import Frozen, either_dict_or_kwargs, is_scalar  # Used as a sentinel value to indicate a all dimensions ALL_DIMS = ...


from .dataset import Dataset     from .variable import Variable <ins>    if not is_scalar(fill_value):        raise ValueError(f"fill_value must be scalar. Received {fill_value} instead.")</ins>     if isinstance(other, Dataset):         data_vars = {             k: _full_like_variable(v, fill_value, dtype)


return self._from_temp_dataset(ds)      def integrate(        self, dim: Union[Hashable, Sequence[Hashable]], datetime_unit: str = None        self,        coord: Union[Hashable, Sequence[Hashable]] = None,        datetime_unit: str = None,        *,        dim: Union[Hashable, Sequence[Hashable]] = None,     ) -> "DataArray":        """ integrate the array with the trapezoidal rule.        """Integrate along the given coordinate using the trapezoidal rule.          .. note::            This feature is limited to simple cartesian geometry, i.e. dim            This feature is limited to simple cartesian geometry, i.e. coord             must be one dimensional.          Parameters         ----------        coord: hashable, or a sequence of hashable            Coordinate(s) used for the integration.         dim : hashable, or sequence of hashable             Coordinate(s) used for the integration.        datetime_unit : {"Y", "M", "W", "D", "h", "m", "s", "ms", "us", "ns", \                         "ps", "fs", "as"}, optional            Can be used to specify the unit if datetime coordinate is used.        datetime_unit: {'Y', 'M', 'W', 'D', 'h', 'm', 's', 'ms', 'us', 'ns', \                        'ps', 'fs', 'as'}, optional          Returns         -------


See also         --------<ins>        Dataset.integrate</ins>         numpy.trapz: corresponding numpy function          Examples


array([5.4, 6.6, 7.8])         Dimensions without coordinates: y         """        ds = self._to_temp_dataset().integrate(dim, datetime_unit)        if dim is not None and coord is not None:            raise ValueError(                "Cannot pass both 'dim' and 'coord'. Please pass only 'coord' instead."            )        if dim is not None and coord is None:            coord = dim            msg = (                "The `dim` keyword argument to `DataArray.integrate` is "                "being replaced with `coord`, for consistency with "                "`Dataset.integrate`. Please pass `coord` instead."                " `dim` will be removed in version 0.19.0."            )            warnings.warn(msg, FutureWarning, stacklevel=2)        ds = self._to_temp_dataset().integrate(coord, datetime_unit)         return self._from_temp_dataset(ds)      def unify_chunks(self) -> "DataArray":diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py-- a/xarray/core/dataset.py++ b/xarray/core/dataset.py


variables[k] = v         return self._replace(variables)     def integrate(self, coord, datetime_unit=None):        """ integrate the array with the trapezoidal rule.    def integrate(        self, coord: Union[Hashable, Sequence[Hashable]], datetime_unit: str = None    ) -> "Dataset":        """Integrate along the given coordinate using the trapezoidal rule.          .. note::             This feature is limited to simple cartesian geometry, i.e. coord


Parameters         ----------        coord: str, or sequence of str        coord: hashable, or a sequence of hashable             Coordinate(s) used for the integration.        datetime_unit : {"Y", "M", "W", "D", "h", "m", "s", "ms", "us", "ns", \                         "ps", "fs", "as"}, optional            Can be specify the unit if datetime coordinate is used.        datetime_unit: {'Y', 'M', 'W', 'D', 'h', 'm', 's', 'ms', 'us', 'ns', \                        'ps', 'fs', 'as'}, optional            Specify the unit if datetime coordinate is used.          Returns         -------


# we need to mask data values that are nan; else the weights are wrong         mask = da.notnull()         sum_of_weights = self._reduce(mask, self.weights, dim=dim, skipna=False)        # bool -> int, because ``xr.dot([True, True], [True, True])`` -> True        # (and not 2); GH4074        if self.weights.dtype == bool:            sum_of_weights = self._reduce(                mask, self.weights.astype(int), dim=dim, skipna=False            )        else:            sum_of_weights = self._reduce(mask, self.weights, dim=dim, skipna=False)          # 0-weights are not valid         valid_weights = sum_of_weights != 0.0


# pull variables out of datarray         data_dict = {}         for k in variables:            data_dict[k] = self.sel({variable_dim: k}).squeeze(drop=True)            data_dict[k] = self.sel({variable_dim: k}, drop=True).squeeze(drop=True)          # unstacked dataset         return Dataset(data_dict)


def array_section(obj):     # "unique" id to expand/collapse the section     data_id = "section-" + str(uuid.uuid4())    collapsed = ""    collapsed = "checked"     variable = getattr(obj, "variable", obj)     preview = escape(inline_variable_array_repr(variable, max_width=70))     data_repr = short_data_repr_html(obj)


import numpy as npimport pandas as pdfrom . import parameterizedclass MultiIndexSeries:    def setup(self, dtype, subset):        data = np.random.rand(100000).astype(dtype)        index = pd.MultiIndex.from_product(            [                list("abcdefhijk"),                list("abcdefhijk"),                pd.date_range(start="2000-01-01", periods=1000, freq="B"),            ]        )        series = pd.Series(data, index)        if subset:            series = series[::3]        self.series = series    @parameterized(["dtype", "subset"], ([int, float], [True, False]))    def time_to_xarray(self, dtype, subset):        self.series.to_xarray()diff --git a/xarray/core/dataset.py b/xarray/core/dataset.py-- a/xarray/core/dataset.py++ b/xarray/core/dataset.py


return self._to_dataframe(self.dims)      def _set_sparse_data_from_dataframe(        self, dataframe: pd.DataFrame, dims: tuple        self, idx: pd.Index, arrays: List[Tuple[Hashable, np.ndarray]], dims: tuple     ) -> None:         from sparse import COO         idx = dataframe.index         if isinstance(idx, pd.MultiIndex):             coords = np.stack([np.asarray(code) for code in idx.codes], axis=0)             is_sorted = idx.is_lexsorted()


is_sorted = True             shape = (idx.size,)         for name, series in dataframe.items():            # Cast to a NumPy array first, in case the Series is a pandas            # Extension array (which doesn't have a valid NumPy dtype)            values = np.asarray(series)        for name, values in arrays:             # In virtually all real use cases, the sparse array will now have             # missing values and needs a fill_value. For consistency, don't             # special case the rare exceptions (e.g., dtype=int without a


self[name] = (dims, data)      def _set_numpy_data_from_dataframe(        self, dataframe: pd.DataFrame, dims: tuple        self, idx: pd.Index, arrays: List[Tuple[Hashable, np.ndarray]], dims: tuple     ) -> None:        idx = dataframe.index        if isinstance(idx, pd.MultiIndex):            # expand the DataFrame to include the product of all levels            full_idx = pd.MultiIndex.from_product(idx.levels, names=idx.names)            dataframe = dataframe.reindex(full_idx)            shape = tuple(lev.size for lev in idx.levels)        else:            shape = (idx.size,)        for name, series in dataframe.items():            data = np.asarray(series).reshape(shape)        if not isinstance(idx, pd.MultiIndex):            for name, values in arrays:                self[name] = (dims, values)            return        shape = tuple(lev.size for lev in idx.levels)        indexer = tuple(idx.codes)        # We already verified that the MultiIndex has all unique values, so        # there are missing values if and only if the size of output arrays is        # larger that the index.        missing_values = np.prod(shape) > idx.shape[0]        for name, values in arrays:            # NumPy indexing is much faster than using DataFrame.reindex() to            # fill in missing values:            # https://stackoverflow.com/a/35049899/809705            if missing_values:                dtype, fill_value = dtypes.maybe_promote(values.dtype)                data = np.full(shape, fill_value, dtype)            else:                # If there are no missing values, keep the existing dtype                # instead of promoting to support NA, e.g., keep integer                # columns as integers.                # TODO: consider removing this special case, which doesn't                # exist for sparse=True.                data = np.zeros(shape, values.dtype)            data[indexer] = values             self[name] = (dims, data)      @classmethod


if not dataframe.columns.is_unique:             raise ValueError("cannot convert DataFrame with non-unique columns")         idx, dataframe = remove_unused_levels_categories(dataframe.index, dataframe)        idx = remove_unused_levels_categories(dataframe.index)        if isinstance(idx, pd.MultiIndex) and not idx.is_unique:            raise ValueError(                "cannot convert a DataFrame with a non-unique MultiIndex into xarray"            )        # Cast to a NumPy array first, in case the Series is a pandas Extension        # array (which doesn't have a valid NumPy dtype)        # TODO: allow users to control how this casting happens, e.g., by        # forwarding arguments to pandas.Series.to_numpy?        arrays = [(k, np.asarray(v)) for k, v in dataframe.items()]         obj = cls()          if isinstance(idx, pd.MultiIndex):


obj[index_name] = (dims, idx)          if sparse:            obj._set_sparse_data_from_dataframe(dataframe, dims)            obj._set_sparse_data_from_dataframe(idx, arrays, dims)         else:            obj._set_numpy_data_from_dataframe(dataframe, dims)            obj._set_numpy_data_from_dataframe(idx, arrays, dims)         return obj      def to_dask_dataframe(self, dim_order=None, set_index=False):diff --git a/xarray/core/indexes.py b/xarray/core/indexes.py-- a/xarray/core/indexes.py++ b/xarray/core/indexes.py


from .variable import Variable  def remove_unused_levels_categories(index, dataframe=None):def remove_unused_levels_categories(index: pd.Index) -> pd.Index:     """     Remove unused levels from MultiIndex and unused categories from CategoricalIndex     """


else:                     level = level[index.codes[i]]                 levels.append(level)            # TODO: calling from_array() reorders MultiIndex levels. It would            # be best to avoid this, if possible, e.g., by using            # MultiIndex.remove_unused_levels() (which does not reorder) on the            # part of the MultiIndex that is not categorical, or by fixing this            # upstream in pandas.             index = pd.MultiIndex.from_arrays(levels, names=index.names)     elif isinstance(index, pd.CategoricalIndex):         index = index.remove_unused_categories()    if dataframe is None:        return index    dataframe = dataframe.set_index(index)    return dataframe.index, dataframe    return index   class Indexes(collections.abc.Mapping):


return inline_dask_repr(var.data)     elif isinstance(var._data, sparse_array_type):         return inline_sparse_repr(var.data)<ins>    elif hasattr(var._data, "_repr_inline_"):        return var._data._repr_inline_(max_width)</ins>     elif hasattr(var._data, "__array_function__"):         return maybe_truncate(repr(var._data).replace("\n", " "), max_width)     else:


"""     xarray version of pandas.core.nanops._maybe_null_out     """    if hasattr(axis, "__len__"):  # if tuple or list        raise ValueError(            "min_count is not available for reduction with more than one dimensions."        )      if axis is not None and getattr(result, "ndim", False):        null_mask = (mask.shape[axis] - mask.sum(axis) - min_count) < 0        null_mask = (np.take(mask.shape, axis).prod() - mask.sum(axis) - min_count) < 0         if null_mask.any():             dtype, fill_value = dtypes.maybe_promote(result.dtype)             result = result.astype(dtype)


combined = concat_vars(vars, dim, positions)             assert isinstance(combined, Variable)             result_vars[k] = combined<ins>        elif k in result_vars:            # preserves original variable order            result_vars[k] = result_vars.pop(k)</ins>      result = Dataset(result_vars, attrs=result_attrs)     absent_coord_names = coord_names - set(result.variables)


nanname = "nan" + name             func = getattr(nanops, nanname)         else:<ins>            if name in ["sum", "prod"]:                kwargs.pop("min_count", None)</ins>             func = _dask_or_eager_func(name, dask_module=dask_module)          try:


median.numeric_only = True prod = _create_nan_agg_method("prod") prod.numeric_only = Truesum.available_min_count = Trueprod.available_min_count = True cumprod_1d = _create_nan_agg_method("cumprod") cumprod_1d.numeric_only = True cumsum_1d = _create_nan_agg_method("cumsum")


cast, ) <ins>import numpy as np</ins> import pandas as pd  from . import formatting, indexing