Repository: diffpy/diffpy.structure (language: python)

Issue:
fix news and changelog
replace #81 


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 3d4b5e17..e446d478 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -4,23 +4,6 @@ Release Notes
 
 .. current developments
 
-Version 3.2.0 - 2024-7-2
---------------------------
-**Added:**
-
-**Changed:**
-
-**Deprecated:**
-
-**Removed:**
-
-**Fixed:**
-
-- Repo structure modified to the new diffpy standard
-
-**Security:**
-
-
 Version 3.1.0 - 2022-12-04
 --------------------------
 
diff --git a/README.rst b/README.rst
index 2fe46560..42d7ef98 100644
--- a/README.rst
+++ b/README.rst
@@ -66,7 +66,7 @@ by citing the following paper in your publication:
 Requirements
 ------------------------------------------------------------------------
 
-The diffpy.structure package requires Python 3.7 or later or 2.7 and
+The diffpy.structure package requires Python 3.7 or later and
 the following software:
 
 * ``setuptools`` - software distribution tools for Python
diff --git a/doc/source/api/diffpy.structure.applications.rst b/doc/source/api/diffpy.structure.applications.rst
deleted file mode 100644
index 30316d0b..00000000
--- a/doc/source/api/diffpy.structure.applications.rst
+++ /dev/null
@@ -1,28 +0,0 @@
-:tocdepth: -1
-
-diffpy.structure.applications package
-=====================================
-
-.. automodule:: diffpy.structure.applications
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-Submodules
-----------
-
-diffpy.structure.applications.transtru module
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. automodule:: diffpy.structure.applications.transtru
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-diffpy.structure.applications.anyeye module
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. automodule:: diffpy.structure.applications.anyeye
-    :members:
-    :undoc-members:
-    :show-inheritance:
diff --git a/doc/source/api/diffpy.structure.rst b/doc/source/api/diffpy.structure.rst
index e414b921..95ff1285 100644
--- a/doc/source/api/diffpy.structure.rst
+++ b/doc/source/api/diffpy.structure.rst
@@ -16,7 +16,6 @@ Subpackages
 
     diffpy.structure.parsers
     diffpy.structure.expansion
-    diffpy.structure.applications
     diffpy.structure.apps
 
 Submodules
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 1a169473..d3af3e37 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -48,6 +48,8 @@
     "m2r",
 ]
 
+autodoc_member_order = "groupwise"
+
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ["_templates"]
 
@@ -118,6 +120,12 @@
 # Display all warnings for missing links.
 nitpicky = True
 
+nitpick_ignore = [
+    ("py:class", "array_like"),
+    ("py:class", "Parser"),
+    ("py:class", "CifFile"),
+]
+
 # -- Options for HTML output ----------------------------------------------
 
 # The theme to use for HTML and HTML Help pages.  See the documentation for
@@ -289,3 +297,7 @@
 
 # Example configuration for intersphinx: refer to the Python standard library.
 # intersphinx_mapping = {'http://docs.python.org/': None}
+intersphinx_mapping = {
+    "python": ("https://docs.python.org/3", None),
+    "numpy": ("https://numpy.org/doc/stable/", None),
+}
diff --git a/news/changlog.rst b/news/changlog.rst
new file mode 100644
index 00000000..fa57dae8
--- /dev/null
+++ b/news/changlog.rst
@@ -0,0 +1,25 @@
+**Added:**
+
+* <news item>
+
+**Changed:**
+
+* All docstrings style updated to numpydoc.
+
+**Deprecated:**
+
+* Deprecated the `diffpy.structure.applications` module. Use
+  `diffpy.structure.apps` instead.
+
+**Removed:**
+
+* Removed all `six` compatibility code. The package is now going to 
+  Python > 3.10.
+
+**Fixed:**
+
+* Repo structure modified to the new diffpy standard.
+
+**Security:**
+
+* <news item>
diff --git a/requirements/run.txt b/requirements/run.txt
index cdc2699e..70f81389 100644
--- a/requirements/run.txt
+++ b/requirements/run.txt
@@ -1,3 +1,2 @@
 numpy < 2.0.0  # Need to fix deprecations before 2.0.0 compat
 pycifrw
-six
diff --git a/src/diffpy/Structure.py b/src/diffpy/Structure.py
index 7847de42..1f65df4b 100644
--- a/src/diffpy/Structure.py
+++ b/src/diffpy/Structure.py
@@ -13,12 +13,13 @@
 #
 ##############################################################################
 
-"""
-Support import of old camel-case module names with DeprecationWarning.
+"""Support import of old camel-case module names with `DeprecationWarning`.
 
 The imported camel-case modules are aliases for the current module
-instances.  Their `__name__` attributes are thus all in lower-case.
+instances. Their `__name__` attributes are thus all in lower-case.
 
+Warning
+-------
 This module is deprecated and will be removed in the future.
 """
 
diff --git a/src/diffpy/structure/__init__.py b/src/diffpy/structure/__init__.py
index 7bc43afe..f8106490 100644
--- a/src/diffpy/structure/__init__.py
+++ b/src/diffpy/structure/__init__.py
@@ -13,16 +13,26 @@
 #
 ##############################################################################
 
-"""classes related to structure of materials
-Classes:
-    Atom
-    Lattice
-    Structure
-    PDFFitStructure
+"""
+Crystal structure container and parsers for structure formats.
+
+Classes related to the structure of materials:
+    * Atom
+    * Lattice
+    * Structure
+    * PDFFitStructure
+
+Other classes:
+    * SpaceGroup
+    * SymOp
+    * ExpandAsymmetricUnit
+    * GeneratorSite
+    * SymmetryConstraints
+
 Exceptions:
-    StructureFormatError
-    LatticeError
-    SymmetryError
+    * StructureFormatError
+    * LatticeError
+    * SymmetryError
 """
 
 # Interface definitions ------------------------------------------------------
@@ -37,27 +47,24 @@
 # package version
 from diffpy.structure.version import __version__
 
-"""Crystal structure container and parsers for structure formats."""
-
 # top level routines
 
 
 def loadStructure(filename, fmt="auto", **kw):
-    """
-    Load new structure object from the specified file.
+    """Load new structure object from the specified file.
 
     Parameters
     ----------
 
     filename : str
         Path to the file to be loaded.
-    fmt : str, optional
-        Format of the structure file such as 'cif' or 'xyz'.  Must be
+    fmt : str, Optional
+        Format of the structure file such as 'cif' or 'xyz'. Must be
         one of the formats listed by the `parsers.inputFormats` function.
         When 'auto', all supported formats are tried in a sequence.
-    kw : misc, optional
+    kw : Optional
         Extra keyword arguments that are passed to `parsers.getParser`
-        function.  These configure the dedicated Parser object that
+        function. These configure the dedicated Parser object that
         is used to read content in filename.
 
     Returns
diff --git a/src/diffpy/structure/_legacy_importer.py b/src/diffpy/structure/_legacy_importer.py
index 743de895..e37a907f 100644
--- a/src/diffpy/structure/_legacy_importer.py
+++ b/src/diffpy/structure/_legacy_importer.py
@@ -17,33 +17,23 @@
 Support import of old camel-case module names with DeprecationWarning.
 
 The imported camel-case modules are aliases for the current module
-instances.  Their `__name__` attributes are thus all in lower-case.
+instances. Their `__name__` attributes are thus all in lower-case.
 
-This module is deprecated and will be removed in the future.
+Note
+----
+this module must be only imported from `diffpy.Structure`.
 
-NOTE: this module must be only imported from `diffpy.Structure`.
+Warning
+-------
+This module is deprecated and will be removed in the future.
 """
 
 
+import importlib.abc
 import sys
 from warnings import warn
 
-import six
-
-if six.PY2:
-    import importlib
-
-    class mock_importlib_abc(object):
-        MetaPathFinder = object
-        Loader = object
-
-    importlib.abc = mock_importlib_abc
-    sys.modules.setdefault("importlib.abc", mock_importlib_abc)
-    del mock_importlib_abc
-
-import importlib.abc
-
-WMSG = "Module {!r} is deprecated.  Use {!r} instead."
+WMSG = "Module {!r} is deprecated. Use {!r} instead."
 
 # ----------------------------------------------------------------------------
 
@@ -63,15 +53,6 @@ def find_spec(self, fullname, path=None, target=None):
             spec.loader = MapRenamedStructureModule()
         return spec
 
-    if six.PY2:
-
-        def find_module(self, fullname, path):
-            # only handle submodules of diffpy.Structure
-            loader = None
-            if fullname.startswith(self.prefix):
-                loader = MapRenamedStructureModule()
-            return loader
-
 
 # end of class FindRenamedStructureModule
 
@@ -79,9 +60,7 @@ def find_module(self, fullname, path):
 
 
 class MapRenamedStructureModule(importlib.abc.Loader):
-    """
-    Loader for old camel-case module names.
-
+    """Loader for old camel-case module names.
     Import the current module and alias it under the old name.
     """
 
@@ -95,15 +74,6 @@ def create_module(self, spec):
     def exec_module(self, module):
         return
 
-    if six.PY2:
-        from collections import namedtuple
-
-        ModuleSpec = namedtuple("ModuleSpec", "name")
-
-        def load_module(self, fullname):
-            spec = self.ModuleSpec(fullname)
-            return self.create_module(spec)
-
 
 # end of class MapRenamedStructureModule
 
diff --git a/src/diffpy/structure/applications/__init__.py b/src/diffpy/structure/applications/__init__.py
deleted file mode 100644
index bc4f87eb..00000000
--- a/src/diffpy/structure/applications/__init__.py
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env python
-##############################################################################
-#
-# diffpy.structure  Complex Modeling Initiative
-#                   (c) 2019 Brookhaven Science Associates,
-#                   Brookhaven National Laboratory.
-#                   All rights reserved.
-#
-# File coded by:    Pavol Juhas
-#
-# See AUTHORS.txt for a list of people who contributed.
-# See LICENSE.txt for license information.
-#
-##############################################################################
-
-"""
-Import support for renamed subpackage diffpy.structure.applications.
-
-This module is deprecated and will be removed in version 3.1.
-"""
-
-# TODO remove this module in version 3.1.
-
-from warnings import warn
-
-warn(
-    "Module 'diffpy.structure.applications' is deprecated.  " "Import 'diffpy.structure.apps' instead.",
-    DeprecationWarning,
-    stacklevel=2,
-)
diff --git a/src/diffpy/structure/applications/anyeye.py b/src/diffpy/structure/applications/anyeye.py
deleted file mode 100755
index c2b9b334..00000000
--- a/src/diffpy/structure/applications/anyeye.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-
-"""
-Temporary support for old import name.
-
-This module is deprecated and will be removed in version 3.1.
-"""
-
-# TODO remove this module in version 3.1.
-
-from diffpy.structure.apps.anyeye import main
-
-if __name__ == "__main__":
-    main()
diff --git a/src/diffpy/structure/applications/transtru.py b/src/diffpy/structure/applications/transtru.py
deleted file mode 100755
index 8c911912..00000000
--- a/src/diffpy/structure/applications/transtru.py
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python
-
-"""
-Temporary support for old import name.
-
-This module is deprecated and will be removed in version 3.1.
-"""
-
-# TODO remove this module in version 3.1.
-
-from diffpy.structure.apps.transtru import main
-
-if __name__ == "__main__":
-    main()
diff --git a/src/diffpy/structure/apps/__init__.py b/src/diffpy/structure/apps/__init__.py
index 7a953806..6f0249a8 100644
--- a/src/diffpy/structure/apps/__init__.py
+++ b/src/diffpy/structure/apps/__init__.py
@@ -13,5 +13,5 @@
 #
 ##############################################################################
 
-"""Script applications that use the diffpy.structure package.
+"""Script applications that use the `diffpy.structure` package.
 """
diff --git a/src/diffpy/structure/apps/anyeye.py b/src/diffpy/structure/apps/anyeye.py
index 4466f93f..fbf549ca 100755
--- a/src/diffpy/structure/apps/anyeye.py
+++ b/src/diffpy/structure/apps/anyeye.py
@@ -13,24 +13,37 @@
 #
 ##############################################################################
 
-"""anyeye    view structure file in atomeye
-Usage: anyeye [options] strufile
+"""
+Anyeye view structure file in atomeye.
+
+Usage: ``anyeye [options] strufile``
 
-anyeye understands more structure formats than atomeye.  It converts strufile
-to a temporary XCFG file which is opened in atomeye.  Supported file formats:
-  inputFormats
+Anyeye understands more `Structure` formats than atomeye. It converts `strufile`
+to a temporary XCFG file which is opened in atomeye. See supported file formats:
+``inputFormats``
 
 Options:
-  -f, --formula     override chemical formula in strufile, formula defines
-                    elements in the same order as in strufile, e.g, Na4Cl4
-  -w, --watch       watch input file for changes
-  --viewer=VIEWER   the structure viewer program, by default "atomeye".
-                    The program will be executed as "VIEWER structurefile"
-  --formats=FORMATS comma separated list of file formats that are understood
-                    by the VIEWER, by default "xcfg,pdb".  Files of other
-                    formats will be converted to the first listed format.
-  -h, --help        display this message and exit
-  -V, --version     show script version and exit
+  -f, --formula
+      Override chemical formula in `strufile`. The formula defines
+      elements in the same order as in `strufile`, e.g., ``Na4Cl4``.
+
+  -w, --watch
+      Watch input file for changes.
+
+  --viewer=VIEWER
+      The structure viewer program, by default "atomeye".
+      The program will be executed as "VIEWER structurefile".
+
+  --formats=FORMATS
+      Comma-separated list of file formats that are understood
+      by the VIEWER, by default ``"xcfg,pdb"``. Files of other
+      formats will be converted to the first listed format.
+
+  -h, --help
+      Display this message and exit.
+
+  -V, --version
+      Show script version and exit.
 """
 
 from __future__ import print_function
@@ -52,7 +65,7 @@
 
 
 def usage(style=None):
-    """show usage info, for style=="brief" show only first 2 lines"""
+    """Show usage info, for ``style=="brief"`` show only first 2 lines."""
     import os.path
 
     myname = os.path.basename(sys.argv[0])
@@ -78,7 +91,17 @@ def version():
 def loadStructureFile(filename, format="auto"):
     """Load structure from specified file.
 
-    Return a tuple of (Structure, fileformat).
+    Parameters
+    ----------
+    filename : str
+        Path to the structure file.
+    format : str, Optional
+        File format, by default "auto".
+
+    Returns
+    -------
+    tuple
+        A tuple of (Structure, fileformat).
     """
     from diffpy.structure import Structure
 
@@ -152,7 +175,7 @@ def cleanUp(pd):
 
 
 def parseFormula(formula):
-    """parse chemical formula and return a list of elements"""
+    """Parse chemical formula and return a list of elements"""
     # remove all blanks
     formula = re.sub(r"\s", "", formula)
     if not re.match("^[A-Z]", formula):
diff --git a/src/diffpy/structure/apps/transtru.py b/src/diffpy/structure/apps/transtru.py
index cb81f54b..86c682db 100755
--- a/src/diffpy/structure/apps/transtru.py
+++ b/src/diffpy/structure/apps/transtru.py
@@ -13,22 +13,26 @@
 #
 ##############################################################################
 
-"""transtru   translate structure file to different format
-Usage: transtru INFMT..OUTFMT strufile
+"""Translate structure file to different format.
 
-translates structure file strufile from INFMT to OUTFMT format and prints it
-to the screen.  Use "-" as strufile to read from standard input.  To save the
+Usage: ``transtru INFMT..OUTFMT strufile``
+
+Translates structure file strufile from `INFMT` to `OUTFMT` format and prints it
+to the screen. Use "-" as `strufile` to read from standard input. To save the
 translated file, use
 
-    transtru INFMT..OUTFMT strufile > strufile.out
+    ``transtru INFMT..OUTFMT strufile > strufile.out``
 
 Supported input and output structure formats are
-  INFMT:   inputFormats
-  OUTFMT:  outputFormats
+    * `INFMT`: ``inputFormats``
+    * `OUTFMT`: ``outputFormats``
 
 Options:
-  -h, --help      display this message
-  -V, --version   show script version
+  -h, --help
+    Display this message.
+
+  -V, --version
+    Show script version.
 """
 
 from __future__ import print_function
@@ -40,7 +44,7 @@
 
 
 def usage(style=None):
-    """show usage info, for style=="brief" show only first 2 lines"""
+    """Show usage info, for ``style=="brief"`` show only first 2 lines."""
     import os.path
 
     myname = os.path.basename(sys.argv[0])
diff --git a/src/diffpy/structure/atom.py b/src/diffpy/structure/atom.py
index 3745d56a..9693b812 100644
--- a/src/diffpy/structure/atom.py
+++ b/src/diffpy/structure/atom.py
@@ -18,7 +18,6 @@
 """
 
 import numpy
-import six
 
 from diffpy.structure.lattice import cartesian as cartesian_lattice
 
@@ -30,8 +29,7 @@
 
 
 class Atom(object):
-    """
-    Storage of structure information relevant for a single atom.
+    """Storage of structure information relevant for a single atom.
 
     This class manages atom information such as element symbol, position
     in fractional and Cartesian coordinates, atomic displacement parameters
@@ -39,40 +37,40 @@ class Atom(object):
 
     Parameters
     ----------
-    atype : str or Atom, optional
+    atype : str or Atom, Optional
         The string atom type to be set as the `element` attribute.
-        By default an empty string.  When of the *Atom* type, create
-        a copy of *atype* and adjust it per other arguments.
-    xyz : ndarray, optional
+        By default an empty string. When of the `Atom` type, create
+        a copy of `atype` and adjust it per other arguments.
+    xyz : numpy.ndarray, Optional
         Fractional coordinates within the associated `lattice`.
         By default ``[0, 0, 0]``.
-    label : str, optional
-        A unique string `label` for referring to this Atom.
+    label : str, Optional
+        A unique string `label` for referring to this `Atom`.
         By default an empty string.
-    occupancy : float, optional
+    occupancy : float, Optional
         The initial `occupancy` of this atom, by default ``1``.
-    anisotropy : bool, optional
+    anisotropy : bool, Optional
         The flag for anisotropic thermal displacements parameters.
         This overrides `anisotropy` implied by presence of the
-        *U* or *Uisoequiv* arguments.  Defaults to ``False``
+        *U* or *Uisoequiv* arguments. Defaults to ``False``
         when not set in any other way.
-    U : ndarray, optional
+    U : numpy.ndarray, Optional
         The 3x3 matrix of anisotropic thermal displacement parameters.
         When present `anisotropy` defaults to ``True``.
-    Uisoequiv: float, optional
-        The isotropic atomic displacement parameter.  The `anisotropy`
-        defaults to ``False`` when present.  Only one of the *U* and
-        *Uisoequiv* arguments may be provided at the same time.  Assume
+    Uisoequiv: float, Optional
+        The isotropic atomic displacement parameter. The `anisotropy`
+        defaults to ``False`` when present. Only one of the *U* and
+        *Uisoequiv* arguments may be provided at the same time. Assume
         zero atomic displacements when *U* and *Uisoequiv* are unset.
-    lattice : Lattice
+    lattice : Lattice, Optional
         Coordinate system for the fractional coordinates `xyz`.
         Use the absolute Cartesian system when ``None``.
 
     Attributes
     ----------
     element : str
-        The string type of the atom.  An element or ion symbol.
-    xyz : ndarray
+        The string type of the atom. An element or ion symbol.
+    xyz : numpy.ndarray
         The fractional coordinates in the associated `lattice`.
     label : str
         A unique string label referring to this atom, for example, "C_1".
@@ -84,6 +82,10 @@ class Atom(object):
         Coordinate system for the fractional coordinates `xyz` and
         the tensor of atomic displacement parameters `U`.
         Use the absolute Cartesian coordinates when ``None``.
+
+    Note
+    ----
+    Cannot use both U and Uisoequiv arguments at the same time.
     """
 
     # Private attributes
@@ -93,10 +95,17 @@ class Atom(object):
 
     # instance attributes that have immutable default values
     element = ""
+    """str: Default values of `element`."""
+
     label = ""
+    """str: Default values of `label`."""
+
     occupancy = 1.0
+    """float: Default values of `occupancy`."""
+
     _anisotropy = False
     lattice = None
+    """None: Default values of `lattice`."""
 
     def __init__(
         self,
@@ -109,11 +118,6 @@ def __init__(
         Uisoequiv=None,
         lattice=None,
     ):
-        """
-        Create atom of the specified type at the given lattice coordinates.
-
-        Atom(a) creates a copy of Atom instance *a*.
-        """
         # check arguments
         if U is not None and Uisoequiv is not None:
             emsg = "Cannot use both U and Uisoequiv arguments."
@@ -148,8 +152,7 @@ def __init__(
         return
 
     def msdLat(self, vl):
-        """
-        Calculate mean square displacement along the lattice vector.
+        """Calculate mean square displacement along the lattice vector.
 
         Parameters
         ----------
@@ -173,8 +176,7 @@ def msdLat(self, vl):
         return msd
 
     def msdCart(self, vc):
-        """
-        Calculate mean square displacement along the Cartesian vector.
+        """Calculate mean square displacement along the Cartesian vector.
 
         Parameters
         ----------
@@ -198,22 +200,19 @@ def msdCart(self, vc):
         return msd
 
     def __repr__(self):
-        """
-        String representation of this Atom.
-        """
+        """String representation of this Atom."""
         xyz = self.xyz
         s = "%-4s %8.6f %8.6f %8.6f %6.4f" % (self.element, xyz[0], xyz[1], xyz[2], self.occupancy)
         return s
 
     def __copy__(self, target=None):
-        """
-        Create a copy of this instance.
+        """Create a copy of this instance.
 
         Parameters
         ----------
-        target : Atom, optional
-            An already existing Atom object to be updated to a duplicate
-            of this Atom.  Create a new Atom object when not specified.
+        target : Atom, Optional
+            An already existing `Atom` object to be updated to a duplicate
+            of this `Atom`. Create a new Atom object when not specified.
             This facilitates extension of the `__copy__` method
             in a derived class.
 
@@ -253,11 +252,10 @@ def __copy__(self, target=None):
 
     @property
     def xyz_cartn(self):
-        """
-        ndarray: Atom position in absolute Cartesian coordinates.
+        """numpy.ndarray: Atom position in absolute Cartesian coordinates.
 
         This is computed from fractional coordinates `xyz` and the
-        current `lattice` setup.  Assignment to *xyz_cartn* or
+        current `lattice` setup. Assignment to *xyz_cartn* or
         its components is applied on fractional coordinates `xyz`.
         """
         if not self.lattice:
@@ -278,8 +276,7 @@ def xyz_cartn(self, value):
 
     @property
     def anisotropy(self):
-        """
-        bool : Flag for allowing anisotropic displacement parameters.
+        """bool : Flag for allowing anisotropic displacement parameters.
 
         When ``False`` the tensor of thermal displacement parameters `U`
         must be isotropic and only its diagonal elements are taken into
@@ -304,8 +301,7 @@ def anisotropy(self, value):
 
     @property
     def U(self):
-        """
-        ndarray : The 3x3 matrix of anisotropic atomic displacements.
+        """numpy.ndarray : The 3x3 matrix of anisotropic atomic displacements.
 
         For isotropic displacements (when `anisotropy` is ``False``)
         assignment to *U* uses only the first ``Unew[0, 0]`` element
@@ -316,7 +312,7 @@ def U(self):
         ----
         Elements of the *U* tensor such as ``U[0, 1]`` should be
         considered read-only as setting them directly leads to
-        undefined behavior.  Use the `U11`, `U22`, ..., or `B11`,
+        undefined behavior. Use the `U11`, `U22`, ..., or `B11`,
         `B22`, ..., descriptors to set only some *U* components.
         """
         if not self.anisotropy:
@@ -334,18 +330,14 @@ def U(self, value):
     # Uij elements
 
     def _get_Uij(self, i, j):
-        """
-        The getter function for the `U11`, `U22`, ..., properties.
-        """
+        """The getter function for the `U11`, `U22`, ..., properties."""
         if self.anisotropy:
             return self._U[i, j]
         lat = self.lattice or cartesian_lattice
         return self._U[0, 0] * lat.isotropicunit[i, j]
 
     def _set_Uij(self, i, j, value):
-        """
-        The setter function for the  `U11`, `U22`, ..., properties.
-        """
+        """The setter function for the `U11`, `U22`, ..., properties."""
         self._U[i, j] = value
         self._U[j, i] = value
         if not self._anisotropy and i == j != 0:
@@ -374,7 +366,7 @@ def _set_Uij(self, i, j, value):
     _doc_uij = """
         float : The ``U[{0}, {1}]`` element of the displacement tensor `U`.
 
-        Sets ``U[{1}, {0}]`` together with ``U[{0}, {1}]``.  Assignment
+        Sets ``U[{1}, {0}]`` together with ``U[{0}, {1}]``. Assignment
         has no effect when `anisotropy` is ``False``.
         """
 
@@ -395,8 +387,7 @@ def _set_Uij(self, i, j, value):
 
     @property
     def Uisoequiv(self):
-        """
-        float : The isotropic displacement parameter or an equivalent value.
+        """float : The isotropic displacement parameter or an equivalent value.
 
         Setting a new value rescales tensor `U` so it yields equivalent
         direction-averaged displacements.
@@ -440,15 +431,15 @@ def Uisoequiv(self, value):
     _doc_bii = """
         float : The ``B{0}{0}`` element of the Debye-Waller matrix.
 
-        This is equivalent to ``8 * pi**2 * U{0}{0}``.  When `anisotropy`
+        This is equivalent to ``8 * pi**2 * U{0}{0}``. When `anisotropy`
         is ``False`` setting a new value updates entire tensor `U`.
         """
 
     _doc_bij = """
         float : The ``B{0}{1}`` element of the Debye-Waller matrix.
 
-        This is equivalent to ``8 * pi**2 * U{0}{1}``.  Setting a new
-        value updates `U` in a symmetric way.  Assignment has no effect
+        This is equivalent to ``8 * pi**2 * U{0}{1}``. Setting a new
+        value updates `U` in a symmetric way. Assignment has no effect
         when `anisotropy` is ``False``.
         """
 
@@ -490,10 +481,9 @@ def Uisoequiv(self, value):
 
     @property
     def Bisoequiv(self):
-        """
-        float : The Debye-Waller isotropic displacement or an equivalent value.
+        """float : The Debye-Waller isotropic displacement or an equivalent value.
 
-        This equals ``8 * pi**2 * Uisoequiv``.  Setting a new value
+        This equals ``8 * pi**2 * Uisoequiv``. Setting a new value
         rescales `U` tensor to yield equivalent direction-average of
         Debye-Waller displacements.
         """
@@ -511,8 +501,7 @@ def Bisoequiv(self, value):
 
 
 class _AtomCartesianCoordinates(numpy.ndarray):
-    """
-    Specialized numpy.ndarray for accessing Cartesian coordinates.
+    """Specialized `numpy.ndarray` for accessing Cartesian coordinates.
 
     Inplace assignments to this array are applied on the *xyz* position
     position of owner `Atom` as per the associated `Atom.lattice`.
@@ -520,13 +509,11 @@ class _AtomCartesianCoordinates(numpy.ndarray):
     Parameters
     ----------
     atom : Atom
-        Atom instance to be linked to these coordinate array.
+        `Atom` instance to be linked to these coordinate array.
     """
 
     def __new__(self, atom):
-        """
-        Create the underlying numpy array base object.
-        """
+        """Create the underlying numpy array base object."""
         return numpy.empty(3, dtype=float).view(self)
 
     def __init__(self, atom):
@@ -536,14 +523,11 @@ def __init__(self, atom):
 
     @property
     def asarray(self):
-        """
-        ndarray : This array viewed as standard numpy array.
-        """
+        """ndarray : This array viewed as standard numpy array."""
         return self.view(numpy.ndarray)
 
     def __setitem__(self, idx, value):
-        """
-        Set some element or slice of this Cartesian coordinates.
+        """Set some element or slice of this Cartesian coordinates.
 
         This overrides inplace array assignment to update the
         *xyz* fractional coordinate of the linked `Atom`.
@@ -553,20 +537,8 @@ def __setitem__(self, idx, value):
         return
 
     def __array_wrap__(self, out_arr, context=None):
-        """
-        Ensure math operations on this type yield standard numpy array.
-        """
+        """Ensure math operations on this type yield standard numpy array."""
         return out_arr.view(numpy.ndarray)
 
-    # Python 2 Compatibility -------------------------------------------------
-
-    if six.PY2:
-
-        def __setslice__(self, lo, hi, sequence):
-            self.__setitem__(slice(lo, hi), sequence)
-            return
-
-    # ------------------------------------------------------------------------
-
 
 # End of _AtomCartesianCoordinates
diff --git a/src/diffpy/structure/expansion/__init__.py b/src/diffpy/structure/expansion/__init__.py
index a00e7fcf..faa60ca3 100644
--- a/src/diffpy/structure/expansion/__init__.py
+++ b/src/diffpy/structure/expansion/__init__.py
@@ -13,11 +13,10 @@
 #
 ##############################################################################
 
-"""Methods and classes for manipulating Structure instances.
+"""Methods and classes for manipulating `Structure` instances.
 
 Package content:
-
-supercell   -- create a supercell from an existing Structure.
+    * supercell -- create a supercell from an existing `Structure`.
 """
 
 # Import below whatever should be available at package namespace.
diff --git a/src/diffpy/structure/expansion/makeellipsoid.py b/src/diffpy/structure/expansion/makeellipsoid.py
index bfd3a8e3..009be577 100644
--- a/src/diffpy/structure/expansion/makeellipsoid.py
+++ b/src/diffpy/structure/expansion/makeellipsoid.py
@@ -26,27 +26,42 @@
 def makeSphere(S, radius):
     """Create a spherical nanoparticle.
 
-    Arguments
-    S       --  A Structure instance
-    radius  --  primary equatorial radius (along x-axis)
-
-    Returns a new structure instance
+    Parameters
+    ----------
+    S : Structure
+        A `Structure` instance.
+    radius : float
+        Primary equatorial radius (along x-axis).
+
+    Returns
+    -------
+    Structure
+        A new `Structure` instance.
     """
     return makeEllipsoid(S, radius)
 
 
 def makeEllipsoid(S, a, b=None, c=None):
-    """Cut a structure out of another one.
-
-    Arguments
-    S       --  A Structure instance
-    a       --  primary equatorial radius (along x-axis)
-    b       --  secondary equatorial radius (along y-axis). If b is None
-                (default) then it is set equal to a
-    c       --  polar radius (along z-axis). If c is None (default), then it is
-                set equal to a.
-
-    Returns a new structure instance
+    """
+    Cut a `Structure` out of another one.
+
+    Parameters
+    ----------
+    S : Structure
+        A `Structure` instance.
+    a : float
+        Primary equatorial radius (along x-axis).
+    b : float, Optional
+        Secondary equatorial radius (along y-axis). If `b` is ``None``
+        (default), then it is set equal to `a`.
+    c : float, Optional
+        Polar radius (along z-axis). If `c` is ``None`` (default), then it is
+        set equal to `a`.
+
+    Returns
+    -------
+    Structure :
+        A new `Structure` instance.
     """
     if b is None:
         b = a
diff --git a/src/diffpy/structure/expansion/shapeutils.py b/src/diffpy/structure/expansion/shapeutils.py
index d05daecf..0e99df05 100644
--- a/src/diffpy/structure/expansion/shapeutils.py
+++ b/src/diffpy/structure/expansion/shapeutils.py
@@ -17,11 +17,19 @@
 
 
 def findCenter(S):
-    """Find the approximate center atom of a structure.
+    """Find the approximate center `Atom` of a `Structure`.
 
-    The center of the structure is the atom closest to (0.5, 0.5, 0.5)
+    The center of the `Structure` is the `Atom` closest to ``(0.5, 0.5, 0.5)``.
 
-    Returns the index of the atom.
+    Parameters
+    ----------
+    S : Structure
+        A `Structure` instance.
+
+    Returns
+    -------
+    int
+        The index of the center `Atom`.
     """
     best = -1
     bestd = len(S)
diff --git a/src/diffpy/structure/expansion/supercell_mod.py b/src/diffpy/structure/expansion/supercell_mod.py
index d0dc5f0a..b5760a3b 100644
--- a/src/diffpy/structure/expansion/supercell_mod.py
+++ b/src/diffpy/structure/expansion/supercell_mod.py
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-"""This module contains functions for simple structure manipulation.
+"""This module contains functions for simple `Structure` manipulation.
 """
 
 import numpy
@@ -22,19 +22,32 @@
 
 
 def supercell(S, mno):
-    """Perform supercell expansion for a structure.
+    """
+    Perform supercell expansion for a `Structure`.
 
-    New lattice parameters are multiplied and fractional coordinates
-    divided by corresponding multiplier.  New atoms are grouped with
+    New `lattice` parameters are multiplied and fractional coordinates
+    divided by corresponding multiplier. New `Atoms` are grouped with
     their source in the original cell.
 
-    S   -- an instance of Structure from diffpy.structure.
-    mno -- sequence of 3 integers for cell multipliers along
-           the a, b and c axes.
+    Parameters
+    ----------
+    S : Structure
+        An instance of `Structure` from `diffpy.structure`.
+    mno : array_like
+        Sequence of 3 integers for cell multipliers along
+        the `a`, `b` and `c` axes.
+
+    Returns
+    -------
+    Structure
+        A new `Structure` instance representing the expanded supercell.
 
-    Return a new expanded structure instance.
-    Raise TypeError when S is not Structure instance.
-    Raise ValueError for invalid mno argument.
+    Raises
+    ------
+    TypeError
+        `S` is not a `Structure` instance.
+    ValueError
+        Invalid `mno` argument.
     """
     # check arguments
     if len(mno) != 3:
diff --git a/src/diffpy/structure/lattice.py b/src/diffpy/structure/lattice.py
index 0139495e..fb51de04 100644
--- a/src/diffpy/structure/lattice.py
+++ b/src/diffpy/structure/lattice.py
@@ -13,11 +13,13 @@
 #
 ##############################################################################
 
-"""class Lattice stores properties and provides simple operations in lattice
+"""Class Lattice stores properties and provides simple operations in lattice
 coordinate system.
 
-Module variables:
-    cartesian   -- constant instance of Lattice, default Cartesian system
+Attributes
+----------
+cartesian : Lattice
+    Constant instance of Lattice, default Cartesian system.
 """
 
 import math
@@ -34,8 +36,19 @@
 
 
 def cosd(x):
-    """Return the cosine of x (measured in degrees).
+    """Return the cosine of *x* (measured in degrees).
+
     Avoid round-off errors for exact cosine values.
+
+    Parameters
+    ----------
+    x : float
+        The angle in degrees.
+
+    Returns
+    -------
+    float
+        The cosine of the angle *x*.
     """
     rv = _EXACT_COSD.get(x % 360.0)
     if rv is None:
@@ -44,8 +57,19 @@ def cosd(x):
 
 
 def sind(x):
-    """Return the sine of x (measured in degrees).
+    """Return the sine of *x* (measured in degrees).
+
     Avoid round-off errors for exact sine values.
+
+    Parameters
+    ----------
+    x : float
+        The angle in degrees.
+
+    Returns
+    -------
+    float
+        The sine of the angle *x*.
     """
     return cosd(90.0 - x)
 
@@ -54,14 +78,13 @@ def sind(x):
 
 
 class Lattice(object):
-    """
-    General coordinate system and associated operations.
+    """General coordinate system and associated operations.
 
     Parameters
     ----------
-    a : float or Lattice, optional
-        The cell length *a*.  When present, other cell parameters
-        must be also specified.  When of the *Lattice* type, create
+    a : float or Lattice, Optional
+        The cell length *a*. When present, other cell parameters
+        must be also specified. When of the *Lattice* type, create
         a duplicate Lattice.
     b : float
         The cell length *b*.
@@ -73,59 +96,59 @@ class Lattice(object):
         The angle between the *b* and *c* axes in degrees.
     gamma : float
         The angle between the *a* and *b* axes in degrees.
-    baserot : array_like, optional
+    baserot : array_like, Optional
         The 3x3 rotation matrix of the base vectors with respect
         to their standard setting.
-    base : array_like, optional
-        The 3x3 array of row base vectors.  This must be the
+    base : array_like, Optional
+        The 3x3 array of row base vectors. This must be the
         only argument when present.
 
     Attributes
     ----------
-    metrics : ndarray
+    metrics : numpy.ndarray
         The metrics tensor.
-    base : ndarray
+    base : numpy.ndarray
         The 3x3 matrix of row base vectors in Cartesian coordinates,
         which may be rotated, i.e., ``base = stdbase @ baserot``.
-    stdbase : ndarray
+    stdbase : numpy.ndarray
         The 3x3 matrix of row base vectors in standard orientation.
-    baserot : ndarray
+    baserot : numpy.ndarray
         The rotation matrix for the `base`.
-    recbase : ndarray
+    recbase : numpy.ndarray
         The inverse of the `base` matrix, where the columns give
         reciprocal vectors in Cartesian coordinates.
-    normbase : ndarray
+    normbase : numpy.ndarray
         The `base` vectors scaled by magnitudes of reciprocal cell lengths.
-    recnormbase : ndarray
+    recnormbase : numpy.ndarray
         The inverse of the `normbase` matrix.
-    isotropicunit : ndarray
+    isotropicunit : numpy.ndarray
         The 3x3 tensor for a unit isotropic displacement parameters in this
-        coordinate system.  This is an identity matrix when this Lattice
+        coordinate system. This is an identity matrix when this Lattice
         is orthonormal.
 
     Note
     ----
-    The array attributes are read-only.  They get updated by changing
+    The array attributes are read-only. They get updated by changing
     some lattice parameters or by calling the `setLatPar()` or
     `setLatBase()` methods.
 
     Examples
     --------
-    Create a Cartesian coordinate system::
+    Create a Cartesian coordinate system:
 
     >>> Lattice()
 
-    Create coordinate system with the cell lengths ``a``, ``b``, ``c``
-    and cell angles ``alpha``, ``beta``, ``gamma`` in degrees::
+    Create coordinate system with the cell lengths `a`, `b`, `c`
+    and cell angles `alpha`, `beta`, `gamma` in degrees:
 
     >>> Lattice(a, b, c, alpha, beta, gamma)
 
-    Create a duplicate of an existing Lattice ``lat``::
+    Create a duplicate of an existing Lattice `lat`:
 
     >>> Lattice(lat)
 
     Create coordinate system with the base vectors given by rows
-    of the ``abc`` matrix::
+    of the `abc` matrix:
 
     >>> Lattice(base=abc)
     """
@@ -169,7 +192,7 @@ class Lattice(object):
 
     @property
     def unitvolume(self):
-        """The unit cell volume when a = b = c = 1."""
+        """The unit cell volume when `a = b = c = 1`."""
         # Recalculate lattice cosines to ensure this is right
         # even if ca, cb, cg data were not yet updated.
         ca = cosd(self.alpha)
@@ -212,7 +235,7 @@ def unitvolume(self):
 
     sar = property(lambda self: self._sar, doc="The sine of the reciprocal angle *alpha*.")
 
-    sbr = property(lambda self: self._sbr, doc="flot: Sine of the reciprocal angle *beta*.")
+    sbr = property(lambda self: self._sbr, doc="The sine of the reciprocal angle *beta*.")
 
     sgr = property(lambda self: self._sgr, doc="The sine of the reciprocal angle *gamma*.")
 
@@ -272,19 +295,19 @@ def setLatPar(self, a=None, b=None, c=None, alpha=None, beta=None, gamma=None, b
 
         Parameters
         ----------
-        a : float, optional
+        a : float, Optional
             The new value of the cell length *a*.
-        b : float, optional
+        b : float, Optional
             The new value of the cell length *b*.
-        c : float, optional
+        c : float, Optional
             The new value of the cell length *c*.
-        alpha : float, optional
+        alpha : float, Optional
             The new value of the cell angle *alpha* in degrees.
-        beta : float, optional
+        beta : float, Optional
             The new value of the cell angle *beta* in degrees.
-        gamma : float, optional
+        gamma : float, Optional
             The new value of the cell angle *gamma* in degrees.
-        baserot : array_like, optional
+        baserot : array_like, Optional
             The new 3x3 rotation matrix of the base vectors with respect
             to their standard setting in Cartesian coordinates.
 
@@ -355,7 +378,7 @@ def setLatBase(self, base):
         """Set new base vectors for this lattice.
 
         This updates the cell lengths and cell angles according to the
-        new base.  The `stdbase`, `baserot`, and `metrics` attributes
+        new base. The `stdbase`, `baserot`, and `metrics` attributes
         are also updated.
 
         Parameters
@@ -403,7 +426,7 @@ def setLatBase(self, base):
         self.stdbase = numpy.array(
             [[1.0 / ar, -cgr / sgr / ar, cb * a], [0.0, b * sa, b * ca], [0.0, 0.0, c]], dtype=float
         )
-        # calculate unit cell rotation matrix,  base = stdbase @ baserot
+        # calculate unit cell rotation matrix, base = stdbase @ baserot
         self.baserot = numpy.dot(numalg.inv(self.stdbase), self.base)
         self.recbase = numalg.inv(self.base)
         # bases normalized to unit reciprocal vectors
@@ -418,16 +441,17 @@ def setLatBase(self, base):
         return
 
     def abcABG(self):
-        """
+        """Return the cell parameters in the standard setting.
         Returns
         -------
+        tuple :
             A tuple of ``(a, b, c, alpha, beta, gamma)``.
         """
         rv = (self.a, self.b, self.c, self.alpha, self.beta, self.gamma)
         return rv
 
     def reciprocal(self):
-        """
+        """Return the reciprocal lattice of the current lattice.
         Returns
         -------
         Lattice
@@ -447,7 +471,7 @@ def cartesian(self, u):
 
         Returns
         -------
-        rc : ndarray
+        rc : numpy.ndarray
             Cartesian coordinates of the *u* vector.
         """
         rc = numpy.dot(u, self.base)
@@ -464,7 +488,7 @@ def fractional(self, rc):
 
         Returns
         -------
-        u : ndarray
+        u : numpy.ndarray
             Fractional coordinates of the Cartesian vector *rc*.
         """
         u = numpy.dot(rc, self.recbase)
@@ -483,7 +507,7 @@ def dot(self, u, v):
 
         Returns
         -------
-        float or ndarray
+        float or numpy.ndarray
             The dot product of lattice vectors *u*, *v*.
         """
         dp = (u * numpy.dot(v, self.metrics)).sum(axis=-1)
@@ -499,7 +523,7 @@ def norm(self, xyz):
 
         Returns
         -------
-        float or ndarray
+        float or numpy.ndarray
             The magnitude of the lattice vector *xyz*.
         """
         # this is a few percent faster than sqrt(dot(u, u)).
@@ -515,7 +539,7 @@ def rnorm(self, hkl):
 
         Returns
         -------
-        float or ndarray
+        float or numpy.ndarray
             The magnitude of the reciprocal vector *hkl*.
         """
         hklcartn = numpy.dot(hkl, self.recbase.T)
@@ -528,7 +552,7 @@ def dist(self, u, v):
         ----------
         u : array_like
             A vector or an Nx3 matrix of fractional coordinates.
-        v : ndarray
+        v : numpy.ndarray
             A vector or an Nx3 matrix of fractional coordinates.
 
         Note
@@ -537,7 +561,7 @@ def dist(self, u, v):
 
         Returns
         -------
-        float or ndarray
+        float or numpy.ndarray
             The distance between lattice points *u* and *v*.
         """
         duv = numpy.asarray(u) - v
@@ -617,12 +641,12 @@ def _isotropicunit(recnormbase):
 
     Parameters
     ----------
-    recnormbase : ndarray
+    recnormbase : numpy.ndarray
         The inverse of normalized base vectors of some lattice.
 
     Returns
     -------
-    ndarray
+    numpy.ndarray
         The 3x3 matrix of displacement parameters corresponding to
         a unit isotropic displacements.
     """
diff --git a/src/diffpy/structure/mmlibspacegroups.py b/src/diffpy/structure/mmlibspacegroups.py
index 29e5dd0b..faa5ce2d 100644
--- a/src/diffpy/structure/mmlibspacegroups.py
+++ b/src/diffpy/structure/mmlibspacegroups.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # Copyright 2002 by PyMMLib Development Group, http://pymmlib.sourceforge.net/
 # This code is part of the PyMMLib distribution and governed by
-# its license.  Please see the LICENSE_pymmlib file that should have been
+# its license.Please see the LICENSE_pymmlib file that should have been
 # included as part of this package.
 """Space groups defined as a part of the pymmlib.
 """
diff --git a/src/diffpy/structure/parsers/__init__.py b/src/diffpy/structure/parsers/__init__.py
index 0924ff23..0d549b80 100644
--- a/src/diffpy/structure/parsers/__init__.py
+++ b/src/diffpy/structure/parsers/__init__.py
@@ -13,22 +13,22 @@
 #
 ##############################################################################
 
-"""Conversion plugins for various structure formats
+"""Conversion plugins for various structure formats.
 
-The recognized structure formats are defined by subclassing StructureParser,
-by convention these classes are named P_<format>.  The parser classes should
-to override the parseLines() and toLines() methods of StructureParser.
-Any structure parser needs to be registered in parser_index module.
+The recognized structure formats are defined by subclassing `StructureParser`,
+by convention these classes are named `P_<format>.py`. The parser classes should
+to override the `parseLines()` and `toLines()` methods of `StructureParser`.
+Any structure parser needs to be registered in `parser_index` module.
 
 For normal usage it should be sufficient to use the routines provided
 in this module.
 
 Content:
-    StructureParser -- base class for a concrete Parser
-    parser_index    -- dictionary of known structure formats
-    getParser       -- factory for Parser at given format
-    inputFormats    -- list of available input formats
-    outputFormats   -- list of available output formats
+    * StructureParser: base class for a concrete Parser
+    * parser_index: dictionary of known structure formats
+    * getParser: factory for Parser at given format
+    * inputFormats: list of available input formats
+    * outputFormats: list of available output formats
 """
 
 from diffpy.structure.parsers.parser_index_mod import parser_index
@@ -42,9 +42,22 @@
 def getParser(format, **kw):
     """Return Parser instance for a given structure format.
 
-    kw   -- keyword arguments passed to the Parser init function.
+    Parameters
+    ----------
+    format : str
+        String with the format name, see `parser_index_mod`.
+    **kw : dict
+        Keyword arguments passed to the Parser init function.
 
-    Raises StructureFormatError exception when format is not defined.
+    Returns
+    -------
+    Parser
+        Parser instance for the given format.
+
+    Raises
+    ------
+    StructureFormatError
+        When the format is not defined.
     """
     if format not in parser_index:
         emsg = "no parser for '%s' format" % format
@@ -57,14 +70,14 @@ def getParser(format, **kw):
 
 
 def inputFormats():
-    """Return list of implemented input structure formats"""
+    """Return list of implemented input structure formats."""
     input_formats = [fmt for fmt, prop in parser_index.items() if prop["has_input"]]
     input_formats.sort()
     return input_formats
 
 
 def outputFormats():
-    """return list of implemented output structure formats"""
+    """Return list of implemented output structure formats."""
     output_formats = [fmt for fmt, prop in parser_index.items() if prop["has_output"]]
     output_formats.sort()
     return output_formats
diff --git a/src/diffpy/structure/parsers/p_auto.py b/src/diffpy/structure/parsers/p_auto.py
index 96409453..745eb5a9 100644
--- a/src/diffpy/structure/parsers/p_auto.py
+++ b/src/diffpy/structure/parsers/p_auto.py
@@ -13,9 +13,9 @@
 #
 ##############################################################################
 
-"""Parser for automatic file format detection
+"""Parser for automatic file format detection.
 
-This Parser does not provide the the toLines() method.
+This Parser does not provide the the `toLines()` method.
 """
 
 import os
@@ -26,8 +26,23 @@
 
 class P_auto(StructureParser):
     """Parser with automatic detection of structure format.
-    When successful, it sets its format attribute to detected
-    structure format.
+
+    This parser attempts to automatically detect the format of a given
+    structure file and parse it accordingly. When successful, it sets
+    its `format` attribute to the detected structure format.
+
+    Parameters
+    ----------
+    **kw : dict
+        Keyword arguments for the structure parser.
+
+    Attributes
+    ----------
+    format : str
+        Detected structure format. Initially set to "auto" and updated
+        after successful detection of the structure format.
+    pkw : dict
+        Keyword arguments passed to the parser.
     """
 
     def __init__(self, **kw):
@@ -39,7 +54,7 @@ def __init__(self, **kw):
     # parseLines helpers
     def _getOrderedFormats(self):
         """Build a list of relevance ordered structure formats.
-        This only works when self.filename has a known extension.
+        This only works when `self.filename` has a known extension.
         """
         from diffpy.structure.parsers import inputFormats
 
@@ -62,41 +77,97 @@ def _getOrderedFormats(self):
         return ofmts
 
     def parseLines(self, lines):
-        """Detect format and create Structure instance from a list of lines.
+        """Detect format and create `Structure` instance from a list of lines.
+
         Set format attribute to the detected file format.
 
-        Return Structure object or raise StructureFormatError exception.
+        Parameters
+        ----------
+        lines : list
+            List of lines with structure data.
+
+        Returns
+        -------
+        Structure
+            `Structure` object.
+
+        Raises
+        ------
+        StructureFormatError
         """
         return self._wrapParseMethod("parseLines", lines)
 
     def parse(self, s):
-        """Detect format and create Structure instance from a string.
+        """Detect format and create `Structure` instance from a string.
+
         Set format attribute to the detected file format.
 
-        Return Structure object or raise StructureFormatError exception.
+        Parameters
+        ----------
+        s : str
+            String with structure data.
+
+        Returns
+        -------
+        Structure
+            `Structure` object.
+
+        Raises
+        ------
+        StructureFormatError
         """
         return self._wrapParseMethod("parse", s)
 
     def parseFile(self, filename):
         """Detect format and create Structure instance from an existing file.
-        Set format attribute to the detected file format.
 
-        filename  -- path to structure file
+        Set format attribute to the detected file format.
 
-        Return Structure object.
-        Raise StructureFormatError or IOError.
+        Parameters
+        ----------
+        filename : str
+            Path to structure file.
+
+        Returns
+        -------
+        Structure
+            `Structure` object.
+
+        Raises
+        ------
+        StructureFormatError
+            If the structure format is unknown or invalid.
+        IOError
+            If the file cannot be read.
         """
         self.filename = filename
         return self._wrapParseMethod("parseFile", filename)
 
     def _wrapParseMethod(self, method, *args, **kwargs):
-        """A helper evaluator method.  Try the specified parse method with
+        """A helper evaluator method that try the specified parse method with
         each registered structure parser and return the first successful
-        resul.  Structure parsers that match structure file extension are
+        resul.
+
+        Structure parsers that match structure file extension are
         tried first.
 
-        Set format attribute to the detected file format.
-        Return Structure instance, or raise StructureFormatError.
+        Parameters
+        ----------
+        method : str
+            Name of the parse method to call.
+        *args : tuple
+            Positional arguments for the parse method.
+        **kwargs : dict
+            Keyword arguments for the parse method.
+
+        Returns
+        -------
+        Structure
+            `Structure` object.
+
+        Raises
+        ------
+        StructureFormatError
         """
         from diffpy.structure.parsers import getParser
 
@@ -131,4 +202,16 @@ def _wrapParseMethod(self, method, *args, **kwargs):
 
 
 def getParser(**kw):
+    """Return a new instance of the automatic parser.
+
+    Parameters
+    ----------
+    **kw : dict
+        Keyword arguments for the structure parser
+
+    Returns
+    -------
+    P_auto
+        Instance of `P_auto`.
+    """
     return P_auto(**kw)
diff --git a/src/diffpy/structure/parsers/p_cif.py b/src/diffpy/structure/parsers/p_cif.py
index bac14f55..6fba3b44 100644
--- a/src/diffpy/structure/parsers/p_cif.py
+++ b/src/diffpy/structure/parsers/p_cif.py
@@ -13,17 +13,26 @@
 #
 ##############################################################################
 
-"""Parser for basic CIF file format
-
-http://www.iucr.org/iucr-top/cif/home.html
+"""Parser for basic CIF file format.
+
+Attributes
+----------
+rx_float : re.Pattern
+    Constant regular expression for `leading_float()`.
+symvec : dict
+    Helper dictionary for `getSymOp()`.
+
+Note
+----
+References: https://www.iucr.org/resources/cif
 """
 
+import io
 import re
 import sys
 from contextlib import contextmanager
 
 import numpy
-import six
 
 from diffpy.structure import Atom, Lattice, Structure
 from diffpy.structure.parsers import StructureParser
@@ -34,31 +43,44 @@
 
 class P_cif(StructureParser):
     """Simple parser for CIF structure format.
+
     Reads Structure from the first block containing _atom_site_label key.
-    Following blocks, if any are ignored.
-
-    Data members:
-
-    format      -- structure format name
-    ciffile     -- instance of CifFile from PyCifRW
-    stru        -- Structure instance used for cif input or output
-
-    Data members used for input only:
-
-    spacegroup  -- instance of SpaceGroup used for symmetry expansion
-    eps         -- resolution in fractional coordinates for non-equal
-                   positions.  Use for expansion of asymmetric unit.
-    eau         -- instance of ExpandAsymmetricUnit from SymmetryUtilities
-    asymmetric_unit -- list of atom instances for the original asymmetric
-                   unit in the CIF file
-    labelindex  -- dictionary mapping unique atom label to index of atom
-                   in self.asymmetric_unit
-    anisotropy  -- dictionary mapping unique atom label to displacement
-                   anisotropy resolved at that site
-    cif_sgname  -- space group name obtained by looking up the value of
-                   _space_group_name_Hall, _symmetry_space_group_name_Hall,
-                   _space_group_name_H-M_alt, _symmetry_space_group_name_H-M
-                   items.  None when neither is defined.
+    Following blocks, if any, are ignored.
+
+    Parameters
+    ----------
+    eps : float, Optional
+        Fractional coordinates cutoff for duplicate positions.
+        When ``None`` use the default for `ExpandAsymmetricUnit`: ``1.0e-5``.
+
+    Attributes
+    ----------
+    format : str
+        Structure format name.
+    ciffile : CifFile
+        Instance of `CifFile` from `PyCifRW`.
+    stru : Structure
+        `Structure` instance used for CIF input or output.
+    spacegroup : SpaceGroup
+        Instance of `SpaceGroup` used for symmetry expansion.
+    eps : float
+        Resolution in fractional coordinates for non-equal positions.
+        Used for expansion of asymmetric unit.
+    eau : ExpandAsymmetricUnit
+        Instance of `ExpandAsymmetricUnit` from `SymmetryUtilities`.
+    asymmetric_unit : list
+        List of `Atom` instances for the original asymmetric unit in the CIF file.
+    labelindex : dict
+        Dictionary mapping unique atom label to index of `Atom` in `self.asymmetric_unit`.
+    anisotropy : dict
+        Dictionary mapping unique atom label to displacement anisotropy resolved at that site.
+    cif_sgname : str or None
+        Space group name obtained by looking up the value of
+        `_space_group_name_Hall`,
+        `_symmetry_space_group_name_Hall`,
+        `_space_group_name_H-M_alt`,
+        `_symmetry_space_group_name_H-M`
+        items. ``None`` when neither is defined.
     """
 
     # static data and methods ------------------------------------------------
@@ -66,6 +88,11 @@ class P_cif(StructureParser):
     # dictionary set of class methods for translating CIF values
     # to Atom attributes
 
+    # static data and methods ------------------------------------------------
+
+    # dictionary set of class methods for translating CIF values
+    # to Atom attributes
+
     _atom_setters = dict.fromkeys(
         (
             "_tr_ignore",
@@ -102,6 +129,7 @@ class P_cif(StructureParser):
     del k
 
     BtoU = 1.0 / (8 * numpy.pi**2)
+    """float: Conversion factor from B values to U values."""
 
     def _tr_ignore(a, value):
         return
@@ -239,12 +267,17 @@ def _tr_atom_site_aniso_B_23(a, value):
     _tr_atom_site_aniso_B_23 = staticmethod(_tr_atom_site_aniso_B_23)
 
     def _get_atom_setters(cifloop):
-        """Find translators of CifLoop items to data in Atom instance.
-        Static method.
+        """Static method for finding translators of CifLoop items to data in `Atom` instance.
 
-        cifloop -- instance of CifLoop
+        Parameters
+        ----------
+        cifloop : CifLoop
+            Instance of `CifLoop`.
 
-        Return a list of setter functions in the order of cifloop.keys().
+        Returns
+        -------
+        list
+            List of setter functions in the order of `cifloop.keys()`.
         """
         rv = []
         for p in cifloop.keys():
@@ -259,11 +292,6 @@ def _get_atom_setters(cifloop):
     # normal methods ---------------------------------------------------------
 
     def __init__(self, eps=None):
-        """Initialize the parser for CIF structure files.
-
-        eps  -- fractional coordinates cutoff for duplicate positions.
-                When None use the default for ExpandAsymmetricUnit.
-        """
         StructureParser.__init__(self)
         self.format = "cif"
         self.ciffile = None
@@ -278,22 +306,46 @@ def __init__(self, eps=None):
         pass
 
     def parse(self, s):
-        """Create Structure instance from a string in CIF format.
+        """Create `Structure` instance from a string in CIF format.
+
+        Parameters
+        ----------
+        s : str
+            A string in CIF format.
 
-        Return Structure instance or raise StructureFormatError.
+        Returns
+        -------
+        Structure
+            `Structure` instance.
+
+        Raises
+        ------
+        StructureFormatError
+            When the data do not constitute a valid CIF format.
         """
         self.ciffile = None
         self.filename = ""
-        fp = six.StringIO(s)
+        fp = io.StringIO(s)
         rv = self._parseCifDataSource(fp)
         return rv
 
     def parseLines(self, lines):
         """Parse list of lines in CIF format.
 
-        lines -- list of strings stripped of line terminator
+        Parameters
+        ----------
+        lines : list
+            List of strings stripped of line terminator.
+
+        Returns
+        -------
+        Structure
+            `Structure` instance.
 
-        Return Structure instance or raise StructureFormatError.
+        Raises
+        ------
+        StructureFormatError
+            When the data do not constitute a valid CIF format.
         """
         s = "\n".join(lines) + "\n"
         return self.parse(s)
@@ -301,10 +353,22 @@ def parseLines(self, lines):
     def parseFile(self, filename):
         """Create Structure from an existing CIF file.
 
-        filename  -- path to structure file
+        Parameters
+        ----------
+        filename : str
+            Path to structure file.
 
-        Return Structure object.
-        Raise StructureFormatError or IOError.
+        Returns
+        -------
+        Structure
+            `Structure` instance.
+
+        Raises
+        ------
+        StructureFormatError
+            When the data do not constitute a valid CIF format.
+        IOError
+            When the file cannot be opened.
         """
         self.ciffile = None
         self.filename = filename
@@ -313,20 +377,18 @@ def parseFile(self, filename):
         return rv
 
     def _parseCifDataSource(self, datasource):
-        """\
-        Open and process CIF data from the specified `datasource`.
-
+        """Open and process CIF data from the specified `datasource`.
 
         Parameters
         ----------
         datasource : str or a file-like object
-            This is used as an argument to the CifFile class.  The CifFile
+            This is used as an argument to the `CifFile` class. The `CifFile`
             instance is stored in `ciffile` attribute of this Parser.
 
         Returns
         -------
         Structure
-            The Structure object loaded from the specified data source.
+            The `Structure` object loaded from the specified data source.
 
         Raises
         ------
@@ -350,16 +412,17 @@ def _parseCifDataSource(self, datasource):
             exc_type, exc_value, exc_traceback = sys.exc_info()
             emsg = str(err).strip()
             e = StructureFormatError(emsg)
-            six.reraise(StructureFormatError, e, exc_traceback)
+            raise e.with_traceback(exc_traceback)
         return self.stru
 
     def _parseCifBlock(self, blockname):
-        """Translate CIF file block, skip blocks without _atom_site_label.
-        Updates data members stru, eau.
-
-        blockname  -- name of top level block in self.ciffile
+        """Translate CIF file block, skip blocks without `_atom_site_label`.
+        Updates data members `stru`, `eau`.
 
-        No return value.
+        Parameters
+        ----------
+        blockname : str
+            Name of top level block in `self.ciffile`.
         """
         block = self.ciffile[blockname]
         if "_atom_site_label" not in block:
@@ -376,12 +439,14 @@ def _parseCifBlock(self, blockname):
         return
 
     def _parse_lattice(self, block):
-        """Obtain lattice parameters from a CifBlock.
-        This method updates self.stru.lattice.
+        """Obtain `lattice` parameters from a `CifBlock`.
 
-        block -- instance of CifBlock
+        This method updates `self.stru.lattic`e.
 
-        No return value.
+        Parameters
+        ----------
+        block : CifBlock
+            Instance of CifBlock.
         """
         if "_cell_length_a" not in block:
             return
@@ -399,18 +464,20 @@ def _parse_lattice(self, block):
             exc_type, exc_value, exc_traceback = sys.exc_info()
             emsg = str(err)
             e = StructureFormatError(emsg)
-            six.reraise(StructureFormatError, e, exc_traceback)
+            raise e.with_traceback(exc_traceback)
         self.stru.lattice = Lattice(*latpars)
         return
 
     def _parse_atom_site_label(self, block):
-        """Obtain atoms in asymmetric unit from a CifBlock.
-        This method inserts Atom instances to self.stru and
-        updates labelindex dictionary.
+        """Obtain atoms in asymmetric unit from a `CifBlock`.
 
-        block -- instance of CifBlock
+        This method inserts `Atom` instances to `self.stru` and
+        updates `labelindex` dictionary.
 
-        No return value.
+        Parameters
+        ----------
+        block : CifBlock
+            Instance of `CifBlock`.
         """
         # process _atom_site_label
         atom_site_loop = block.GetLoop("_atom_site_label")
@@ -438,13 +505,15 @@ def _parse_atom_site_label(self, block):
         return
 
     def _parse_atom_site_aniso_label(self, block):
-        """Obtain value of anisotropic thermal displacements from a CifBlock.
-        This method updates U members of Atom instances in self.stru.
-        The labelindex dictionary has to be defined beforehand.
+        """Obtain value of anisotropic thermal displacements from a `CifBlock`.
 
-        block -- instance of CifBlock
+        This method updates `U` members of `Atom` instances in `self.stru`.
+        The `labelindex` dictionary has to be defined beforehand.
 
-        No return value.
+        Parameters
+        ----------
+        block : CifBlock
+            Instance of `CifBlock`.
         """
         if "_atom_site_aniso_label" not in block:
             return
@@ -469,14 +538,16 @@ def _parse_atom_site_aniso_label(self, block):
         return
 
     def _parse_space_group_symop_operation_xyz(self, block):
-        """Process symmetry operations from a CifBlock.  The method
-        updates spacegroup and eau data according to symmetry
-        operations defined in _space_group_symop_operation_xyz or
-        _symmetry_equiv_pos_as_xyz items in CifBlock.
+        """Process symmetry operations from a CifBlock.
 
-        block -- instance of CifBlock
+        The method updates `spacegroup` and `eau` data according to symmetry
+        operations defined in `_space_group_symop_operation_xyz` or
+        `_symmetry_equiv_pos_as_xyz` items in `CifBlock`.
 
-        No return value.
+        Parameters
+        ----------
+        block : CifBlock
+            Instance of `CifBlock`.
         """
         from diffpy.structure.spacegroups import FindSpaceGroup, GetSpaceGroup, IsSpaceGroupIdentifier, SpaceGroup
 
@@ -528,9 +599,9 @@ def _parse_space_group_symop_operation_xyz(self, block):
         return
 
     def _expandAsymmetricUnit(self, block):
-        """Perform symmetry expansion of self.stru using self.spacegroup.
+        """Perform symmetry expansion of `self.stru` using `self.spacegroup`.
 
-        This method updates data in stru and eau.
+        This method updates data in `stru` and `eau`.
 
         Parameters
         ----------
@@ -568,9 +639,17 @@ def _expandAsymmetricUnit(self, block):
     # conversion to CIF ------------------------------------------------------
 
     def toLines(self, stru):
-        """Convert Structure stru to a list of lines in basic CIF format.
+        """Convert `Structure` to a list of lines in basic CIF format.
+
+        Parameters
+        ----------
+        stru : Structure
+            The structure to be converted.
 
-        Return list of strings.
+        Returns
+        -------
+        list
+            List of lines in basic CIF format.
         """
         import time
 
@@ -692,7 +771,7 @@ def leading_float(s, d=0.0):
     ----------
     s : str
         The string to be scanned for floating point value.
-    d : float, optional
+    d : float, Optional
         The default value when `s` is "." or "?", which in CIF
         format stands for inapplicable and unknown, respectively.
 
@@ -733,11 +812,17 @@ def leading_float(s, d=0.0):
 
 
 def getSymOp(s):
-    """Create SpaceGroups.SymOp instance from a string.
+    """Create `SpaceGroups.SymOp` instance from a string.
 
-    s   -- formula for equivalent coordinates, for example 'x,1/2-y,1/2+z'
+    Parameters
+    ----------
+    s : str
+        Formula for equivalent coordinates, for example ``'x,1/2-y,1/2+z'``.
 
-    Return instance of SymOp.
+    Returns
+    -------
+    SymOp
+        Instance of `SymOp`.
     """
     from diffpy.structure.spacegroups import SymOp
 
@@ -757,10 +842,18 @@ def getSymOp(s):
 
 
 def getParser(eps=None):
-    """Return new parser object for CIF structure format.
+    """Return new `parser` object for CIF format.
+
+    Parameters
+    ----------
+    eps : float, Optional
+        fractional coordinates cutoff for duplicate positions.
+        When ``None`` use the default for `ExpandAsymmetricUnit`: ``1.0e-5``.
 
-    eps  -- fractional coordinates cutoff for duplicate positions.
-            When None use the default for ExpandAsymmetricUnit.
+    Returns
+    -------
+    P_cif
+        Instance of `P_cif`.
     """
     return P_cif(eps=eps)
 
@@ -770,9 +863,7 @@ def getParser(eps=None):
 
 @contextmanager
 def _suppressCifParserOutput():
-    """\
-    Context manager which suppresses diagnostic messages from CIF parser.
-    """
+    """Context manager which suppresses diagnostic messages from CIF parser."""
     from CifFile import yapps3_compiled_rt
 
     print_error = yapps3_compiled_rt.print_error
diff --git a/src/diffpy/structure/parsers/p_discus.py b/src/diffpy/structure/parsers/p_discus.py
index 101801be..3ee7e5fd 100644
--- a/src/diffpy/structure/parsers/p_discus.py
+++ b/src/diffpy/structure/parsers/p_discus.py
@@ -19,16 +19,33 @@
 import sys
 from functools import reduce
 
-import six
-
 from diffpy.structure import Lattice, PDFFitStructure
 from diffpy.structure.parsers import StructureParser
 from diffpy.structure.structureerrors import StructureFormatError
 
 
 class P_discus(StructureParser):
-    """Parser for DISCUS structure format.  The parser chokes
+    """Parser for DISCUS structure format. The parser chokes
     on molecule and generator records.
+
+    Attributes
+    ----------
+    format : str
+        File format name, default "discus".
+    nl : int
+        Line number of the current line being parsed.
+    lines : list of str
+        List of lines from the input file.
+    line : str
+        Current line being parsed.
+    stru : PDFFitStructure
+        Structure being parsed.
+    ignored_lines : list of str
+        List of lines that were ignored during parsing.
+    cell_read : bool
+        ``True`` if cell record processed.
+    ncell_read : bool
+        ``True`` if ncell record processed.
     """
 
     def __init__(self):
@@ -47,7 +64,20 @@ def __init__(self):
     def parseLines(self, lines):
         """Parse list of lines in DISCUS format.
 
-        Return PDFFitStructure instance or raise StructureFormatError.
+        Parameters
+        ----------
+        lines : list of str
+            List of lines from the input file.
+
+        Returns
+        -------
+        PDFFitStructure
+            Parsed `PDFFitStructure` instance.
+
+        Raises
+        ------
+        StructureFormatError
+            If the file is not in DISCUS format.
         """
         self.lines = lines
         ilines = self._linesIterator()
@@ -100,12 +130,21 @@ def parseLines(self, lines):
             exc_type, exc_value, exc_traceback = sys.exc_info()
             emsg = "%d: file is not in DISCUS format" % self.nl
             e = StructureFormatError(emsg)
-            six.reraise(StructureFormatError, e, exc_traceback)
+            raise e.with_traceback(exc_traceback)
         return self.stru
 
     def toLines(self, stru):
-        """Convert Structure stru to a list of lines in DISCUS format.
-        Return list of strings.
+        """Convert `Structure` stru to a list of lines in DISCUS format.
+
+        Parameters
+        ----------
+        stru : Structure
+            Structure to be converted.
+
+        Returns
+        -------
+        list of str
+            List of lines in DISCUS format.
         """
         self.stru = stru
         # if necessary, convert self.stru to PDFFitStructure
@@ -136,7 +175,7 @@ def toLines(self, stru):
         return lines
 
     def _linesIterator(self):
-        """Iterator over self.lines, which increments self.nl"""
+        """Iterator over `self.lines`, which increments `self.nl`"""
         # ignore trailing empty lines
         stop = len(self.lines)
         while stop > 0 and self.lines[stop - 1].strip() == "":
@@ -187,7 +226,18 @@ def _parse_title(self, words):
         return
 
     def _parse_shape(self, words):
-        """Process the shape record from DISCUS structure file."""
+        """Process the shape record from DISCUS structure file.
+
+        Parameters
+        ----------
+        words : list of str
+            List of words in the line.
+
+        Raises
+        ------
+        StructureFormatError
+            Invalid type of particle shape correction.
+        """
         # strip away any commas
         linefixed = " ".join(words).replace(",", " ")
         wordsfixed = linefixed.split()
@@ -213,15 +263,34 @@ def _parse_atom(self, words):
 
     def _parse_unknown_record(self, words):
         """Process unknown record in DISCUS structure file.
-        Silently ignores the line and adds it to self.ignored_lines
-        Raises StructureFormatError.
+
+        Silently ignores the line and adds it to `self.ignored_lines`.
+
+        Parameters
+        ----------
+        words : list of str
+            List of words in the line.
+
+        Raises
+        ------
+        StructureFormatError
+            Unkown record.
         """
         self.ignored_lines.append(self.line)
         return
 
     def _parse_not_implemented(self, words):
         """Process the unimplemented records from DISCUS structure file.
-        Raises NotImplementedError.
+
+        Parameters
+        ----------
+        words : list of str
+            List of words in the line.
+
+        Raises
+        ------
+        NotImplementedError
+            If the record is not implemented.
         """
         emsg = "%d: reading of DISCUS record %r is not implemented." % (self.nl, words[0])
         raise NotImplementedError(emsg)
@@ -233,4 +302,11 @@ def _parse_not_implemented(self, words):
 
 
 def getParser():
+    """Return new `parser` object for DISCUS format.
+
+    Returns
+    -------
+    P_discus
+        Instance of `P_discus`.
+    """
     return P_discus()
diff --git a/src/diffpy/structure/parsers/p_pdb.py b/src/diffpy/structure/parsers/p_pdb.py
index 11ff9a43..6d0f95aa 100644
--- a/src/diffpy/structure/parsers/p_pdb.py
+++ b/src/diffpy/structure/parsers/p_pdb.py
@@ -15,16 +15,16 @@
 
 """Basic parser for PDB structure format.
 
-References
-
-    http://www.wwpdb.org/documentation/format23/v2.3.html
-    http://www.wwpdb.org/documentation/format30/index.html
+Note
+----
+References:
+    https://www.wwpdb.org/documentation/file-format-content/format23/v2.3.html
+    https://www.wwpdb.org/documentation/file-format-content/format30/index.html
 """
 
 import sys
 
 import numpy
-import six
 from numpy import pi
 
 from diffpy.structure import Structure
@@ -34,13 +34,14 @@
 
 class P_pdb(StructureParser):
     """Simple parser for PDB format.
-    The parser understands following PDB records: TITLE, CRYST1, SCALE1,
-    SCALE2, SCALE3, ATOM, SIGATM, ANISOU, SIGUIJ, TER, HETATM, END
 
-    Static data members:
+    The parser understands following PDB records: `TITLE, CRYST1, SCALE1,
+    SCALE2, SCALE3, ATOM, SIGATM, ANISOU, SIGUIJ, TER, HETATM, END`.
 
-    orderOfRecords -- order of PDB record labels
-    validRecords   -- dictionary of valid PDB records
+    Attributes
+    ----------
+    format : str
+        Format name, default "pdb".
     """
 
     # Static data members
@@ -101,7 +102,10 @@ class P_pdb(StructureParser):
         "MASTER",
         "END",
     ]
+    """list: Ordered list of PDB record labels."""
+
     validRecords = dict.fromkeys(orderOfRecords)
+    """dict: Dictionary of PDB record labels."""
 
     def __init__(self):
         StructureParser.__init__(self)
@@ -111,7 +115,20 @@ def __init__(self):
     def parseLines(self, lines):
         """Parse list of lines in PDB format.
 
-        Return Structure instance or raise StructureFormatError.
+        Parameters
+        ----------
+        lines : list of str
+            List of lines in PDB format.
+
+        Returns
+        -------
+        Structure
+            Parsed structure instance.
+
+        Raises
+        ------
+        StructureFormatError
+            Invalid PDB record.
         """
         try:
             stru = Structure()
@@ -225,11 +242,11 @@ def parseLines(self, lines):
             emsg = "%d: invalid PDB record" % p_nl
             exc_type, exc_value, exc_traceback = sys.exc_info()
             e = StructureFormatError(emsg)
-            six.reraise(StructureFormatError, e, exc_traceback)
+            raise e.with_traceback(exc_traceback)
         return stru
 
     def titleLines(self, stru):
-        """build lines corresponding to TITLE record"""
+        """Build lines corresponding to `TITLE` record."""
         lines = []
         title = stru.title
         while title != "":
@@ -248,7 +265,7 @@ def titleLines(self, stru):
         return lines
 
     def cryst1Lines(self, stru):
-        """build lines corresponding to CRYST1 record"""
+        """Build lines corresponding to `CRYST1` record."""
         lines = []
         latpar = (
             stru.lattice.a,
@@ -264,8 +281,8 @@ def cryst1Lines(self, stru):
         return lines
 
     def atomLines(self, stru, idx):
-        """build ATOM records and possibly SIGATM, ANISOU or SIGUIJ records
-        for structure stru atom number aidx
+        """Build `ATOM` records and possibly `SIGATM`, `ANISOU` or `SIGUIJ` records
+        for `structure` stru `atom` number aidx.
         """
         lines = []
         a = stru[idx]
@@ -341,9 +358,17 @@ def atomLines(self, stru, idx):
         return lines
 
     def toLines(self, stru):
-        """Convert Structure stru to a list of lines in PDFFit format.
+        """Convert `Structure` stru to a list of lines in PDB format.
 
-        Return list of strings.
+        Parameters
+        ----------
+        stru : Structure
+            Structure to be converted.
+
+        Returns
+        -------
+        list of str
+            List of lines in PDB format.
         """
         lines = []
         lines.extend(self.titleLines(stru))
@@ -370,4 +395,11 @@ def toLines(self, stru):
 
 
 def getParser():
+    """Return new `parser` object for PDB format.
+
+    Returns
+    -------
+    P_pdb
+        Instance of `P_pdb`.
+    """
     return P_pdb()
diff --git a/src/diffpy/structure/parsers/p_pdffit.py b/src/diffpy/structure/parsers/p_pdffit.py
index 659851e0..692c417f 100644
--- a/src/diffpy/structure/parsers/p_pdffit.py
+++ b/src/diffpy/structure/parsers/p_pdffit.py
@@ -20,7 +20,6 @@
 from functools import reduce
 
 import numpy
-import six
 
 from diffpy.structure import Lattice, PDFFitStructure
 from diffpy.structure.parsers import StructureParser
@@ -30,7 +29,14 @@
 class P_pdffit(StructureParser):
     """Parser for PDFfit structure format.
 
-    stru -- Structure instance used for cif input or output
+    Attributes
+    ----------
+    format : str
+        Format name, default "pdffit".
+    ignored_lines : list
+        List of lines ignored during parsing.
+    stru : PDFFitStructure
+        Structure instance used for cif input or output.
     """
 
     def __init__(self):
@@ -43,7 +49,20 @@ def __init__(self):
     def parseLines(self, lines):
         """Parse list of lines in PDFfit format.
 
-        Return Structure object or raise StructureFormatError.
+        Parameters
+        ----------
+        lines : list of str
+            List of lines in PDB format.
+
+        Returns
+        -------
+        Structure
+            Parsed structure instance.
+
+        Raises
+        ------
+        StructureFormatError
+            File not in PDFfit format.
         """
         p_nl = 0
         try:
@@ -158,13 +177,21 @@ def parseLines(self, lines):
             emsg = "%d: file is not in PDFfit format" % p_nl
             exc_type, exc_value, exc_traceback = sys.exc_info()
             e = StructureFormatError(emsg)
-            six.reraise(StructureFormatError, e, exc_traceback)
+            raise e.with_traceback(exc_traceback)
         return stru
 
     def toLines(self, stru):
-        """Convert Structure stru to a list of lines in PDFfit format.
+        """Convert `Structure` stru to a list of lines in PDFfit format.
+
+        Parameters
+        ----------
+        stru : Structure
+            Structure to be converted.
 
-        Return list of strings.
+        Returns
+        -------
+        list of str
+            List of lines in PDFfit format.
         """
         # build the stru_pdffit dictionary initialized from the defaults
         # in PDFFitStructure
@@ -221,12 +248,17 @@ def toLines(self, stru):
     # Protected methods ------------------------------------------------------
 
     def _parse_shape(self, line):
-        """Process shape line from PDFfit file and update self.stru
+        """Process shape line from PDFfit file and update self.stru.
 
-        line -- line containing data for particle shape correction
+        Parameters
+        ----------
+        line : str
+            Line containing data for particle shape correction.
 
-        No return value.
-        Raise StructureFormatError for invalid record.
+        Raises
+        ------
+        StructureFormatError
+            Invalid type of particle shape correction.
         """
         line_nocommas = line.replace(",", " ")
         words = line_nocommas.split()
@@ -248,4 +280,11 @@ def _parse_shape(self, line):
 
 
 def getParser():
+    """Return new `parser` object for PDFfit format.
+
+    Returns
+    -------
+    P_pdffit
+        Instance of `P_pdffit`.
+    """
     return P_pdffit()
diff --git a/src/diffpy/structure/parsers/p_rawxyz.py b/src/diffpy/structure/parsers/p_rawxyz.py
index ee199cca..65e9588e 100644
--- a/src/diffpy/structure/parsers/p_rawxyz.py
+++ b/src/diffpy/structure/parsers/p_rawxyz.py
@@ -13,15 +13,14 @@
 #
 ##############################################################################
 
-"""Parser for raw XYZ file format.  Raw XYZ is a 3 or 4 column text
-file with cartesian coordinates of atoms and an optional first column
-for atom types.
+"""Parser for raw XYZ file format.
+
+Raw XYZ is a 3 or 4 column text file with cartesian coordinates
+of atoms and an optional first column for atom types.
 """
 
 import sys
 
-import six
-
 from diffpy.structure import Structure
 from diffpy.structure.parsers import StructureParser
 from diffpy.structure.structureerrors import StructureFormatError
@@ -29,7 +28,13 @@
 
 
 class P_rawxyz(StructureParser):
-    """Parser --> StructureParser subclass for RAWXYZ format"""
+    """Parser --> StructureParser subclass for RAWXYZ format.
+
+    Attributes
+    ----------
+    format : str
+        Format name, default "rawxyz".
+    """
 
     def __init__(self):
         StructureParser.__init__(self)
@@ -39,7 +44,20 @@ def __init__(self):
     def parseLines(self, lines):
         """Parse list of lines in RAWXYZ format.
 
-        Return Structure object or raise StructureFormatError.
+        Parameters
+        ----------
+        lines : list of str
+            List of lines in RAWXYZ format.
+
+        Returns
+        -------
+        Structure
+            Parsed structure instance.
+
+        Raises
+        ------
+        StructureFormatError
+            Invalid RAWXYZ format.
         """
         linefields = [line.split() for line in lines]
         # prepare output structure
@@ -91,13 +109,21 @@ def parseLines(self, lines):
             emsg = "%d: invalid number" % p_nl
             exc_type, exc_value, exc_traceback = sys.exc_info()
             e = StructureFormatError(emsg)
-            six.reraise(StructureFormatError, e, exc_traceback)
+            raise e.with_traceback(exc_traceback)
         return stru
 
     def toLines(self, stru):
-        """Convert Structure stru to a list of lines in XYZ format.
+        """Convert Structure stru to a list of lines in RAWXYZ format.
+
+        Parameters
+        ----------
+        stru : Structure
+            Structure to be converted.
 
-        Return list of strings.
+        Returns
+        -------
+        list of str
+            List of lines in RAWXYZ format.
         """
         lines = []
         for a in stru:
@@ -113,4 +139,11 @@ def toLines(self, stru):
 
 
 def getParser():
+    """Return new `parser` object for RAWXYZ format.
+
+    Returns
+    -------
+    P_rawxyz
+        Instance of `P_rawxyz`.
+    """
     return P_rawxyz()
diff --git a/src/diffpy/structure/parsers/p_xcfg.py b/src/diffpy/structure/parsers/p_xcfg.py
index bbf44e83..372e7ba8 100644
--- a/src/diffpy/structure/parsers/p_xcfg.py
+++ b/src/diffpy/structure/parsers/p_xcfg.py
@@ -13,13 +13,18 @@
 #
 ##############################################################################
 
-"""Parser for extended CFG format used by atomeye"""
+"""Parser for extended CFG format used by atomeye.
+
+Attributes
+----------
+AtomicMass : dict
+    Dictionary of atomic masses for elements.
+"""
 
 import re
 import sys
 
 import numpy
-import six
 
 from diffpy.structure import Structure
 from diffpy.structure.parsers import StructureParser
@@ -151,11 +156,16 @@
 class P_xcfg(StructureParser):
     """Parser for AtomEye extended CFG format.
 
-    cluster_boundary -- width of boundary around corners of non-periodic
-                        cluster to avoid PBC effects in atomeye
+    Attributes
+    ----------
+    format : str
+        Format name, default "xcfg".
     """
 
     cluster_boundary = 2
+    """int: Width of boundary around corners of non-periodic
+    cluster to avoid PBC effects in atomeye.
+    """
 
     def __init__(self):
         StructureParser.__init__(self)
@@ -163,9 +173,22 @@ def __init__(self):
         return
 
     def parseLines(self, lines):
-        """Parse list of lines in PDB format.
+        """Parse list of lines in XCFG format.
+
+        Parameters
+        ----------
+        lines : list of str
+            List of lines in XCFG format.
+
+        Returns
+        -------
+        Structure
+            Parsed structure instance.
 
-        Return Structure object or raise StructureFormatError.
+        Raises
+        ------
+        StructureFormatError
+            Invalid XCFG format.
         """
         xcfg_Number_of_particles = None
         xcfg_A = None
@@ -260,13 +283,26 @@ def parseLines(self, lines):
             emsg = "%d: file is not in XCFG format" % p_nl
             exc_type, exc_value, exc_traceback = sys.exc_info()
             e = StructureFormatError(emsg)
-            six.reraise(StructureFormatError, e, exc_traceback)
+            raise e.with_traceback(exc_traceback)
         return stru
 
     def toLines(self, stru):
         """Convert Structure stru to a list of lines in XCFG atomeye format.
 
-        Return list of strings.
+        Parameters
+        ----------
+        stru : Structure
+            Structure to be converted.
+
+        Returns
+        -------
+        list of str
+            List of lines in XCFG format.
+
+        Raises
+        ------
+        StructureFormatError
+            Cannot convert empty structure to XCFG format.
         """
         if len(stru) == 0:
             emsg = "cannot convert empty structure to XCFG format"
@@ -374,6 +410,13 @@ def toLines(self, stru):
 
 
 def getParser():
+    """Return new `parser` object for XCFG format.
+
+    Returns
+    -------
+    P_xcfg
+        Instance of `P_xcfg`.
+    """
     return P_xcfg()
 
 
@@ -381,13 +424,12 @@ def getParser():
 
 
 def _assign_auxiliaries(a, fields, auxiliaries, no_velocity):
-    """\
-    Assing auxiliary properties for Atom object when reading CFG format.
+    """Assing auxiliary properties for `Atom` object when reading CFG format.
 
     Parameters
     ----------
     a : Atom
-        The Atom instance for which the auxiliary properties need to be set.
+        The `Atom` instance for which the auxiliary properties need to be set.
     fields : list
         Floating point values for the current row of the processed CFG file.
     auxiliaries : dict
@@ -396,8 +438,6 @@ def _assign_auxiliaries(a, fields, auxiliaries, no_velocity):
     no_velocity : bool
         When `False` set atom velocity `a.v` to `fields[3:6]`.
         Use `fields[3:6]` for auxiliary values otherwise.
-
-    No return value.
     """
     if not no_velocity:
         a.v = numpy.asarray(fields[3:6], dtype=float)
diff --git a/src/diffpy/structure/parsers/p_xyz.py b/src/diffpy/structure/parsers/p_xyz.py
index 2985aa7a..cd540a90 100644
--- a/src/diffpy/structure/parsers/p_xyz.py
+++ b/src/diffpy/structure/parsers/p_xyz.py
@@ -14,22 +14,27 @@
 ##############################################################################
 
 """Parser for XYZ file format, where
-first line gives number of atoms
-second one has optional title
-remaining lines contain element, x, y, z
+
+    * First line gives number of atoms.
+    * Second line has optional title.
+    * Remaining lines contain element, `x, y, z`.
 """
 
 import sys
 
-import six
-
 from diffpy.structure import Structure
 from diffpy.structure.parsers import StructureParser
 from diffpy.structure.structureerrors import StructureFormatError
 
 
 class P_xyz(StructureParser):
-    """Parser for standard XYZ structure format."""
+    """Parser for standard XYZ structure format.
+
+    Attributes
+    ----------
+    format : str
+        Format name, default "xyz".
+    """
 
     def __init__(self):
         StructureParser.__init__(self)
@@ -39,7 +44,20 @@ def __init__(self):
     def parseLines(self, lines):
         """Parse list of lines in XYZ format.
 
-        Return Structure object or raise StructureFormatError.
+        Parameters
+        ----------
+        lines : list of str
+            List of lines in XYZ format.
+
+        Returns
+        -------
+        Structure
+            Parsed structure instance.
+
+        Raises
+        ------
+        StructureFormatError
+            Invalid XYZ format.
         """
         linefields = [line.split() for line in lines]
         # prepare output structure
@@ -66,7 +84,7 @@ def parseLines(self, lines):
             exc_type, exc_value, exc_traceback = sys.exc_info()
             emsg = "%d: invalid XYZ format, missing number of atoms" % (start + 1)
             e = StructureFormatError(emsg)
-            six.reraise(StructureFormatError, e, exc_traceback)
+            raise e.with_traceback(exc_traceback)
         # find the last valid record
         stop = len(lines)
         while stop > start and len(linefields[stop - 1]) == 0:
@@ -97,7 +115,7 @@ def parseLines(self, lines):
             exc_type, exc_value, exc_traceback = sys.exc_info()
             emsg = "%d: invalid number format" % p_nl
             e = StructureFormatError(emsg)
-            six.reraise(StructureFormatError, e, exc_traceback)
+            raise e.with_traceback(exc_traceback)
         # finally check if all the atoms have been read
         if p_natoms is not None and len(stru) != p_natoms:
             emsg = "expected %d atoms, read %d" % (p_natoms, len(stru))
@@ -107,7 +125,15 @@ def parseLines(self, lines):
     def toLines(self, stru):
         """Convert Structure stru to a list of lines in XYZ format.
 
-        Return list of strings.
+        Parameters
+        ----------
+        stru : Structure
+            Structure to be converted.
+
+        Returns
+        -------
+        list of str
+            List of lines in XYZ format.
         """
         lines = []
         lines.append(str(len(stru)))
@@ -125,4 +151,11 @@ def toLines(self, stru):
 
 
 def getParser():
+    """Return new `parser` object for XYZ format.
+
+    Returns
+    -------
+    P_xcfg
+        Instance of `P_xyz`.
+    """
     return P_xyz()
diff --git a/src/diffpy/structure/parsers/parser_index_mod.py b/src/diffpy/structure/parsers/parser_index_mod.py
index 48314780..5bb6ba98 100644
--- a/src/diffpy/structure/parsers/parser_index_mod.py
+++ b/src/diffpy/structure/parsers/parser_index_mod.py
@@ -14,8 +14,30 @@
 ##############################################################################
 
 """Index of recognized structure formats, their IO capabilities and
-associated modules where they are defined.  Plugins for new structure
-formats need to be added to the parser_index dictionary in this module.
+associated modules where they are defined.
+
+Attributes
+----------
+parser_index : dict
+    Dictionary of recognized structure formats. The keys are format names
+    and the values are dictionaries with the following keys:
+
+    module : str
+        Name of the module that defines the parser class.
+    file_extension : str
+        File extension for the format, including the leading dot.
+    file_pattern : str
+        File pattern for the format, using '|' as separator for multiple
+        patterns.
+    has_input : bool
+        ``True`` if the parser can read the format.
+    has_output : bool
+        ``True`` if the parser can write the format.
+
+Note
+----
+Plugins for new structure formats need to be added to the parser_index
+dictionary in this module.
 """
 
 parser_index = {
diff --git a/src/diffpy/structure/parsers/structureparser.py b/src/diffpy/structure/parsers/structureparser.py
index 1637d86b..2b748664 100644
--- a/src/diffpy/structure/parsers/structureparser.py
+++ b/src/diffpy/structure/parsers/structureparser.py
@@ -20,9 +20,12 @@
 class StructureParser(object):
     """Base class for all structure parsers.
 
-    Data members:
-        format   -- format of particular parser
-        filename -- path to structure file that is read or written
+    Attributes
+    ----------
+    format : str
+        Format name of particular parser.
+    filename : str
+        Path to structure file that is read or written.
     """
 
     def __init__(self):
@@ -34,6 +37,9 @@ def parseLines(self, lines):
         """Create Structure instance from a list of lines.
 
         Return Structure object or raise StructureFormatError exception.
+
+        Note
+        ----
         This method has to be overloaded in derived class.
         """
         raise NotImplementedError("parseLines not defined for '%s' format" % self.format)
@@ -41,35 +47,29 @@ def parseLines(self, lines):
 
     def toLines(self, stru):
         """Convert Structure stru to a list of lines.
-        This method has to be overloaded in derived class.
 
         Return list of strings.
+
+        Note
+        ----
+        This method has to be overloaded in derived class.
         """
         raise NotImplementedError("toLines not defined for '%s' format" % self.format)
 
     def parse(self, s):
-        """Create Structure instance from a string.
-
-        Return Structure object or raise StructureFormatError exception.
-        """
+        """Create `Structure` instance from a string."""
         lines = s.rstrip("\r\n").split("\n")
         stru = self.parseLines(lines)
         return stru
 
     def tostring(self, stru):
-        """Convert Structure instance to a string."""
+        """Convert `Structure` instance to a string."""
         lines = self.toLines(stru)
         s = "\n".join(lines) + "\n"
         return s
 
     def parseFile(self, filename):
-        """Create Structure instance from an existing file.
-
-        filename  -- path to structure file
-
-        Return Structure object.
-        Raise StructureFormatError or IOError.
-        """
+        """Create Structure instance from an existing file."""
         self.filename = filename
         with open(filename) as fp:
             s = fp.read()
diff --git a/src/diffpy/structure/pdffitstructure.py b/src/diffpy/structure/pdffitstructure.py
index c2ed21a1..cc3b66d1 100644
--- a/src/diffpy/structure/pdffitstructure.py
+++ b/src/diffpy/structure/pdffitstructure.py
@@ -13,7 +13,7 @@
 #
 ##############################################################################
 
-"""definition of PDFFitStructure class derived from Structure
+"""Definition of PDFFitStructure class derived from Structure
 """
 
 
@@ -23,13 +23,20 @@
 
 
 class PDFFitStructure(Structure):
-    """PDFFitStructure --> Structure with extra pdffit member
+    """PDFFitStructure --> Structure with extra pdffit member.
 
-    Data members:
-        pdffit -- dictionary for storing following extra parameters from
-                  PDFFit structure files:
-                      'scale', 'delta1', 'delta2', 'sratio',
-                      'rcut', 'spcgr', 'dcell', 'ncell'
+    Parameters
+    ----------
+    *args, **kwargs :
+        See `Structure` class constructor.
+
+    Attributes
+    ----------
+    pdffit : dict
+        Dictionary for storing following extra parameters from
+        PDFFit structure files:
+            `'scale', 'delta1', 'delta2', 'sratio',
+            'rcut', 'spcgr', 'dcell', 'ncell'`
     """
 
     def __init__(self, *args, **kwargs):
@@ -49,11 +56,23 @@ def __init__(self, *args, **kwargs):
         return
 
     def read(self, filename, format="auto"):
-        """Same as Structure.read, but update spcgr value in
-        self.pdffit when parser can get spacegroup.
+        """Same as `Structure.read`, but update `spcgr` value in
+        `self.pdffit` when parser can get spacegroup.
+
+        See `Structure.read()` for more info.
+
+        Parameters
+        ----------
+        filename : str
+            File to be loaded.
+        format : str, Optional
+            All structure formats are defined in parsers submodule,
+            when ``format == 'auto'`` all parsers are tried one by one.
 
-        Return instance of StructureParser used to load the data.
-        See Structure.read() for more info.
+        Return
+        ------
+        StructureParser
+            Instance of StructureParser used to load the data.
         """
         p = Structure.read(self, filename, format)
         sg = getattr(p, "spacegroup", None)
@@ -62,11 +81,23 @@ def read(self, filename, format="auto"):
         return p
 
     def readStr(self, s, format="auto"):
-        """Same as Structure.readStr, but update spcgr value in
-        self.pdffit when parser can get spacegroup.
+        """Same as `Structure.readStr`, but update `spcgr` value in
+        `self.pdffit` when parser can get spacegroup.
+
+        See `Structure.readStr()` for more info.
+
+        Parameters
+        ----------
+        s : str
+            String with structure definition.
+        format : str, Optional
+            All structure formats are defined in parsers submodule. When ``format == 'auto'``,
+            all parsers are tried one by one.
 
-        Return instance of StructureParser used to load the data.
-        See Structure.readStr() for more info.
+        Return
+        ------
+        StructureParser
+            Instance of `StructureParser` used to load the data.
         """
         p = Structure.readStr(self, s, format)
         sg = getattr(p, "spacegroup", None)
diff --git a/src/diffpy/structure/sgtbxspacegroups.py b/src/diffpy/structure/sgtbxspacegroups.py
index 0b5c382a..0ba28fc2 100644
--- a/src/diffpy/structure/sgtbxspacegroups.py
+++ b/src/diffpy/structure/sgtbxspacegroups.py
@@ -13,11 +13,13 @@
 #
 ##############################################################################
 
-"""Extra space group representations generated using sgtbx module from cctbx.
-Import of this module extends the SpaceGroupList in the SpaceGroups module.
-Notable variables:
+"""Extra space group representations generated using `sgtbx` module from `cctbx`.
+Import of this module extends the `SpaceGroupList` in the `SpaceGroups` module.
 
-sgtbxSpaceGroupList -- list of space group instances defined in this module
+Attributes
+----------
+sgtbxSpaceGroupList : list
+    List of space group instances defined in this module.
 """
 
 
diff --git a/src/diffpy/structure/spacegroupmod.py b/src/diffpy/structure/spacegroupmod.py
index 091f305d..c31b7cae 100644
--- a/src/diffpy/structure/spacegroupmod.py
+++ b/src/diffpy/structure/spacegroupmod.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # Copyright 2002 by PyMMLib Development Group, http://pymmlib.sourceforge.net/
 # This code is part of the PyMMLib distribution and governed by
-# its license.  Please see the LICENSE_pymmlib file that should have been
+# its license. Please see the LICENSE_pymmlib file that should have been
 # included as part of this package.
 """Symmetry operations as functions on vectors or arrays.
 """
@@ -110,25 +110,24 @@
 
 
 class SymOp(object):
-    """
-    The transformation of coordinates to a symmetry-related position.
+    """The transformation of coordinates to a symmetry-related position.
 
     The SymOp operation involves rotation and translation in cell coordinates.
 
     Parameters
     ----------
-    R : ndarray
+    R : numpy.ndarray
         The 3x3 matrix of rotation for this symmetry operation.
-    t : ndarray
+    t : numpy.ndarray
         The vector of translation in this symmetry operation.
 
     Attributes
     ----------
-    R : ndarray
+    R : numpy.ndarray
         The 3x3 matrix of rotation pertaining to unit cell coordinates.
         This may be identity, simple rotation, improper rotation, mirror
-        or inversion.  The determinant of *R* is either +1 or -1.
-    t : ndarray
+        or inversion. The determinant of *R* is either +1 or -1.
+    t : numpy.ndarray
         The translation of cell coordinates applied after rotation *R*.
     """
 
@@ -149,18 +148,18 @@ def __call__(self, vec):
 
         Parameters
         ----------
-        vec : ndarray
+        vec : numpy.ndarray
             The initial position in fractional cell coordinates.
 
         Returns
         -------
-        ndarray
+        numpy.ndarray
             The transformed position after this symmetry operation.
         """
         return numpy.dot(self.R, vec) + self.t
 
     def __eq__(self, symop):
-        """Implement the ``(self == symop)`` test of equality.
+        """Implement the ``self == symop`` test of equality.
 
         Return ``True`` when *self* and *symop* difference is within
         tiny round-off errors.
@@ -211,9 +210,9 @@ class SpaceGroup(object):
     Attributes
     ----------
     number : int
-        A unique space group number.  This may be incremented by
+        A unique space group number. This may be incremented by
         several thousands to facilitate unique values for multiple
-        settings of the same space group.  Use ``number % 1000``
+        settings of the same space group. Use ``number % 1000``
         to get the standard space group number from International
         Tables.
     num_sym_equiv : int
@@ -225,7 +224,7 @@ class SpaceGroup(object):
     point_group_name : str
         The point group to which this space group belongs to.
     crystal_system : str
-        The crystal system of this space group.  The possible values are
+        The crystal system of this space group. The possible values are
         ``"TRICLINIC", "MONOCLINIC", "ORTHORHOMBIC", "TETRAGONAL",
         "TRIGONAL" "HEXAGONAL", "CUBIC"``.
     pdb_name : str
@@ -271,7 +270,7 @@ def iter_symops(self):
 
         Yields
         ------
-        `SymOp`
+        SymOp
             Generate all symmetry operations for this space group.
         """
         return iter(self.symop_list)
@@ -312,12 +311,12 @@ def iter_equivalent_positions(self, vec):
 
         Parameters
         ----------
-        vec : ndarray
+        vec : numpy.ndarray
             The initial position in fractional coordinates.
 
         Yields
         ------
-        ndarray
+        numpy.ndarray
             The symmetry equivalent positions in fractional coordinates.
             The positions may be duplicate or outside of the ``0 <= x < 1``
             unit cell bounds.
diff --git a/src/diffpy/structure/spacegroups.py b/src/diffpy/structure/spacegroups.py
index f0a2957d..414d56e5 100644
--- a/src/diffpy/structure/spacegroups.py
+++ b/src/diffpy/structure/spacegroups.py
@@ -14,12 +14,15 @@
 ##############################################################################
 
 """Space group classes and definitions from mmLib and sgtbx.
+
+Attributes
+----------
+SpaceGroupList : list
+    List of all spacegroup definitions.
 """
 
 import copy
-
-import six
-from six.moves import zip_longest
+from itertools import zip_longest
 
 from diffpy.structure.mmlibspacegroups import (
     mmLibSpaceGroupList,
@@ -645,18 +648,27 @@
 # Import SpaceGroup objects --------------------------------------------------
 
 
-# all spacegroup definitions
 SpaceGroupList = mmLibSpaceGroupList + sgtbxSpaceGroupList
 
 
 def GetSpaceGroup(sgid):
     """Returns the SpaceGroup instance for the given identifier.
 
-    sgid -- space group symbol, either short_name or pdb_name,
-            whatever it means in mmlib.  Can be also an integer.
+    Parameters
+    ----------
+    sgid : str, int
+        space group symbol, either `short_name` or `pdb_name`,
+        whatever it means in mmlib. Can be also an integer.
+
+    Returns
+    -------
+    SpaceGroup
+        The SpaceGroup object for the given identifier.
 
-    Return space group instance.
-    Raise ValueError when not found.
+    Raises
+    ------
+    ValueError
+        When the identifier is not found.
     """
     if not _sg_lookup_table:
         _buildSGLookupTable()
@@ -664,7 +676,7 @@ def GetSpaceGroup(sgid):
         return _sg_lookup_table[sgid]
     # Try different versions of sgid, first make sure it is a string
     emsg = "Unknown space group identifier %r" % sgid
-    if not isinstance(sgid, six.string_types):
+    if not isinstance(sgid, str):
         raise ValueError(emsg)
     sgbare = sgid.strip()
     # short_name case adjusted
@@ -681,9 +693,11 @@ def GetSpaceGroup(sgid):
 
 
 def IsSpaceGroupIdentifier(sgid):
-    """Check if identifier can be used as an argument to GetSpaceGroup.
+    """Check if identifier can be used as an argument to `GetSpaceGroup`.
 
-    Return bool.
+    Returns
+    -------
+    bool
     """
     try:
         GetSpaceGroup(sgid)
@@ -700,15 +714,15 @@ def FindSpaceGroup(symops, shuffle=False):
     ----------
     symops : list
         The list of `SymOp` objects for which to find SpaceGroup.
-    shuffle : bool, optional
+    shuffle : bool, Optional
         Flag for allowing different order of symops in the returned
-        SpaceGroup.  The default is ``False``.
+        SpaceGroup. The default is ``False``.
 
     Returns
     -------
     SpaceGroup
         The SpaceGroup object with equivalent list of symmetry
-        operations.  Return predefined SpaceGroup instance when
+        operations. Return predefined SpaceGroup instance when
         symmetry operations have the same order or when the
         `shuffle` flag is set.
 
@@ -753,10 +767,8 @@ def _hashSymOpList(symops):
 
 
 def _buildSGLookupTable():
-    """Rebuild space group lookup table from the SpaceGroupList data.
-
-    This routine updates the global _sg_lookup_table dictionary.
-    No return value.
+    """Rebuild space group lookup table from the `SpaceGroupList` data.
+    This routine updates the global `_sg_lookup_table` dictionary.
     """
     _sg_lookup_table.clear()
     for sg in SpaceGroupList:
@@ -797,7 +809,7 @@ def _buildSGLookupTable():
 
 
 def _getSGHashLookupTable():
-    """Return lookup table of symop hashes to standard SpaceGroup objects."""
+    """Return lookup table of symop hashes to standard `SpaceGroup` objects."""
     if _sg_hash_lookup_table:
         return _sg_hash_lookup_table
     for sg in SpaceGroupList:
diff --git a/src/diffpy/structure/structure.py b/src/diffpy/structure/structure.py
index 30eb3a31..5bebf4eb 100644
--- a/src/diffpy/structure/structure.py
+++ b/src/diffpy/structure/structure.py
@@ -13,14 +13,13 @@
 #
 ##############################################################################
 
-"""This module defines class Structure.
+"""This module defines class `Structure`.
 """
 
 import codecs
 import copy as copymod
 
 import numpy
-import six
 
 from diffpy.structure.atom import Atom
 from diffpy.structure.lattice import Lattice
@@ -30,45 +29,65 @@
 
 
 class Structure(list):
-    """Structure --> group of atoms
-
-    Structure class is inherited from Python list.  It contains
-    a list of Atom instances.  Structure overloads setitem and setslice
-    methods so that the lattice attribute of atoms get set to lattice.
-
-    Data members:
-        title   -- structure description
-        lattice -- coordinate system (instance of Lattice)
-        pdffit  -- None or a dictionary of PDFFit-related metadata
+    """Define group of atoms in a specified lattice. Structure --> group of atoms.
+
+    `Structure` class is inherited from Python `list`. It contains
+    a list of `Atom` instances. `Structure` overloads `setitem` and `setslice`
+    methods so that the `lattice` attribute of atoms get set to `lattice`.
+
+    Parameters
+    ----------
+    atoms : list of Atom or Structure, Optional
+        List of `Atom` instances to be included in this `Structure`.
+        When `atoms` argument is an existing `Structure` instance,
+        the new structure is its copy.
+    lattice : Lattice, Optional
+        Instance of `Lattice` defining coordinate systems, property.
+    title : str, Optional
+        String description of the structure.
+    filename : str, Optional
+        Name of a file to load the structure from.
+    format : str, Optional
+        `Structure` format of the loaded `filename`. By default
+        all structure formats are tried one by one. Ignored when
+        `filename` has not been specified.
+
+    Note
+    ----
+    Cannot use `filename` and `atoms` arguments together. Overrides `atoms` argument
+    when `filename` is specified.
+
+    Attributes
+    ----------
+    title : str
+        String description of the structure.
+    lattice : Lattice
+        Instance of `Lattice` defining coordinate systems.
+    pdffit : None or dict
+        Dictionary of PDFFit-related metadata.
+
+    Examples
+    --------
+    ``Structure(stru)`` create a copy of `Structure` instance stru.
+
+    >>> stru = Structure()
+    >>> copystru = Structure(stru)
+
+    `Structure` is inherited from a list it can use list expansions.
+
+    >>> oxygen_atoms = [a for a in stru if a.element == "O" ]
+    >>> oxygen_stru = Structure(oxygen_atoms, lattice=stru.lattice)
     """
 
     # default values for instance attributes
-
     title = ""
+    """str: default values for `title`."""
+
     _lattice = None
     pdffit = None
+    """None: default values for `pdffit`."""
 
     def __init__(self, atoms=None, lattice=None, title=None, filename=None, format=None):
-        """define group of atoms in a specified lattice.
-
-        atoms    -- list of Atom instances to be included in this Structure.
-                    When atoms argument is an existing Structure instance,
-                    the new Structure is its copy.
-        lattice  -- instance of Lattice defining coordinate systems, property.
-        title    -- string description of the structure
-        filename -- optional, name of a file to load the structure from.
-                    Overrides atoms argument when specified.
-        format   -- optional structure format of the loaded filename.  By default
-                    all structure formats are tried one by one.  Ignored when
-                    filename has not been specified.
-
-        Structure(stru)     create a copy of Structure instance stru.
-
-        Because Structure is inherited from a list it can use list expansions,
-        for example:
-            oxygen_atoms = [ for a in stru if a.element == "O" ]
-            oxygen_stru = Structure(oxygen_atoms, lattice=stru.lattice)
-        """
         # if filename is specified load it and return
         if filename is not None:
             if any((atoms, lattice, title)):
@@ -93,17 +112,22 @@ def __init__(self, atoms=None, lattice=None, title=None, filename=None, format=N
         return
 
     def copy(self):
-        """Return a copy of this Structure object."""
+        """Return a copy of this `Structure` object."""
         return copymod.copy(self)
 
     def __copy__(self, target=None):
         """Create a deep copy of this instance.
 
-        target   -- optional target instance for copying, useful for
-                    copying a derived class.  Defaults to new instance
-                    of the same type as self.
-
-        Return a duplicate instance of this object.
+        Parameters
+        ----------
+        target :
+            Optional target instance for copying, useful for
+            copying a derived class. Defaults to new instance
+            of the same type as self.
+
+        Returns
+        -------
+        A duplicate instance of this object.
         """
         if target is None:
             target = Structure()
@@ -118,17 +142,18 @@ def __copy__(self, target=None):
         return target
 
     def __str__(self):
-        """simple string representation"""
+        """Simple string representation."""
         s_lattice = "lattice=%s" % self.lattice
         s_atoms = "\n".join([str(a) for a in self])
         return s_lattice + "\n" + s_atoms
 
     def addNewAtom(self, *args, **kwargs):
-        """Add new Atom instance to the end of this Structure.
-
-        All arguments are forwarded to Atom constructor.
+        """Add new `Atom` instance to the end of this `Structure`.
 
-        No return value.
+        Parameters
+        ----------
+        *args, **kwargs :
+            See `Atom` class constructor.
         """
         kwargs["lattice"] = self.lattice
         a = Atom(*args, **kwargs)
@@ -136,16 +161,15 @@ def addNewAtom(self, *args, **kwargs):
         return
 
     def getLastAtom(self):
-        """Return Reference to the last Atom in this structure."""
+        """Return Reference to the last `Atom` in this structure."""
         last_atom = self[-1]
         return last_atom
 
     def assignUniqueLabels(self):
-        """Set a unique label string for each atom in this structure.
+        """Set a unique label string for each `Atom` in this structure.
+
         The label strings are formatted as "%(baresymbol)s%(index)i",
         where baresymbol is the element right-stripped of "[0-9][+-]".
-
-        No return value.
         """
         elnum = {}
         # support duplicate atom instances
@@ -160,30 +184,51 @@ def assignUniqueLabels(self):
         return
 
     def distance(self, aid0, aid1):
-        """Distance between 2 atoms, no periodic boundary conditions.
+        """Calculate distance between 2 `Atoms`, no periodic boundary conditions.
 
-        aid0 -- zero based index of the first atom or a string label
-                such as "Na1"
-        aid1 -- zero based index or string label of the second atom.
-
-        Return float.
-        Raise IndexError for invalid arguments.
+        Parameters
+        ----------
+        aid0 : int or str
+            Zero based index of the first `Atom` or a string label.
+        aid1 : int or str
+            Zero based index or string label of the second atom.
+
+        Returns
+        -------
+        float
+            Distance between the two `Atoms` in Angstroms.
+
+        Raises
+        ------
+        IndexError
+            If any of the `Atom` indices or labels are invalid.
         """
         # lookup by labels
         a0, a1 = self[aid0, aid1]
         return self.lattice.dist(a0.xyz, a1.xyz)
 
     def angle(self, aid0, aid1, aid2):
-        """The bond angle at the second of three atoms in degrees.
-
-        aid0 -- zero based index of the first atom or a string label
-                such as "Na1"
-        aid1 -- index or string label for the second atom,
-                where the angle is formed
-        aid2 -- index or string label for the third atom
+        """
+        The bond angle at the second of three `Atoms` in degrees.
 
-        Return float.
-        Raise IndexError for invalid arguments.
+        Parameters
+        ----------
+        aid0 : int or str
+            Zero based index of the first `Atom` or a string label.
+        aid1 : int or str
+            Index or string label for the second atom, where the angle is formed.
+        aid2 : int or str
+            Index or string label for the third atom.
+
+        Returns
+        -------
+        float
+            The bond angle in degrees.
+
+        Raises
+        ------
+        IndexError
+            If any of the arguments are invalid.
         """
         a0, a1, a2 = self[aid0, aid1, aid2]
         u10 = a0.xyz - a1.xyz
@@ -191,12 +236,21 @@ def angle(self, aid0, aid1, aid2):
         return self.lattice.angle(u10, u12)
 
     def placeInLattice(self, new_lattice):
-        """place structure into new_lattice coordinate system
+        """place structure into `new_lattice` coordinate system.
 
-        sets lattice to new_lattice and recalculate fractional coordinates
-        of all atoms so their absolute positions remain the same
+        Sets `lattice` to `new_lattice` and recalculate fractional coordinates
+        of all `Atoms` so their absolute positions remain the same.
 
-        return self
+        Parameters
+        ----------
+        new_lattice : Lattice
+            New `lattice` to place the structure into.
+
+        Returns
+        -------
+        Structure
+            Reference to this `Structure` object. The `lattice` attribute
+            is updated to `new_lattice`.
         """
         Tx = numpy.dot(self.lattice.base, new_lattice.recbase)
         Tu = numpy.dot(self.lattice.normbase, new_lattice.recnormbase)
@@ -210,12 +264,19 @@ def placeInLattice(self, new_lattice):
     def read(self, filename, format="auto"):
         """Load structure from a file, any original data become lost.
 
-        filename -- file to be loaded
-        format   -- all structure formats are defined in parsers submodule,
-                    when format == 'auto' all parsers are tried one by one
-
-        Return instance of data Parser used to process file.  This
-        can be inspected for information related to particular format.
+        Parameters
+        ----------
+        filename : str
+            File to be loaded.
+        format : str, Optional
+            All structure formats are defined in parsers submodule,
+            when ``format == 'auto'`` all parsers are tried one by one.
+
+        Returns
+        -------
+        Parser
+            Return instance of data Parser used to process input string. This
+            can be inspected for information related to particular format.
         """
         import diffpy.structure
         import diffpy.structure.parsers
@@ -238,14 +299,21 @@ def read(self, filename, format="auto"):
         return p
 
     def readStr(self, s, format="auto"):
-        """Load structure from a string, any original data become lost.
+        """Read structure from a string.
 
-        s        -- string with structure definition
-        format   -- all structure formats are defined in parsers submodule,
-                    when format == 'auto' all parsers are tried one by one
-
-        Return instance of data Parser used to process input string.  This
-        can be inspected for information related to particular format.
+        Parameters
+        ----------
+        s : str
+            String with structure definition.
+        format : str, Optional
+            All structure formats are defined in parsers submodule. When ``format == 'auto'``,
+            all parsers are tried one by one.
+
+        Returns
+        -------
+        Parser
+            Return instance of data Parser used to process input string. This
+            can be inspected for information related to particular format.
         """
         from diffpy.structure.parsers import getParser
 
@@ -260,12 +328,20 @@ def readStr(self, s, format="auto"):
         return p
 
     def write(self, filename, format):
-        """Save structure to file in the specified format
+        """Save structure to file in the specified format.
+
+        Parameters
+        ----------
+        filename : str
+            File to save the structure to.
+        format : str
+            `Structure` format to use for saving.
 
-        No return value.
+        Note
+        ----
+        Available structure formats can be obtained by:
 
-        Note: available structure formats can be obtained by:
-            from parsers import formats
+            ``from parsers import formats``
         """
         from diffpy.structure.parsers import getParser
 
@@ -277,10 +353,13 @@ def write(self, filename, format):
         return
 
     def writeStr(self, format):
-        """return string representation of the structure in specified format
+        """return string representation of the structure in specified format.
 
-        Note: available structure formats can be obtained by:
-            from parsers import formats
+        Note
+        ----
+        Available structure formats can be obtained by:
+
+            ``from parsers import formats``
         """
         from diffpy.structure.parsers import getParser
 
@@ -289,20 +368,21 @@ def writeStr(self, format):
         return s
 
     def tolist(self):
-        """Return atoms in this Structure as a standard Python list."""
+        """Return `Atoms` in this `Structure` as a standard Python list."""
         rv = [a for a in self]
         return rv
 
     # Overloaded list Methods and Operators ----------------------------------
 
     def append(self, a, copy=True):
-        """Append atom to a structure and update its lattice attribute.
-
-        a    -- instance of Atom
-        copy -- flag for appending a copy of a.
-                When False, append a and update a.lattice.
+        """Append `Atom` to a structure and update its `lattice` attribute.
 
-        No return value.
+        Parameters
+        ----------
+        a : Atom
+            Instance of `Atom` to be appended.
+        copy : bool, Optional
+            Flag for appending a copy of `a`. When ``False``, append `a` and update `a.lattice`.
         """
         adup = copy and Atom(a) or a
         adup.lattice = self.lattice
@@ -310,14 +390,16 @@ def append(self, a, copy=True):
         return
 
     def insert(self, idx, a, copy=True):
-        """Insert atom a before position idx in this Structure.
-
-        idx  -- position in atom list
-        a    -- instance of Atom
-        copy -- flag for inserting a copy of a.
-                When False, append a and update a.lattice.
+        """Insert `Atom` a before position idx in this `Structure`.
 
-        No return value.
+        Parameters
+        ----------
+        idx : int
+            Position in `Atom` list.
+        a : Atom
+            Instance of `Atom` to be inserted.
+        copy : bool, Optional
+            Flag for inserting a copy of `a`. When ``False``, append `a` and update `a.lattice`.
         """
         adup = copy and copymod.copy(a) or a
         adup.lattice = self.lattice
@@ -325,17 +407,17 @@ def insert(self, idx, a, copy=True):
         return
 
     def extend(self, atoms, copy=None):
-        """Extend Structure with an iterable of atoms.
+        """Extend `Structure` with an iterable of `atoms`.
 
-        Update the `lattice` attribute of all added atoms.
+        Update the `lattice` attribute of all added `atoms`.
 
         Parameters
         ----------
-        atoms : iterable
-            The `Atom` objects to be appended to this Structure.
-        copy : bool, optional
-            Flag for adding copies of Atom objects.
-            Make copies when `True`, append `atoms` unchanged when ``False``.
+        atoms : Iterable
+            The `Atom` objects to be appended to this `Structure`.
+        copy : bool, Optional
+            Flag for adding copies of `Atom` objects.
+            Make copies when ``True``, append `atoms` unchanged when ``False``.
             The default behavior is to make copies when `atoms` are of
             `Structure` type or if new atoms introduce repeated objects.
         """
@@ -365,25 +447,44 @@ def setlat(a):
         return
 
     def __getitem__(self, idx):
-        """Get one or more atoms in this structure.
+        """Get one or more `Atoms` in this structure.
+
+        Parameters
+        ----------
+        idx : int ot str ot Iterable
+            `Atom` identifier. When integer use standard list lookup.
+            For iterables use numpy lookup, this supports integer or
+            boolean flag arrays. For string or string-containing iterables
+            lookup the `Atoms` by string label.
+
+        Returns
+        -------
+        Atom or Structure
+            An `Atom` instance for integer or string index or a substructure
+            in all other cases.
 
-        idx  -- atom identifier, which can be integer, string or iterable.
-                When integer use standard list lookup.  For iterables use
-                numpy lookup, this supports integer or boolean flag arrays.
-                For string or string-containing iterables lookup the atoms
-                by string label.
+        Raises
+        ------
+        IndexError
+            If the index is invalid or the `Atom` label is not unique.
 
-        Return an Atom instance for integer or string index or a substructure
-        in all other cases.  Raise IndexError for invalid index or for
-        non-unique atom label.
+        Examples
+        --------
+        First `Atom` in the `Structure`:
 
-        Examples:
+        >>> stru[0]
 
-        stru[0]  -->  first atom in the Structure
-        stru[stru.element == 'Na']  -->  substructure of all Na atoms
-        stru['Na3']  -->  atom with a unique label 'Na3'
-        stru['Na3', 2, 'Cl2']  -->  substructure of three atoms, lookup by
-            label is more efficient when done for several atoms at once.
+        Substructure of all ``'Na'`` `Atoms`:
+
+        >>> stru[stru.element == 'Na']
+
+        `Atom` with a unique label ``'Na3'``:
+        >>> stru['Na3']
+
+        Substructure of three `Atoms`, lookup by label is more efficient
+        when done for several `Atoms` at once.
+
+        >>> stru['Na3', 2, 'Cl2']
         """
         if isinstance(idx, slice):
             rv = self.__emptySharedStructure()
@@ -396,10 +497,8 @@ def __getitem__(self, idx):
         except TypeError:
             pass
         # check if there is any string label that should be resolved
-        scalarstringlabel = isinstance(idx, six.string_types)
-        hasstringlabel = scalarstringlabel or (
-            isiterable(idx) and any(isinstance(ii, six.string_types) for ii in idx)
-        )
+        scalarstringlabel = isinstance(idx, str)
+        hasstringlabel = scalarstringlabel or (isiterable(idx) and any(isinstance(ii, str) for ii in idx))
         # if not, use numpy indexing to resolve idx
         if not hasstringlabel:
             idx1 = idx
@@ -440,14 +539,18 @@ def _resolveindex(aid):
         return rv
 
     def __setitem__(self, idx, value, copy=True):
-        """Assign self[idx] atom to value.
+        """Assign `self[idx]` `Atom` to value.
 
-        idx  -- index of atom in this Structure or a slice
-        value -- instance of Atom or an iterable.
-        copy -- flag for making a copy of the value.  When False, update
-                the `lattice` attribute of Atom objects present in value.
-
-        No return value.
+        Parameters
+        ----------
+        idx : int or slice
+            Index of `Atom` in this `Structure` or a slice.
+        value : Atom or Iterable
+            Instance of `Atom` or an iterable.
+        copy : bool, Optional
+            Flag for making a copy of the value. When ``False``, update
+            the `lattice` attribute of `Atom` objects present in value.
+            Default is ``True``.
         """
         # handle slice assignment
         if isinstance(idx, slice):
@@ -469,32 +572,50 @@ def _fixlat(a):
         return
 
     def __add__(self, other):
-        """Return new Structure object with appended atoms from other.
+        """Return new `Structure` object with appended `Atoms` from other.
 
-        other    -- sequence of Atom instances
+        Parameters
+        ----------
+        other : sequence of Atom
+            Sequence of `Atom` instances.
 
-        Return new Structure with a copy of Atom instances.
+        Returns
+        -------
+        Structure
+            New `Structure` with a copy of `Atom` instances.
         """
         rv = copymod.copy(self)
         rv += other
         return rv
 
     def __iadd__(self, other):
-        """Extend this Structure with atoms from other.
+        """Extend this `Structure` with `Atoms` from other.
 
-        other    -- sequence of Atom instances
+        Parameters
+        ----------
+        other : sequence of Atom
+            Sequence of `Atom` instances.
 
-        Return self.
+        Returns
+        -------
+        Structure
+            Reference to this `Structure` object.
         """
         self.extend(other, copy=True)
         return self
 
     def __sub__(self, other):
-        """Return new Structure that has atoms from the other removed.
+        """Return new `Structure` that has `Atoms` from the other removed.
 
-        other    -- sequence of Atom instances
+        Parameters
+        ----------
+        other : sequence of Atom
+            Sequence of `Atom` instances.
 
-        Return new Structure with a copy of Atom instances.
+        Returns
+        -------
+        Structure
+            New `Structure` with a copy of `Atom` instances.
         """
         otherset = set(other)
         keepindices = [i for i, a in enumerate(self) if a not in otherset]
@@ -502,23 +623,35 @@ def __sub__(self, other):
         return rv
 
     def __isub__(self, other):
-        """Remove other atoms if present in this structure.
+        """Remove other `Atoms` if present in this structure.
 
-        other    -- sequence of Atom instances
+        Parameters
+        ----------
+        other : sequence of Atom
+            Sequence of `Atom` instances.
 
-        Return self.
+        Returns
+        -------
+        Structure
+            Reference to this `Structure` object.
         """
         otherset = set(other)
         self[:] = [a for a in self if a not in otherset]
         return self
 
     def __mul__(self, n):
-        """Return new Structure with n-times concatenated atoms from self.
-        Atoms and lattice in the new structure are all copies.
+        """Return new `Structure` with n-times concatenated `Atoms` from self.
+        `Atoms` and `lattice` in the new structure are all copies.
 
-        n    -- integer multiple
+        Parameters
+        ----------
+        n : int
+            Integer multiple.
 
-        Return new Structure.
+        Returns
+        -------
+        Structure
+            New `Structure` with n-times concatenated `Atoms`.
         """
         rv = copymod.copy(self[:0])
         rv += n * self.tolist()
@@ -528,13 +661,19 @@ def __mul__(self, n):
     __rmul__ = __mul__
 
     def __imul__(self, n):
-        """Concatenate this Structure to n-times more atoms.
-        For positive multiple the current Atom objects remain at the
-        beginning of this Structure.
+        """Concatenate this `Structure` to n-times more `Atoms`.
+        For positive multiple the current `Atom` objects remain at the
+        beginning of this `Structure`.
 
-        n    -- integer multiple
+        Parameters
+        ----------
+        n : int
+            Integer multiple.
 
-        Return self.
+        Returns
+        -------
+        Structure
+            Reference to this `Structure` object.
         """
         if n <= 0:
             self[:] = []
@@ -555,7 +694,7 @@ def _set_lattice(self, value):
         self._lattice = value
         return
 
-    lattice = property(_get_lattice, _set_lattice, doc="Coordinate system for this Structure.")
+    lattice = property(_get_lattice, _set_lattice, doc="Coordinate system for this `Structure`.")
 
     # composition
 
@@ -571,170 +710,157 @@ def _get_composition(self):
 
     element = _linkAtomAttribute(
         "element",
-        """Character array of atom types.  Assignment updates
-        the element attribute of the respective atoms.""",
+        """Character array of `Atom` types. Assignment updates
+        the element attribute of the respective `Atoms`.""",
         toarray=numpy.char.array,
     )
 
     xyz = _linkAtomAttribute(
         "xyz",
-        """Array of fractional coordinates of all atoms.
-        Assignment updates xyz attribute of all atoms.""",
+        """Array of fractional coordinates of all `Atoms`.
+        Assignment updates `xyz` attribute of all `Atoms`.""",
     )
 
     x = _linkAtomAttribute(
         "x",
-        """Array of all fractional coordinates x.
-        Assignment updates xyz attribute of all atoms.""",
+        """Array of all fractional coordinates `x`.
+        Assignment updates `xyz` attribute of all `Atoms`.""",
     )
 
     y = _linkAtomAttribute(
         "y",
-        """Array of all fractional coordinates y.
-        Assignment updates xyz attribute of all atoms.""",
+        """Array of all fractional coordinates `y`.
+        Assignment updates `xyz` attribute of all `Atoms`.""",
     )
 
     z = _linkAtomAttribute(
         "z",
-        """Array of all fractional coordinates z.
-        Assignment updates xyz attribute of all atoms.""",
+        """Array of all fractional coordinates `z`.
+        Assignment updates `xyz` attribute of all `Atoms`.""",
     )
 
     label = _linkAtomAttribute(
         "label",
-        """Character array of atom names.  Assignment updates
-        the label attribute of all atoms.""",
+        """Character array of `Atom` names. Assignment updates
+        the label attribute of all `Atoms`.""",
         toarray=numpy.char.array,
     )
 
     occupancy = _linkAtomAttribute(
         "occupancy",
-        """Array of atom occupancies.  Assignment updates the
-        occupancy attribute of all atoms.""",
+        """Array of `Atom` occupancies. Assignment updates the
+        occupancy attribute of all `Atoms`.""",
     )
 
     xyz_cartn = _linkAtomAttribute(
         "xyz_cartn",
-        """Array of absolute Cartesian coordinates of all atoms.
-        Assignment updates the xyz attribute of all atoms.""",
+        """Array of absolute Cartesian coordinates of all `Atoms`.
+        Assignment updates the `xyz` attribute of all `Atoms`.""",
     )
 
     anisotropy = _linkAtomAttribute(
         "anisotropy",
         """Boolean array for anisotropic thermal displacement flags.
-        Assignment updates the anisotropy attribute of all atoms.""",
+        Assignment updates the anisotropy attribute of all `Atoms`.""",
     )
 
     U = _linkAtomAttribute(
         "U",
         """Array of anisotropic thermal displacement tensors.
-        Assignment updates the U and anisotropy attributes of all atoms.""",
+        Assignment updates the U and anisotropy attributes of all `Atoms`.""",
     )
 
     Uisoequiv = _linkAtomAttribute(
         "Uisoequiv",
         """Array of isotropic thermal displacement or equivalent values.
-        Assignment updates the U attribute of all atoms.""",
+        Assignment updates the U attribute of all `Atoms`.""",
     )
 
     U11 = _linkAtomAttribute(
         "U11",
-        """Array of U11 elements of the anisotropic displacement tensors.
-        Assignment updates the U and anisotropy attributes of all atoms.""",
+        """Array of `U11` elements of the anisotropic displacement tensors.
+        Assignment updates the U and anisotropy attributes of all `Atoms`.""",
     )
 
     U22 = _linkAtomAttribute(
         "U22",
-        """Array of U22 elements of the anisotropic displacement tensors.
-        Assignment updates the U and anisotropy attributes of all atoms.""",
+        """Array of `U22` elements of the anisotropic displacement tensors.
+        Assignment updates the U and anisotropy attributes of all `Atoms`.""",
     )
 
     U33 = _linkAtomAttribute(
         "U33",
-        """Array of U33 elements of the anisotropic displacement tensors.
-        Assignment updates the U and anisotropy attributes of all atoms.""",
+        """Array of `U33` elements of the anisotropic displacement tensors.
+        Assignment updates the U and anisotropy attributes of all `Atoms`.""",
     )
 
     U12 = _linkAtomAttribute(
         "U12",
-        """Array of U12 elements of the anisotropic displacement tensors.
-        Assignment updates the U and anisotropy attributes of all atoms.""",
+        """Array of `U12` elements of the anisotropic displacement tensors.
+        Assignment updates the U and anisotropy attributes of all `Atoms`.""",
     )
 
     U13 = _linkAtomAttribute(
         "U13",
-        """Array of U13 elements of the anisotropic displacement tensors.
-        Assignment updates the U and anisotropy attributes of all atoms.""",
+        """Array of `U13` elements of the anisotropic displacement tensors.
+        Assignment updates the U and anisotropy attributes of all `Atoms`.""",
     )
 
     U23 = _linkAtomAttribute(
         "U23",
-        """Array of U23 elements of the anisotropic displacement tensors.
-        Assignment updates the U and anisotropy attributes of all atoms.""",
+        """Array of `U23` elements of the anisotropic displacement tensors.
+        Assignment updates the U and anisotropy attributes of all `Atoms`.""",
     )
 
     Bisoequiv = _linkAtomAttribute(
         "Bisoequiv",
         """Array of Debye-Waller isotropic thermal displacement or equivalent
-        values.  Assignment updates the U attribute of all atoms.""",
+        values. Assignment updates the U attribute of all `Atoms`.""",
     )
 
     B11 = _linkAtomAttribute(
         "B11",
-        """Array of B11 elements of the Debye-Waller displacement tensors.
-        Assignment updates the U and anisotropy attributes of all atoms.""",
+        """Array of `B11` elements of the Debye-Waller displacement tensors.
+        Assignment updates the U and anisotropy attributes of all `Atoms`.""",
     )
 
     B22 = _linkAtomAttribute(
         "B22",
-        """Array of B22 elements of the Debye-Waller displacement tensors.
-        Assignment updates the U and anisotropy attributes of all atoms.""",
+        """Array of `B22` elements of the Debye-Waller displacement tensors.
+        Assignment updates the U and anisotropy attributes of all `Atoms`.""",
     )
 
     B33 = _linkAtomAttribute(
         "B33",
-        """Array of B33 elements of the Debye-Waller displacement tensors.
-        Assignment updates the U and anisotropy attributes of all atoms.""",
+        """Array of `B33` elements of the Debye-Waller displacement tensors.
+        Assignment updates the U and anisotropy attributes of all `Atoms`.""",
     )
 
     B12 = _linkAtomAttribute(
         "B12",
-        """Array of B12 elements of the Debye-Waller displacement tensors.
-        Assignment updates the U and anisotropy attributes of all atoms.""",
+        """Array of `B12` elements of the Debye-Waller displacement tensors.
+        Assignment updates the U and anisotropy attributes of all `Atoms`.""",
     )
 
     B13 = _linkAtomAttribute(
         "B13",
-        """Array of B13 elements of the Debye-Waller displacement tensors.
-        Assignment updates the U and anisotropy attributes of all atoms.""",
+        """Array of `B13` elements of the Debye-Waller displacement tensors.
+        Assignment updates the U and anisotropy attributes of all `Atoms`.""",
     )
 
     B23 = _linkAtomAttribute(
         "B23",
-        """Array of B23 elements of the Debye-Waller displacement tensors.
-        Assignment updates the U and anisotropy attributes of all atoms.""",
+        """Array of `B23` elements of the Debye-Waller displacement tensors.
+        Assignment updates the U and anisotropy attributes of all `Atoms`.""",
     )
 
     # Private Methods --------------------------------------------------------
 
     def __emptySharedStructure(self):
-        """Return empty Structure with standard attributes same as in self."""
+        """Return empty `Structure` with standard attributes same as in self."""
         rv = Structure()
         rv.__dict__.update([(k, getattr(self, k)) for k in rv.__dict__])
         return rv
 
-    # Python 2 Compatibility -------------------------------------------------
-
-    if six.PY2:
-
-        def __getslice__(self, lo, hi):
-            return self.__getitem__(slice(lo, hi))
-
-        def __setslice__(self, lo, hi, sequence):
-            self.__setitem__(slice(lo, hi), sequence)
-            return
-
-    # ------------------------------------------------------------------------
-
 
 # End of class Structure
diff --git a/src/diffpy/structure/structureerrors.py b/src/diffpy/structure/structureerrors.py
index 2669b6e1..c930b9b7 100644
--- a/src/diffpy/structure/structureerrors.py
+++ b/src/diffpy/structure/structureerrors.py
@@ -18,7 +18,7 @@
 
 
 class StructureFormatError(Exception):
-    """Exception for failed IO from Structure file"""
+    """Exception for failed IO from Structure file."""
 
     pass
 
diff --git a/src/diffpy/structure/symmetryutilities.py b/src/diffpy/structure/symmetryutilities.py
index efc13782..b58e7c88 100644
--- a/src/diffpy/structure/symmetryutilities.py
+++ b/src/diffpy/structure/symmetryutilities.py
@@ -15,6 +15,16 @@
 
 """Symmetry utility functions such as expansion of asymmetric unit,
 and generation of positional constraints.
+
+Attributes
+----------
+epsilon : float
+    Default tolerance for equality of 2 positions, also
+    used for identification of special positions.
+
+stdUsymbols : list
+    Standard symbols denoting elements of anisotropic thermal
+    displacement tensor.
 """
 
 import re
@@ -26,12 +36,8 @@
 
 # Constants ------------------------------------------------------------------
 
-# Default tolerance for equality of 2 positions, also
-# used for identification of special positions.
 epsilon = 1.0e-5
 
-# Standard symbols denoting elements of anisotropic thermal
-# displacement tensor.
 stdUsymbols = ["U11", "U22", "U33", "U12", "U13", "U23"]
 
 # ----------------------------------------------------------------------------
@@ -40,10 +46,23 @@
 def isSpaceGroupLatPar(spacegroup, a, b, c, alpha, beta, gamma):
     """Check if space group allows passed lattice parameters.
 
-    spacegroup -- instance of SpaceGroup
-    a, b, c, alpha, beta, gamma -- lattice parameters
+    Parameters
+    ----------
+    spacegroup : SpaceGroup
+        Instance of `SpaceGroup`.
+    a, b, c, alpha, beta, gamma : float
+        `Lattice` parameters.
+
+    Return
+    ------
+    bool
+        ``True`` when lattice parameters are allowed by space group.
+
+    Note
+    ----
+    Crystal system rules:
 
-    Return bool.
+    Benjamin, W. A., Introduction to crystallography, New York (1969), p.60.
     """
 
     # crystal system rules
@@ -93,12 +112,17 @@ def check_cubic():
 
 
 def isconstantFormula(s):
-    """Check if formula string is constant.  True when argument
-    is a floating point number or a fraction of float with integer.
+    """Check if formula string is constant.
 
-    s   -- formula string
+    Parameters
+    ----------
+    s : str
+        Formula string.
 
-    Return bool.
+    Return
+    ------
+    bool
+        ``True`` when argument is a floating point number or a fraction of float with integer.
     """
     res = _rx_constant_formula.match(s.replace(" ", ""))
     return bool(res)
@@ -109,22 +133,26 @@ def isconstantFormula(s):
 
 class _Position2Tuple(object):
     """Create callable object that converts fractional coordinates to
-    a tuple of integers with given precision.  For presision close to zero
+    a tuple of integers with given precision. For presision close to zero
     it will return a tuples of double.
 
-    Note: Helper class intended for local use only.
+    Note
+    ----
+    Helper class intended for local use only.
 
-    Data members:
+    Parameters
+    ----------
+    eps : float
+        Cutoff for equivalent coordinates.
 
-    eps -- cutoff for equivalent coordinates.  When two coordiantes map to the
-           same tuple, they are closer than eps.
+    Attributes
+    ----------
+    eps : float
+        Cutoff for equivalent coordinates. When two coordiantes map to the
+        same tuple, they are closer than `eps`.
     """
 
     def __init__(self, eps=None):
-        """Initialize _Position2Tuple
-
-        eps -- cutoff for equivalent coordinates
-        """
         if eps is None:
             eps = epsilon
         # ensure self.eps has exact machine representation
@@ -138,9 +166,15 @@ def __init__(self, eps=None):
     def __call__(self, xyz):
         """Convert array of fractional coordinates to a tuple.
 
-        xyz -- fractional coordinates
+        Parameters
+        ----------
+        xyz : Iterable
+            Fractional coordinates.
 
-        Return a tuple of 3 numbers.
+        Return
+        ------
+        tuple
+            Tuple of 3 float when `eps` is zero, otherwise tuple of 3 int.
         """
         # no conversion case
         if self.eps == 0.0:
@@ -157,9 +191,16 @@ def __call__(self, xyz):
 def positionDifference(xyz0, xyz1):
     """Smallest difference between two coordinates in periodic lattice.
 
-    xyz0, xyz1  -- fractional coordinates
+    Parameters
+    ----------
+    xyz0, xyz1 : array_like
+        Fractional coordinates.
 
-    Return dxyz, a numpy.array dxyz with 0 <= dxyz <= 0.5.
+    Return
+    ------
+    dxyz : numpy.ndarray
+        Smallest difference between two coordinates in periodic lattice
+        with ``0 <= dxyz <= 0.5``.
     """
     dxyz = numpy.asarray(xyz0) - xyz1
     # map differences to [0,0.5]
@@ -172,10 +213,17 @@ def positionDifference(xyz0, xyz1):
 def nearestSiteIndex(sites, xyz):
     """Index of the nearest site to a specified position.
 
-    sites -- list of coordinates or a 2-dimensional numpy.array
-    xyz   -- single position
-
-    Return integer.
+    Parameters
+    ----------
+    sites : array_like
+        List of coordinates.
+    xyz : array_like
+        Single position.
+
+    Return
+    ------
+    int
+        Index of the nearest site.
     """
     # we use box distance to be consistent with _Position2Tuple conversion
     dbox = positionDifference(sites, xyz).max(axis=1)
@@ -186,10 +234,17 @@ def nearestSiteIndex(sites, xyz):
 def equalPositions(xyz0, xyz1, eps):
     """Equality of two coordinates with optional tolerance.
 
-    xyz0, xyz1 -- fractional coordinates
-    eps        -- tolerance for equality of coordinates
-
-    Return bool.
+    Parameters
+    ----------
+    xyz0, xyz1 : array_like
+        Fractional coordinates.
+    eps : float
+        Tolerance for equality of coordinates.
+
+    Return
+    ------
+    bool
+        ``True`` when two coordinates are closer than `eps`.
     """
     # we use box distance to be consistent with _Position2Tuple conversion
     dxyz = positionDifference(xyz0, xyz1)
@@ -199,13 +254,22 @@ def equalPositions(xyz0, xyz1, eps):
 def expandPosition(spacegroup, xyz, sgoffset=[0, 0, 0], eps=None):
     """Obtain unique equivalent positions and corresponding operations.
 
-    spacegroup -- instance of SpaceGroup
-    xyz        -- position to be expanded
-    sgoffset   -- offset of space group origin [0, 0, 0]
-    eps        -- cutoff for equal positions
-
-    Return a tuple with (list of unique equivalent positions, nested
-    list of SpaceGroups.SymOp instances, site multiplicity).
+    Parameters
+    ----------
+    spacegroup : SpaceGroup
+        Instance of SpaceGroup.
+    xyz : list
+        Position to be expanded.
+    sgoffset : list, Optional
+        Offset of space group origin ``[0, 0, 0]``. Default is ``[0, 0, 0]``.
+    eps : float, Optional
+        Cutoff for equal positions, default is ``1.0e-5``.
+
+    Return
+    ------
+    tuple
+        A tuple with ``(list of unique equivalent positions, nested
+        list of `SpaceGroups.SymOp` instances, site multiplicity)``.
     """
     sgoffset = numpy.asarray(sgoffset, dtype=float)
     if eps is None:
@@ -256,10 +320,20 @@ def nullSpace(A):
 def _findInvariants(symops):
     """Find a list of symmetry operations which contains identity.
 
-    symops  -- nested list of SymOp instances
+    Parameters
+    ----------
+    symops : list of SymOp
+        Nested list of `SymOp` instances.
+
+    Return
+    ------
+    list
+        List-item in symops which contains identity.
 
-    Return the list-item in symops which contains identity.
-    Raise ValueError when identity was not found.
+    Raise
+    -----
+    ValueError
+        When identity is not found.
     """
     invrnts = None
     R0 = numpy.identity(3, dtype=float)
@@ -283,23 +357,53 @@ def _findInvariants(symops):
 class GeneratorSite(object):
     """Storage of data related to a generator positions.
 
-    Data members:
-        xyz          -- fractional coordinates of generator site
-        Uij          -- anisotropic thermal displacement at generator site
-        sgoffset     -- offset of space group origin [0, 0, 0]
-        eps          -- cutoff for equal positions
-        eqxyz        -- list of equivalent positions
-        eqUij        -- list of displacement matrices at equivalent positions
-        symops       -- nested list of operations per each eqxyz
-        multiplicity -- generator site multiplicity
-        Uisotropy    -- bool flag for isotropic thermal factors
-        invariants   -- list of invariant operations for generator site
-        null_space   -- null space of all possible differences of invariant
-                        rotational matrices, this is a base of symmetry
-                        allowed shifts.
-        Uspace       -- 3D array of independent components of U matrices.
-        pparameters  -- list of (xyz symbol, value) pairs
-        Uparameters  -- list of (U symbol, value) pairs
+    Parameters
+    ----------
+    spacegroup : SpaceGroup
+        Instance of `SpaceGroup`.
+    xyz : array_like
+        Generating site. When `xyz` is close to special
+        position `self.xyz` will be adjusted.
+    Uij : array_like, Optional
+        Thermal factors at generator site. Yields `self.Uij`
+        after adjusting to spacegroup symmetry. Default is zeros.
+    sgoffset : list, Optional
+        Offset of space group origin ``[0, 0, 0]``. Default is ``[0, 0, 0]``.
+    eps : float, Optional
+        Cutoff for equal positions. Default is ``1.0e-5``.
+
+    Attributes
+    ----------
+    xyz : numpy.ndarray
+        Fractional coordinates of generator site.
+    Uij : numpy.ndarray
+        Anisotropic thermal displacement at generator site.
+    sgoffset : numpy.ndarray
+        Offset of space group origin ``[0, 0, 0]``.
+    eps : float
+        Cutoff for equal positions.
+    eqxyz : list
+        List of equivalent positions.
+    eqUij : list
+        List of displacement matrices at equivalent positions.
+    symops : list
+        Nested list of operations per each `eqxyz`.
+    multiplicity : int
+        Generator site multiplicity.
+    Uisotropy : bool
+        Bool flag for isotropic thermal factors.
+    invariants : list
+        List of invariant operations for generator site.
+    null_space : numpy.ndarray
+        Null space of all possible differences of invariant
+        rotational matrices, this is a base of symmetry
+        allowed shifts.
+    Uspace : numpy.ndarray
+        3D array of independent components of U matrices.
+    pparameters : list
+        List of ``(xyz symbol, value)`` pairs.
+    Uparameters : list
+        List of ``(U symbol, value)`` pairs.
     """
 
     Ucomponents = numpy.array(
@@ -313,19 +417,12 @@ class GeneratorSite(object):
         ],
         dtype=float,
     )
+    """numpy.ndarray: 6x3x3 array of independent components of U matrices."""
+
     idx2Usymbol = {0: "U11", 1: "U12", 2: "U13", 3: "U12", 4: "U22", 5: "U23", 6: "U13", 7: "U23", 8: "U33"}
+    """dict: Mapping of index to standard U symbol."""
 
     def __init__(self, spacegroup, xyz, Uij=numpy.zeros((3, 3)), sgoffset=[0, 0, 0], eps=None):
-        """Initialize GeneratorSite.
-
-        spacegroup -- instance of SpaceGroup
-        xyz        -- generating site.  When xyz is close to special
-                      position self.xyz will be adjusted.
-        Uij        -- thermal factors at generator site.  Yields self.Uij
-                      after adjusting to spacegroup symmetry.
-        sgoffset   -- offset of space group origin [0, 0, 0]
-        eps        -- cutoff for equal positions
-        """
         if eps is None:
             eps = epsilon
         # just declare the members
@@ -371,10 +468,19 @@ def __init__(self, spacegroup, xyz, Uij=numpy.zeros((3, 3)), sgoffset=[0, 0, 0],
 
     def signedRatStr(self, x):
         """Convert floating point number to signed rational representation.
+
         Possible fractional are multiples of 1/3, 1/6, 1/7, 1/9, if these
-        are not close, return "%+g" format.
+        are not close, return `%+g` format.
 
-        Return string.
+        Parameters
+        ----------
+        x : float
+            Floating point number.
+
+        Return
+        ------
+        str
+            Signed rational representation of `x`.
         """
         s = "{:.8g}".format(x)
         if len(s) < 6:
@@ -388,8 +494,8 @@ def signedRatStr(self, x):
         return "%+.0f/%.0f" % (nom[idx[0]], den[idx[0]])
 
     def _findNullSpace(self):
-        """Calculate self.null_space from self.invariants.
-        Try to represent self.null_space using small integers.
+        """Calculate `self.null_space` from `self.invariants`.
+        Try to represent `self.null_space` using small integers.
         """
         R0 = self.invariants[0].R
         Rdiff = [(symop.R - R0) for symop in self.invariants]
@@ -419,7 +525,7 @@ def _findNullSpace(self):
         return
 
     def _findPosParameters(self):
-        """Find pparameters and their values for expressing self.xyz."""
+        """Find pparameters and their values for expressing `self.xyz`."""
         usedsymbol = {}
         # parameter values depend on offset of self.xyz
         txyz = self.xyz
@@ -462,7 +568,7 @@ def _findUSpace(self):
         return
 
     def _findUParameters(self):
-        """Find Uparameters and their values for expressing self.Uij."""
+        """Find Uparameters and their values for expressing `self.Uij`."""
         # permute indices as     00 11 22 01 02 12 10 20 21
         diagorder = numpy.array((0, 4, 8, 1, 2, 5, 3, 6, 7))
         Uijflat = self.Uij.flatten()
@@ -477,7 +583,7 @@ def _findUParameters(self):
         return
 
     def _findeqUij(self):
-        """Adjust self.Uij and self.eqUij to be consistent with spacegroup"""
+        """Adjust `self.Uij` and `self.eqUij` to be consistent with spacegroup."""
         self.Uij = numpy.zeros((3, 3), dtype=float)
         for i in range(len(self.Uparameters)):
             Usp = self.Uspace[i]
@@ -492,15 +598,22 @@ def _findeqUij(self):
         return
 
     def positionFormula(self, pos, xyzsymbols=("x", "y", "z")):
-        """Formula of equivalent position with respect to generator site
-
-        pos        -- fractional coordinates of possibly equivalent site
-        xyzsymbols -- symbols for parametrized coordinates
-
-        Return position formulas in a dictionary with keys equal ("x", "y", "z")
-        or an empty dictionary when pos is not equivalent to generator.
-        Formulas are formatted as "[[-][%g*]{x|y|z}] [{+|-}%g]", for example
-        "-x", "z +0.5", "0.25".
+        """Formula of equivalent position with respect to generator site.
+
+        Parameters
+        ----------
+        pos : array_like
+            Fractional coordinates of possibly equivalent site.
+        xyzsymbols : tuple, Optional
+            Symbols for parametrized coordinates.
+
+        Return
+        ------
+        dict
+            Position formulas in a dictionary with keys equal ``("x", "y", "z")``
+            or an empty dictionary when pos is not equivalent to generator.
+            Formulas are formatted as ``[[-][%g*]{x|y|z}] [{+|-}%g]``, for example
+            ``-x``, ``z +0.5``, ``0.25``.
         """
         # find pos in eqxyz
         idx = nearestSiteIndex(self.eqxyz, pos)
@@ -535,12 +648,20 @@ def positionFormula(self, pos, xyzsymbols=("x", "y", "z")):
     def UFormula(self, pos, Usymbols=stdUsymbols):
         """List of atom displacement formulas with custom parameter symbols.
 
-        pos        -- fractional coordinates of possibly equivalent site
-        Usymbols   -- 6 symbols for possible U matrix parameters
-
-        Return U element formulas in a dictionary where keys are from
-        ('U11','U22','U33','U12','U13','U23') or empty dictionary when
-        pos is not equivalent to generator.
+        Parameters
+        ----------
+        pos : array_like
+            Fractional coordinates of possibly equivalent site.
+        Usymbols : list, Optional
+            6 symbols for possible U matrix parameters, default is
+            ``["U11", "U22", "U33", "U12", "U13", "U23"]``.
+
+        Return
+        ------
+        Uformula : dict
+            U element formulas in a dictionary where keys are from
+            ``('U11','U22','U33','U12','U13','U23')`` or empty dictionary when
+            pos is not equivalent to generator.
         """
         # find pos in eqxyz
         idx = nearestSiteIndex(self.eqxyz, pos)
@@ -570,11 +691,17 @@ def UFormula(self, pos, Usymbols=stdUsymbols):
         return Uformula
 
     def eqIndex(self, pos):
-        """Index of the nearest generator equivalent site
+        """Index of the nearest generator equivalent site.
 
-        pos -- fractional coordinates
+        Parameters
+        ----------
+        pos : array_like
+            Fractional coordinates.
 
-        Return integer.
+        Return
+        ------
+        int
+            Index of the nearest generator equivalent site.
         """
         return nearestSiteIndex(self.eqxyz, pos)
 
@@ -585,34 +712,48 @@ def eqIndex(self, pos):
 
 
 class ExpandAsymmetricUnit(object):
-    """Expand asymmetric unit and anisotropic thermal displacement
-
-    Data members:
-        spacegroup  -- instance of SpaceGroup
-        corepos     -- list of positions in asymmetric unit,
-                       it may contain duplicates
-        coreUijs    -- thermal factors for corepos (defaults to zeros)
-        sgoffset    -- optional offset of space group origin [0, 0, 0]
-        eps         -- cutoff for equivalent positions
-    Calculated data members:
-        multiplicity -- multiplicity of each site in corepos
-        Uisotropy   -- bool flags for isotropic sites in corepos
-        expandedpos -- list of equivalent positions per each site in corepos
-        expandedUijs -- list of thermal factors per each site in corepos
+    """Expand asymmetric unit and anisotropic thermal displacement.
+
+    Parameters
+    ----------
+    spacegroup : SpaceGroup
+        Instance of `SpaceGroup`.
+    corepos : array_like
+        List of positions in asymmetric unit,
+        it may contain duplicates.
+    coreUijs : numpy.ndarray, Optional
+        Thermal factors for `corepos`.
+    sgoffset : list, Optional
+        Offset of space group origin ``[0, 0, 0]``. Default is ``[0, 0, 0]``.
+    eps : float, Optional
+        Cutoff for duplicate positions. Default is ``1.0e-5``.
+
+    Attributes
+    ----------
+    spacegroup : SpaceGroup
+        Instance of `SpaceGroup`.
+    corepos : array_like
+        List of positions in asymmetric unit,
+        it may contain duplicates.
+    coreUijs : numpy.ndarray
+        Thermal factors for `corepos`. Defaults to zeros.
+    sgoffset : numpy.ndarray
+        Offset of space group origin ``[0, 0, 0]``. Default to zeros.
+    eps : float
+        Cutoff for equivalent positions. Default is ``1.0e-5``.
+    multiplicity : list
+        Multiplicity of each site in `corepos`.
+    Uisotropy : list
+        Bool flags for isotropic sites in `corepos`.
+    expandedpos : list
+        List of equivalent positions per each site in `corepos`.
+    expandedUijs : list
+        List of thermal factors per each site in `corepos`.
     """
 
     # By design Atom instances are not accepted as arguments to keep
     # number of required imports low.
     def __init__(self, spacegroup, corepos, coreUijs=None, sgoffset=[0, 0, 0], eps=None):
-        """Initialize and calculate instance of ExpandAsymmetricUnit
-
-        spacegroup   -- instance of SpaceGroup
-        corepos      -- list of positions in asymmetric unit,
-                        it may contain duplicates
-        coreUijs     -- thermal factors for corepos (defaults to zeros)
-        sgoffset     -- offset of space group origin [0, 0, 0]
-        eps          -- cutoff for duplicate positions
-        """
         if eps is None:
             eps = epsilon
         # declare data members
@@ -643,17 +784,23 @@ def __init__(self, spacegroup, corepos, coreUijs=None, sgoffset=[0, 0, 0], eps=N
 # End of class ExpandAsymmetricUnit
 
 
-# Helper function for SymmetryConstraints class.  It may be useful
+# Helper function for SymmetryConstraints class. It may be useful
 # elsewhere therefore its name does not start with underscore.
 
 
 def pruneFormulaDictionary(eqdict):
     """Remove constant items from formula dictionary.
 
-    eqdict -- formula dictionary which maps standard variable symbols
-              ("x", "U11") to string formulas ("0", "-x3", "z7 +0.5")
+    Parameters
+    ----------
+    eqdict : dict
+        Formula dictionary which maps standard variable symbols
+        ``("x", "U11")`` to string formulas ``("0", "-x3", "z7 +0.5")``.
 
-    Return pruned formula dictionary.
+    Return
+    ------
+    dict
+        Pruned formula dictionary.
     """
     pruned = {}
     for smb, eq in eqdict.items():
@@ -663,41 +810,58 @@ def pruneFormulaDictionary(eqdict):
 
 
 class SymmetryConstraints(object):
-    """Generate symmetry constraints for specified positions
-
-    Data members:
-        spacegroup -- instance of SpaceGroup
-        positions  -- all positions to be constrained
-        Uijs       -- thermal factors for all positions (defaults to zeros)
-        sgoffset   -- optional offset of space group origin [0, 0, 0]
-        eps        -- cutoff for equivalent positions
-    Calculated data members:
-        corepos    -- list of of positions in the asymmetric unit
-        coremap    -- dictionary mapping indices of asymmetric core positions
-                      to indices of all symmetry related positions
-        poseqns    -- list of coordinate formula dictionaries per each site.
-                      Formula dictionary keys are from ("x", "y", "z") and
-                      the values are formatted as [[-]{x|y|z}%i] [{+|-}%g],
-                      for example: "x0", "-x3", "z7 +0.5", "0.25".
-        pospars    -- list of (xyz symbol, value) pairs
-        Ueqns      -- list of anisotropic atomic displacement formula
-                      dictionaries per each position.  Formula dictionary
-                      keys are from ('U11','U22','U33','U12','U13','U23')
-                      and the values are formatted as {[%g*][Uij%i]|0},
-                      for example: "U110", "0.5*U2213", "0"
-        Upars      -- list of (U symbol, value) pairs
-        Uisotropy  -- list of bool flags for isotropic thermal displacements
+    """Generate symmetry constraints for specified positions.
+
+    Parameters
+    ----------
+    spacegroup : SpaceGroup
+        Instance of `SpaceGroup`.
+    positions : array_like
+        List of all positions to be constrained.
+    Uijs : array_like, Optional
+        List of U matrices for all constrained positions.
+    sgoffset : list, Optional
+        Offset of space group origin ``[0, 0, 0]``. Default is ``[0, 0, 0]``.
+    eps : float, Optional
+        Cutoff for duplicate positions. Default is ``1.0e-5``.
+
+    Attributes
+    ----------
+    spacegroup : SpaceGroup
+        Instance of `SpaceGroup`.
+    positions : numpy.ndarray
+        All positions to be constrained.
+    Uijs : numpy.ndarray
+        Thermal factors for all positions. Defaults to zeros.
+    sgoffset : numpy.ndarray
+        Optional offset of space group origin ``[0, 0, 0]``.
+    eps : float
+        Cutoff for equivalent positions. Default is ``1.0e-5``.
+    corepos : list
+        List of of positions in the asymmetric unit.
+    coremap : dict
+        Dictionary mapping indices of asymmetric core positions
+        to indices of all symmetry related positions.
+    poseqns : list
+        List of coordinate formula dictionaries per each site.
+        Formula dictionary keys are from ``("x", "y", "z")`` and
+        the values are formatted as ``[[-]{x|y|z}%i] [{+|-}%g]``,
+        for example: ``x0``, ``-x3``, ``z7 +0.5``, ``0.25``.
+    pospars : list
+        List of ``(xyz symbol, value)`` pairs.
+    Ueqns : list
+        List of anisotropic atomic displacement formula
+        dictionaries per each position. Formula dictionary
+        keys are from ``('U11','U22','U33','U12','U13','U23')``
+        and the values are formatted as ``{[%g*][Uij%i]|0}``,
+        for example: ``U110``, ``0.5*U2213``, ``0``.
+    Upars : list
+        List of ``(U symbol, value)`` pairs.
+    Uisotropy : list
+        List of bool flags for isotropic thermal displacements.
     """
 
     def __init__(self, spacegroup, positions, Uijs=None, sgoffset=[0, 0, 0], eps=None):
-        """Initialize and calculate SymmetryConstraints.
-
-        spacegroup -- instance of SpaceGroup
-        positions  -- list of all positions to be constrained
-        Uijs       -- list of U matrices for all constrained positions
-        sgoffset   -- optional offset of space group origin [0, 0, 0]
-        eps        -- cutoff for equivalent positions
-        """
         if eps is None:
             eps = epsilon
         # fill in data members
@@ -738,7 +902,7 @@ def __init__(self, spacegroup, positions, Uijs=None, sgoffset=[0, 0, 0], eps=Non
         return
 
     def _findConstraints(self):
-        """Find constraints for positions and anisotropic displacements Uij"""
+        """Find constraints for positions and anisotropic displacements `Uij`."""
         numpos = len(self.positions)
         # canonical xyzsymbols and Usymbols
         xyzsymbols = [smbl + str(i) for i in range(numpos) for smbl in "xyz"]
@@ -796,11 +960,17 @@ def posparValues(self):
     def positionFormulas(self, xyzsymbols=None):
         """List of position formulas with custom parameter symbols.
 
-        xyzsymbols -- list of custom symbols used in formula strings
-
-        Return list of coordinate formulas dictionaries.  Formulas dictionary
-        keys are from ("x", "y", "z") and the values are formatted as
-        [[-]{symbol}] [{+|-}%g], for example: "x0", "-sym", "@7 +0.5", "0.25".
+        Parameters
+        ----------
+        xyzsymbols : list, Optional
+            List of custom symbols used in formula strings.
+
+        Return
+        ------
+        list
+            List of coordinate formulas dictionaries. Formulas dictionary
+            keys are from ``("x", "y", "z")`` and the values are formatted as
+            ``[[-]{symbol}] [{+|-}%g]``, for example: ``x0``, ``-sym``, ``@7 +0.5``, ``0.25``.
         """
         if not xyzsymbols:
             return list(self.poseqns)
@@ -825,11 +995,20 @@ def translatesymbol(matchobj):
 
     def positionFormulasPruned(self, xyzsymbols=None):
         """List of position formula dictionaries with constant items removed.
-        See also positionFormulas().
 
-        xyzsymbols -- list of custom symbols used in formula strings
+        See also
+        --------
+        positionFormulas()
+
+        Parameters
+        ----------
+        xyzsymbols : list, Optional
+            List of custom symbols used in formula strings.
 
-        Return list of coordinate formula dictionaries.
+        Return
+        ------
+        list
+            List of coordinate formula dictionaries.
         """
         rv = [pruneFormulaDictionary(eqns) for eqns in self.positionFormulas(xyzsymbols)]
         return rv
@@ -845,12 +1024,18 @@ def UparValues(self):
     def UFormulas(self, Usymbols=None):
         """List of atom displacement formulas with custom parameter symbols.
 
-        Usymbols -- list of custom symbols used in formula strings
-
-        Return list of atom displacement formula dictionaries per each site.
-        Formula dictionary keys are from ('U11','U22','U33','U12','U13','U23')
-        and the values are formatted as {[%g*][Usymbol]|0}, for example:
-        "U11", "0.5*@37", "0".
+        Parameters
+        ----------
+        Usymbols : list, Optional
+            List of custom symbols used in formula strings.
+
+        Return
+        ------
+        list
+            List of atom displacement formula dictionaries per each site.
+            Formula dictionary keys are from ``('U11','U22','U33','U12','U13','U23')``
+            and the values are formatted as ``{[%g*][Usymbol]|0}``, for example:
+            ``U11``, ``0.5*@37``, ``0``.
         """
         if not Usymbols:
             return list(self.Ueqns)
@@ -875,12 +1060,22 @@ def translatesymbol(matchobj):
 
     def UFormulasPruned(self, Usymbols=None):
         """List of atom displacement formula dictionaries with constant items
-        removed.  See also UFormulas().
-
-        Usymbols -- list of custom symbols used in formula strings
-
-        Return list of atom displacement formulas in tuples of
-        (U11, U22, U33, U12, U13, U23).
+        removed.
+
+        See Also
+        --------
+        UFormulas()
+
+        Parameters
+        ----------
+        Usymbols : list, Optional
+            List of custom symbols used in formula strings.
+
+        Return
+        ------
+        list
+            List of atom displacement formulas in tuples of
+            ``(U11, U22, U33, U12, U13, U23)``.
         """
         rv = [pruneFormulaDictionary(eqns) for eqns in self.UFormulas(Usymbols)]
         return rv
diff --git a/src/diffpy/structure/utils.py b/src/diffpy/structure/utils.py
index 823ce9da..e5fa3ce3 100644
--- a/src/diffpy/structure/utils.py
+++ b/src/diffpy/structure/utils.py
@@ -16,23 +16,19 @@
 """Small shared functions.
 """
 
-import numpy
-import six
+from collections.abc import Iterable as _Iterable
 
-if six.PY2:
-    from collections import Iterable as _Iterable
-else:
-    from collections.abc import Iterable as _Iterable
+import numpy
 
 
 def isiterable(obj):
-    """True if argument is iterable."""
+    """``True`` if argument is iterable."""
     rv = isinstance(obj, _Iterable)
     return rv
 
 
 def isfloat(s):
-    """True if argument can be converted to float"""
+    """``True`` if argument can be converted to float."""
     try:
         float(s)
         return True
@@ -43,12 +39,30 @@ def isfloat(s):
 
 def atomBareSymbol(smbl):
     """Remove atom type string stripped of isotope and ion charge symbols.
-    This removes blank and leading [0-9-] or trailing [1-9][+-] characters.
 
-    smbl -- atom type string such as "Cl-", "Ca2+" or "12-C".
+    This function removes any blank, isotope numbers (0-9), leading hyphens (-), and ion charge
+    symbols (1-9)(+-) from the given atom type string, returning only the bare element symbol.
 
-    Return bare element symbol.
+    Parameters
+    ----------
+    smbl : str
+        Atom type string that may include isotope numbers, ion charges, or hyphens.
+
+    Returns
+    -------
+    str
+        The bare element symbol.
+
+    Examples
+    --------
+    >>> atomBareSymbol("Cl-")
+    'Cl'
+    >>> atomBareSymbol("Ca2+")
+    'Ca'
+    >>> atomBareSymbol("12-C")
+    'C'
     """
+
     rv = smbl.strip().lstrip("0123456789-").rstrip("123456789+-")
     return rv
 
@@ -60,15 +74,15 @@ def _linkAtomAttribute(attrname, doc, toarray=numpy.array):
     """Create property wrapper that maps the specified atom attribute.
 
     The returned property object provides convenient access to atom
-    attributes from the owner Structure class.
+    attributes from the owner `Structure` class.
 
     Parameters
     ----------
     attrname : str
-        The string name of the Atom class attribute to be mapped.
+        The string name of the `Atom` class attribute to be mapped.
     doc : str
         The docstring for the property wrapper.
-    toarray : callable, optional
+    toarray : callable, Optional
         Factory function that converts list of attributes to `numpy.ndarray`.
         Use `numpy.char.array` for string attributes.
 


Test patch:
diff --git a/src/diffpy/structure/tests/test_p_cif.py b/src/diffpy/structure/tests/test_p_cif.py
index f066ad75..edd611f6 100644
--- a/src/diffpy/structure/tests/test_p_cif.py
+++ b/src/diffpy/structure/tests/test_p_cif.py
@@ -19,7 +19,6 @@
 import unittest
 
 import numpy
-import six
 
 from diffpy.structure import Structure
 from diffpy.structure.parsers import getParser
@@ -148,7 +147,7 @@ def test_parseFile(self):
         self.assertEqual("C1", c1.label)
         # filename with unicode encoding
         hasbs = "\\" in self.graphiteciffile
-        uciffile = six.u(self.graphiteciffile.replace("\\", "/"))
+        uciffile = self.graphiteciffile.replace("\\", "/")
         if hasbs:  # pragma: no cover
             uciffile = uciffile.replace("/", "\\")
         ugraphite = P_cif().parseFile(uciffile)