text: from __future__ import unicode_literals
  
  try:
      from urllib import parse as urlparse
  except ImportError:
      import urlparse  # Python 2
  try:
      basestring
  except NameError:
      basestring = str  # Python 3
  
  from django import forms
  from django.core import checks, exceptions
  from django.contrib.admin.filters import FieldListFilter
  from django.db.models.fields import CharField, BLANK_CHOICE_DASH
  from django.utils.encoding import force_text, python_2_unicode_compatible
  from django.utils.html import escape as escape_html
  from django.utils.functional import lazy
  
  from django_countries import countries, ioc_data, widgets, filters
  from django_countries.conf import settings
  
  
  def country_to_text(value):
      if hasattr(value, "code"):
          value = value.code
      if value is None:
          return None
      return force_text(value)
  
  
  class TemporaryEscape(object):
      __slots__ = ["country", "original_escape"]
  
      def __init__(self, country):
          self.country = country
  
      def __bool__(self):
          return self.country._escape
  
      __nonzero__ = __bool__
  
      def __enter__(self):
          self.original_escape = self.country._escape
          self.country._escape = True
  
      def __exit__(self, type, value, traceback):
          self.country._escape = self.original_escape
  
  
  @python_2_unicode_compatible
  class Country(object):
      def __init__(self, code, flag_url=None, str_attr="code", custom_countries=None):
          self.flag_url = flag_url
          self._escape = False
          self._str_attr = str_attr
          if custom_countries is countries:
              custom_countries = None
          self.custom_countries = custom_countries
          # Attempt to convert the code to the alpha2 equivalent, but this
          # is not meant to be full validation so use the given code if no
          # match was found.
          self.code = self.countries.alpha2(code) or code
  
      def __str__(self):
          return force_text(getattr(self, self._str_attr) or "")
  
      def __eq__(self, other):
          return force_text(self.code or "") == force_text(other or "")
  
      def __ne__(self, other):
          return not self.__eq__(other)
  
      def __hash__(self):
          return hash(force_text(self))
  
      def __repr__(self):
          args = ["code={country.code!r}"]
          if self.flag_url is not None:
              args.append("flag_url={country.flag_url!r}")
          if self._str_attr != "code":
              args.append("str_attr={country._str_attr!r}")
          args = ", ".join(args).format(country=self)
          return "{name}({args})".format(name=self.__class__.__name__, args=args)
  
      def __bool__(self):
          return bool(self.code)
  
      __nonzero__ = __bool__  # Python 2 compatibility.
  
      def __len__(self):
          return len(force_text(self))
  
      @property
      def countries(self):
          return self.custom_countries or countries
  
      @property
      def escape(self):
          return TemporaryEscape(self)
  
      def maybe_escape(self, text):
          if not self.escape:
              return text
          return escape_html(text)
  
      @property
      def name(self):
          return self.maybe_escape(self.countries.name(self.code))
  
      @property
      def alpha3(self):
          return self.countries.alpha3(self.code)
  
      @property
      def numeric(self):
          return self.countries.numeric(self.code)
  
      @property
      def numeric_padded(self):
          return self.countries.numeric(self.code, padded=True)
  
      @property
      def flag(self):
          if not self.code:
              return ""
          flag_url = self.flag_url
          if flag_url is None:
              flag_url = settings.COUNTRIES_FLAG_URL
          url = flag_url.format(code_upper=self.code, code=self.code.lower())
          if not url:
              return ""
          url = urlparse.urljoin(settings.STATIC_URL, url)
          return self.maybe_escape(url)
  
      @property
      def flag_css(self):
          """
          Output the css classes needed to display an HTML element as a flag
          sprite.
  
          Requires the use of 'flags/sprite.css' or 'flags/sprite-hq.css'.
          Usage example::
  
              <i class="{{ ctry.flag_css }}" aria-label="{{ ctry.code }}></i>
          """
          if not self.code:
              return ""
          return "flag-sprite flag-{} flag-_{}".format(*self.code.lower())
  
      @property
      def unicode_flag(self):
          """
          Generate a unicode flag for the given country.
  
          The logic for how these are determined can be found at:
  
          https://en.wikipedia.org/wiki/Regional_Indicator_Symbol
  
          Currently, these glyphs appear to only be supported on OS X and iOS.
          """
          if not self.code:
              return ""
  
          # Don't really like magic numbers, but this is the code point for [A]
          # (Regional Indicator A), minus the code point for ASCII A. By adding
          # this to the uppercase characters making up the ISO 3166-1 alpha-2
          # codes we can get the flag.
          OFFSET = 127397
          points = [ord(x) + OFFSET for x in self.code.upper()]
  
          try:
              # Python 3 is simple: we can just chr() the unicode points.
              return chr(points[0]) + chr(points[1])
          except ValueError:
              # Python 2 requires us to be a bit more creative. We could use
              # unichr(), but that only works if the python has been compiled
              # with wide unicode support. This method should always work.
              return ("\\U%08x\\U%08x" % tuple(points)).decode("unicode-escape")
  
      @staticmethod
      def country_from_ioc(ioc_code, flag_url=""):
          code = ioc_data.IOC_TO_ISO.get(ioc_code, "")
          if code == "":
              return None
          return Country(code, flag_url=flag_url)
  
      @property
      def ioc_code(self):
          return ioc_data.ISO_TO_IOC.get(self.code, "")
  
  
  class CountryDescriptor(object):
      """
      A descriptor for country fields on a model instance. Returns a Country when
      accessed so you can do things like::
  
          >>> from people import Person
          >>> person = Person.object.get(name='Chris')
  
          >>> person.country.name
          'New Zealand'
  
          >>> person.country.flag
          '/static/flags/nz.gif'
      """
  
      def __init__(self, field):
          self.field = field
  
      def __get__(self, instance=None, owner=None):
          if instance is None:
              return self
          # Check in case this field was deferred.
          if self.field.name not in instance.__dict__:
              instance.refresh_from_db(fields=[self.field.name])
          value = instance.__dict__[self.field.name]
          if self.field.multiple:
              return [self.country(code) for code in value]
          return self.country(value)
  
      def country(self, code):
          return Country(
              code=code,
              flag_url=self.field.countries_flag_url,
              custom_countries=self.field.countries,
          )
  
      def __set__(self, instance, value):
          value = self.field.get_clean_value(value)
          instance.__dict__[self.field.name] = value
  
  
  class LazyChoicesMixin(widgets.LazyChoicesMixin):
      def _set_choices(self, value):
          """
          Also update the widget's choices.
          """
          super(LazyChoicesMixin, self)._set_choices(value)
          self.widget.choices = value
  
  
  class LazyTypedChoiceField(LazyChoicesMixin, forms.TypedChoiceField):
      """
      A form TypedChoiceField that respects choices being a lazy object.
      """
  
      widget = widgets.LazySelect
  
  
  class LazyTypedMultipleChoiceField(LazyChoicesMixin, forms.TypedMultipleChoiceField):
      """
      A form TypedMultipleChoiceField that respects choices being a lazy object.
      """
  
      widget = widgets.LazySelectMultiple
  
  
  class CountryField(CharField):
      """
      A country field for Django models that provides all ISO 3166-1 countries as
      choices.
      """
  
      descriptor_class = CountryDescriptor
  
      def __init__(self, *args, **kwargs):
          countries_class = kwargs.pop("countries", None)
          self.countries = countries_class() if countries_class else countries
          self.countries_flag_url = kwargs.pop("countries_flag_url", None)
          self.blank_label = kwargs.pop("blank_label", None)
          self.multiple = kwargs.pop("multiple", None)
          kwargs["choices"] = self.countries
          if self.multiple:
              kwargs["max_length"] = len(self.countries) * 3 - 1
          else:
              kwargs["max_length"] = 2
          super(CharField, self).__init__(*args, **kwargs)
  
      def check(self, **kwargs):
          errors = super(CountryField, self).check(**kwargs)
          errors.extend(self._check_multiple())
          return errors
  
      def _check_multiple(self):
          if not self.multiple or not self.null:
              return []
  
          hint = "Remove null=True argument on the field"
          if not self.blank:
              hint += " (just add blank=True if you want to allow no selection)"
          hint += "."
  
          return [
              checks.Error(
                  "Field specifies multiple=True, so should not be null.",
                  obj=self,
                  id="django_countries.E100",
                  hint=hint,
              )
          ]
  
      def get_internal_type(self):
          return "CharField"
  
      def contribute_to_class(self, cls, name):
          super(CountryField, self).contribute_to_class(cls, name)
          setattr(cls, self.name, self.descriptor_class(self))
  
      def pre_save(self, *args, **kwargs):
          "Returns field's value just before saving."
          value = super(CharField, self).pre_save(*args, **kwargs)
          return self.get_prep_value(value)
  
      def get_prep_value(self, value):
          "Returns field's value prepared for saving into a database."
          value = self.get_clean_value(value)
          if self.multiple:
              if value:
                  value = ",".join(value)
              else:
                  value = ""
          return super(CharField, self).get_prep_value(value)
  
      def get_clean_value(self, value):
          if value is None:
              return None
          if not self.multiple:
              return country_to_text(value)
          if isinstance(value, (basestring, Country)):
              if isinstance(value, basestring) and "," in value:
                  value = value.split(",")
              else:
                  value = [value]
          else:
              try:
                  iter(value)
              except TypeError:
                  value = [value]
          return list(filter(None, [country_to_text(c) for c in value]))
  
      def deconstruct(self):
          """
          Remove choices from deconstructed field, as this is the country list
          and not user editable.
  
          Not including the ``blank_label`` property, as this isn't database
          related.
          """
          name, path, args, kwargs = super(CountryField, self).deconstruct()
          kwargs.pop("choices")
          if self.multiple:  # multiple determines the length of the field
              kwargs["multiple"] = self.multiple
          if self.countries is not countries:
              # Include the countries class if it's not the default countries
              # instance.
              kwargs["countries"] = self.countries.__class__
          return name, path, args, kwargs
  
      def get_choices(self, include_blank=True, blank_choice=None, *args, **kwargs):
          if blank_choice is None:
              if self.blank_label is None:
                  blank_choice = BLANK_CHOICE_DASH
              else:
                  blank_choice = [("", self.blank_label)]
          if self.multiple:
              include_blank = False
          return super(CountryField, self).get_choices(
              include_blank=include_blank, blank_choice=blank_choice, *args, **kwargs
          )
  
      get_choices = lazy(get_choices, list)
  
      def formfield(self, **kwargs):
          kwargs.setdefault(
              "choices_form_class",
              LazyTypedMultipleChoiceField if self.multiple else LazyTypedChoiceField,
          )
          if "coerce" not in kwargs:
              kwargs["coerce"] = super(CountryField, self).to_python
          field = super(CharField, self).formfield(**kwargs)
          return field
  
      def to_python(self, value):
          if not self.multiple:
              return super(CountryField, self).to_python(value)
          if not value:
              return value
          if isinstance(value, basestring):
              value = value.split(",")
          output = []
          for item in value:
              output.append(super(CountryField, self).to_python(item))
          return output
  
      def validate(self, value, model_instance):
          """
          Use custom validation for when using a multiple countries field.
          """
          if not self.multiple:
              return super(CountryField, self).validate(value, model_instance)
  
          if not self.editable:
              # Skip validation for non-editable fields.
              return
  
          if value:
              choices = [option_key for option_key, option_value in self.choices]
              for single_value in value:
                  if single_value not in choices:
                      raise exceptions.ValidationError(
                          self.error_messages["invalid_choice"],
                          code="invalid_choice",
                          params={"value": single_value},
                      )
  
          if not self.blank and value in self.empty_values:
              raise exceptions.ValidationError(self.error_messages["blank"], code="blank")
  
      def value_to_string(self, obj):
          """
          Ensure data is serialized correctly.
          """
          value = self.value_from_object(obj)
          return self.get_prep_value(value)
  
  
  FieldListFilter.register(lambda f: isinstance(f, CountryField), filters.CountryFilter)
  