diff --git a/CHANGES.rst b/CHANGES.rst
index 66f0250..3cd9280 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -27,6 +27,20 @@ Changes
   doctests on both Python 2 and Python 3. See `issue 21
   <https://github.com/zopefoundation/zope.configuration/issues/21>`_.
 
+- Fix ``GlobalObject`` and ``GlobalInterface`` fields to only accept
+  dotted names instead of names with ``/``. Previously, slash
+  delimited names could result in incorrect imports. See `issue 6
+  <https://github.com/zopefoundation/zope.configuration/issues/6>`_.
+
+- Fix the schema fields to include the ``value`` and ``field`` values
+  on exceptions they raise.
+
+- Make ``zope.configuration.fields.PythonIdentifier`` subclass
+  ``PythonIdentifier`` from ``zope.schema``. It now implements ``fromBytes``
+  always produces a native string, and validates the value in
+  ``fromUnicode``. See `issue 28
+  <https://github.com/zopefoundation/zope.configuration/issues/28>`_.
+
 4.1.0 (2017-04-26)
 ------------------
 
diff --git a/docs/api/fields.rst b/docs/api/fields.rst
index dd542dc..928a632 100644
--- a/docs/api/fields.rst
+++ b/docs/api/fields.rst
@@ -33,17 +33,17 @@
    .. doctest::
 
       >>> for value in (u'foo', u'foo3', u'foo_', u'_foo3', u'foo_3', u'foo3_'):
-      ...     field._validate(value)
+      ...     _ = field.fromUnicode(value)
       >>> from zope.schema import ValidationError
       >>> for value in (u'3foo', u'foo:', u'\\', u''):
       ...     try:
-      ...         field._validate(value)
+      ...         field.fromUnicode(value)
       ...     except ValidationError:
-      ...         print('Validation Error')
-      Validation Error
-      Validation Error
-      Validation Error
-      Validation Error
+      ...         print('Validation Error ' + repr(value))
+      Validation Error '3foo'
+      Validation Error 'foo:'
+      Validation Error '\\'
+      Validation Error ''
 
 .. autoclass:: GlobalObject
    :members:
diff --git a/setup.py b/setup.py
index fc9a6b9..00c5a0f 100644
--- a/setup.py
+++ b/setup.py
@@ -27,8 +27,9 @@ def read(*rnames):
 TESTS_REQUIRE = [
     'manuel',
     # We test the specific exceptions raised, which
-    # chang from version to version.
-    'zope.schema >= 4.8.0',
+    # change from version to version, and we need the behaviour
+    # in DottedName that allows underscores.
+    'zope.schema >= 4.9.0',
     'zope.testing',
     'zope.testrunner',
 ]
diff --git a/src/zope/configuration/fields.py b/src/zope/configuration/fields.py
index bb27c07..b27a236 100644
--- a/src/zope/configuration/fields.py
+++ b/src/zope/configuration/fields.py
@@ -14,45 +14,47 @@
 """Configuration-specific schema fields
 """
 import os
-import re
 import sys
 import warnings
 
 from zope.interface import implementer
 from zope.schema import Bool as schema_Bool
+from zope.schema import DottedName
 from zope.schema import Field
 from zope.schema import InterfaceField
 from zope.schema import List
+from zope.schema import PythonIdentifier as schema_PythonIdentifier
 from zope.schema import Text
-from zope.schema import TextLine
 from zope.schema import ValidationError
 from zope.schema.interfaces import IFromUnicode
+from zope.schema.interfaces import InvalidValue
 
 from zope.configuration.exceptions import ConfigurationError
 from zope.configuration.interfaces import InvalidToken
 
 
-PYIDENTIFIER_REGEX = u'\\A[a-zA-Z_]+[a-zA-Z0-9_]*\\Z'
-pyidentifierPattern = re.compile(PYIDENTIFIER_REGEX)
-
-
-@implementer(IFromUnicode)
-class PythonIdentifier(TextLine):
-    """This field describes a python identifier, i.e. a variable name.
+class PythonIdentifier(schema_PythonIdentifier):
+    """
+    This class is like `zope.schema.PythonIdentifier`, but does not allow empty strings.
     """
-    def fromUnicode(self, u):
-        return u.strip()
 
     def _validate(self, value):
         super(PythonIdentifier, self)._validate(value)
-        if pyidentifierPattern.match(value) is None:
-            raise ValidationError(value)
+        if not value:
+            raise ValidationError(value).with_field_and_value(self, value)
 
 
 @implementer(IFromUnicode)
 class GlobalObject(Field):
-    """An object that can be accessed as a module global.
     """
+    An object that can be accessed as a module global.
+
+    The special value ``*`` indicates a value of `None`; this is
+    not validated against the *value_type*.
+    """
+
+    _DOT_VALIDATOR = DottedName()
+
     def __init__(self, value_type=None, **kw):
         self.value_type = value_type
         super(GlobalObject, self).__init__(**kw)
@@ -62,17 +64,26 @@ class GlobalObject(Field):
         if self.value_type is not None:
             self.value_type.validate(value)
 
-    def fromUnicode(self, u):
-        name = str(u.strip())
+    def fromUnicode(self, value):
+        name = str(value.strip())
 
         # special case, mostly for interfaces
         if name == '*':
             return None
 
+        try:
+            # Leading dots are allowed here to indicate current
+            # package.
+            to_validate = name[1:] if name.startswith('.') else name
+            self._DOT_VALIDATOR.validate(to_validate)
+        except ValidationError as v:
+            v.with_field_and_value(self, name)
+            raise
+
         try:
             value = self.context.resolve(name)
         except ConfigurationError as v:
-            raise ValidationError(v)
+            raise ValidationError(v).with_field_and_value(self, name)
 
         self.validate(value)
         return value
@@ -99,7 +110,7 @@ class Tokens(List):
                 try:
                     v = vt.fromUnicode(s)
                 except ValidationError as v:
-                    raise InvalidToken("%s in %s" % (v, u))
+                    raise InvalidToken("%s in %s" % (v, u)).with_field_and_value(self, s)
                 else:
                     values.append(v)
         else:
@@ -131,13 +142,15 @@ class Bool(schema_Bool):
     Values may be input (in upper or lower case) as any of:
        yes, no, y, n, true, false, t, or f.
     """
-    def fromUnicode(self, u):
-        u = u.lower()
-        if u in ('1', 'true', 'yes', 't', 'y'):
+    def fromUnicode(self, value):
+        value = value.lower()
+        if value in ('1', 'true', 'yes', 't', 'y'):
             return True
-        if u in ('0', 'false', 'no', 'f', 'n'):
+        if value in ('0', 'false', 'no', 'f', 'n'):
             return False
-        raise ValidationError
+        # Unlike the superclass, anything else is invalid.
+        raise InvalidValue().with_field_and_value(self, value)
+
 
 
 @implementer(IFromUnicode)

Dotted name resolver accepts '/' as module name separator
In https://bugs.launchpad.net/zope.configuration/+bug/161984 @ctheune reported:

> It's possible to do something like this:
> 
> ``` xml
> <include package="zope/config.config"/>
> ```
> 
> This will result in a separate import so that `zope.config.config` and `zope/config.config` are two different modules. This can lead to confusing errors because all the ZCML is executed but doesn't seem to apply (maybe even just partially doesn't apply).
> 
> It currently works this way because Python's `__import__` function allows '/' and '.' to be used. However, I couldn't find any documentation on the `__import__` function that says that '/' is being treated as a path separator. Maybe this should be reported to Python's tracker as well.
> 
> I propose to modify the definition of the schema field to not accept slashes.

diff --git a/src/zope/configuration/tests/test_fields.py b/src/zope/configuration/tests/test_fields.py
index 7eeaeec..734572e 100644
--- a/src/zope/configuration/tests/test_fields.py
+++ b/src/zope/configuration/tests/test_fields.py
@@ -36,39 +36,6 @@ class _ConformsToIFromUnicode(object):
         verifyObject(IFromUnicode, self._makeOne())
 
 
-class PythonIdentifierTests(unittest.TestCase, _ConformsToIFromUnicode):
-
-    def _getTargetClass(self):
-        from zope.configuration.fields import PythonIdentifier
-        return PythonIdentifier
-
-    def _makeOne(self, *args, **kw):
-        return self._getTargetClass()(*args, **kw)
-
-    def test_fromUnicode_empty(self):
-        pi = self._makeOne()
-        self.assertEqual(pi.fromUnicode(''), '')
-
-    def test_fromUnicode_normal(self):
-        pi = self._makeOne()
-        self.assertEqual(pi.fromUnicode('normal'), 'normal')
-
-    def test_fromUnicode_strips_ws(self):
-        pi = self._makeOne()
-        self.assertEqual(pi.fromUnicode('   '), '')
-        self.assertEqual(pi.fromUnicode(' normal  '), 'normal')
-
-    def test__validate_miss(self):
-        from zope.schema import ValidationError
-        pi = self._makeOne()
-        with self.assertRaises(ValidationError):
-            pi._validate(u'not-an-identifier')
-
-    def test__validate_hit(self):
-        pi = self._makeOne()
-        pi._validate(u'is_an_identifier')
-
-
 class GlobalObjectTests(unittest.TestCase, _ConformsToIFromUnicode):
 
     def _getTargetClass(self):
@@ -107,9 +74,12 @@ class GlobalObjectTests(unittest.TestCase, _ConformsToIFromUnicode):
         go = self._makeOne()
         context = Context()
         bound = go.bind(context)
-        with self.assertRaises(ValidationError):
+        with self.assertRaises(ValidationError) as exc:
             bound.fromUnicode('tried')
         self.assertEqual(context._resolved, 'tried')
+        ex = exc.exception
+        self.assertIs(ex.field, bound)
+        self.assertEqual(ex.value, 'tried')
 
     def test_fromUnicode_w_resolve_success(self):
         _target = object()
@@ -141,6 +111,16 @@ class GlobalObjectTests(unittest.TestCase, _ConformsToIFromUnicode):
             bound.fromUnicode('tried')
         self.assertEqual(context._resolved, 'tried')
 
+    def test_fromUnicode_rejects_slash(self):
+        from zope.schema import ValidationError
+        _target = object()
+        field = self._makeOne()
+        with self.assertRaises(ValidationError) as exc:
+            field.fromUnicode('foo/bar')
+        ex = exc.exception
+        self.assertIs(ex.field, field)
+        self.assertEqual(ex.value, 'foo/bar')
+
 
 class GlobalInterfaceTests(unittest.TestCase, _ConformsToIFromUnicode):
 
@@ -179,9 +159,13 @@ class TokensTests(unittest.TestCase, _ConformsToIFromUnicode):
         from zope.schema import Int
         from zope.configuration.interfaces import InvalidToken
         tok = self._makeOne(value_type=Int(min=0))
-        with self.assertRaises(InvalidToken):
+        with self.assertRaises(InvalidToken) as exc:
             tok.fromUnicode(u' 1 -1 3 ')
 
+        ex = exc.exception
+        self.assertIs(ex.field, tok)
+        self.assertEqual(ex.value, '-1')
+
 
 class PathTests(unittest.TestCase, _ConformsToIFromUnicode):
 
@@ -234,10 +218,13 @@ class BoolTests(unittest.TestCase, _ConformsToIFromUnicode):
             self.assertEqual(bo.fromUnicode(value), False)
 
     def test_fromUnicode_w_invalid(self):
-        from zope.schema import ValidationError
+        from zope.schema.interfaces import InvalidValue
         bo = self._makeOne()
-        with self.assertRaises(ValidationError):
+        with self.assertRaises(InvalidValue) as exc:
             bo.fromUnicode('notvalid')
+        ex = exc.exception
+        self.assertIs(ex.field, bo)
+        self.assertEqual(ex.value, 'notvalid')
 
 
 class MessageIDTests(unittest.TestCase, _ConformsToIFromUnicode):

pip install -e .[dev]
parse_log_pytest
pytest
pytest
3.7
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs @ file:///croot/attrs_1668696182826/work
certifi @ file:///croot/certifi_1671487769961/work/certifi
flit_core @ file:///opt/conda/conda-bld/flit-core_1644941570762/work/source/flit_core
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1648562407465/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
packaging @ file:///croot/packaging_1671697413597/work
pluggy @ file:///tmp/build/80754af9/pluggy_1648042572264/work
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pytest==7.1.2
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
typing_extensions @ file:///croot/typing_extensions_1669924550328/work
zipp @ file:///croot/zipp_1672387121353/work
-e git+https://github.com/zopefoundation/zope.configuration.git@cd96619be3714183270889b5f0037bebed8cb067#egg=zope.configuration
zope.event==5.0
zope.i18nmessageid==6.1.0
zope.interface==6.4.post2
zope.schema==7.0.1

name: zope.configuration
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=22.1.0=py37h06a4308_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - flit-core=3.6.0=pyhd3eb1b0_0
  - importlib-metadata=4.11.3=py37h06a4308_0
  - importlib_metadata=4.11.3=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=22.0=py37h06a4308_0
  - pip=22.3.1=py37h06a4308_0
  - pluggy=1.0.0=py37h06a4308_1
  - py=1.11.0=pyhd3eb1b0_0
  - pytest=7.1.2=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py37h06a4308_0
  - typing_extensions=4.4.0=py37h06a4308_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.11.0=py37h06a4308_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - zope-event==5.0
      - zope-i18nmessageid==6.1.0
      - zope-interface==6.4.post2
      - zope-schema==7.0.1
prefix: /opt/conda/envs/zope.configuration

src/zope/configuration/tests/test_fields.py::GlobalObjectTests::test_fromUnicode_rejects_slash src/zope/configuration/tests/test_fields.py::GlobalObjectTests::test_fromUnicode_w_resolve_fails src/zope/configuration/tests/test_fields.py::TokensTests::test_fromUnicode_invalid src/zope/configuration/tests/test_fields.py::BoolTests::test_fromUnicode_w_invalid
src/zope/configuration/tests/test_fields.py::GlobalObjectTests::test__validate_w_value_type src/zope/configuration/tests/test_fields.py::GlobalObjectTests::test__validate_wo_value_type src/zope/configuration/tests/test_fields.py::GlobalObjectTests::test_class_conforms_to_IFromUnicode src/zope/configuration/tests/test_fields.py::GlobalObjectTests::test_fromUnicode_w_resolve_but_validation_fails src/zope/configuration/tests/test_fields.py::GlobalObjectTests::test_fromUnicode_w_resolve_success src/zope/configuration/tests/test_fields.py::GlobalObjectTests::test_fromUnicode_w_star_and_extra_ws src/zope/configuration/tests/test_fields.py::GlobalObjectTests::test_instance_conforms_to_IFromUnicode src/zope/configuration/tests/test_fields.py::GlobalInterfaceTests::test_class_conforms_to_IFromUnicode src/zope/configuration/tests/test_fields.py::GlobalInterfaceTests::test_ctor src/zope/configuration/tests/test_fields.py::GlobalInterfaceTests::test_instance_conforms_to_IFromUnicode src/zope/configuration/tests/test_fields.py::TokensTests::test_class_conforms_to_IFromUnicode src/zope/configuration/tests/test_fields.py::TokensTests::test_fromUnicode_empty src/zope/configuration/tests/test_fields.py::TokensTests::test_fromUnicode_strips_ws src/zope/configuration/tests/test_fields.py::TokensTests::test_instance_conforms_to_IFromUnicode src/zope/configuration/tests/test_fields.py::PathTests::test_class_conforms_to_IFromUnicode src/zope/configuration/tests/test_fields.py::PathTests::test_fromUnicode_absolute src/zope/configuration/tests/test_fields.py::PathTests::test_fromUnicode_relative src/zope/configuration/tests/test_fields.py::PathTests::test_instance_conforms_to_IFromUnicode src/zope/configuration/tests/test_fields.py::BoolTests::test_class_conforms_to_IFromUnicode src/zope/configuration/tests/test_fields.py::BoolTests::test_fromUnicode_w_false_values src/zope/configuration/tests/test_fields.py::BoolTests::test_fromUnicode_w_true_values src/zope/configuration/tests/test_fields.py::BoolTests::test_instance_conforms_to_IFromUnicode src/zope/configuration/tests/test_fields.py::MessageIDTests::test_class_conforms_to_IFromUnicode src/zope/configuration/tests/test_fields.py::MessageIDTests::test_domain_decodes_bytes src/zope/configuration/tests/test_fields.py::MessageIDTests::test_instance_conforms_to_IFromUnicode src/zope/configuration/tests/test_fields.py::MessageIDTests::test_w_empty_id src/zope/configuration/tests/test_fields.py::MessageIDTests::test_w_id_and_default src/zope/configuration/tests/test_fields.py::MessageIDTests::test_wo_domain src/zope/configuration/tests/test_fields.py::test_suite
setup.py src/zope/configuration/fields.py docs/api/fields.rst CHANGES.rst
setup.py src/zope/configuration/fields.py docs/api/fields.rst CHANGES.rst