You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by fo...@apache.org on 2019/05/31 17:43:48 UTC

[avro] branch master updated: AVRO-2391 Refactor Py3 Setup (#514)

This is an automated email from the ASF dual-hosted git repository.

fokko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git


The following commit(s) were added to refs/heads/master by this push:
     new f33e36f  AVRO-2391 Refactor Py3 Setup (#514)
f33e36f is described below

commit f33e36f70f5f149b38b9056273f584184591c23f
Author: Michael A. Smith <mi...@smith-li.com>
AuthorDate: Fri May 31 13:43:42 2019 -0400

    AVRO-2391 Refactor Py3 Setup (#514)
    
    The main purpose of this change is to simplify and modernize the setup code without really changing its behavior.
    
    The main change is that I moved most of the setup code into the declarative setup.cfg, where I hope it is somewhat clearer.
    I also fleshed out the setup.py commands so that the build.sh and setup.py have parity -- that is, the build.sh is entirely implemented using setup.py.
---
 lang/py3/{build.sh => MANIFEST.in} |  55 +---------
 lang/py3/build.sh                  |  56 +++-------
 lang/py3/setup.cfg                 |  65 ++++++++++++
 lang/py3/setup.py                  | 209 +++++++++++++++----------------------
 4 files changed, 171 insertions(+), 214 deletions(-)

diff --git a/lang/py3/build.sh b/lang/py3/MANIFEST.in
old mode 100755
new mode 100644
similarity index 54%
copy from lang/py3/build.sh
copy to lang/py3/MANIFEST.in
index fdb457a..acdbd3b
--- a/lang/py3/build.sh
+++ b/lang/py3/MANIFEST.in
@@ -1,5 +1,3 @@
-#!/bin/bash
-
 # Licensed to the Apache Software Foundation (ASF) under one or more
 # contributor license agreements.  See the NOTICE file distributed with
 # this work for additional information regarding copyright ownership.
@@ -15,51 +13,8 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-set -e # exit on error
-
-function usage {
-  echo "Usage: $0 {test|dist|clean}"
-  exit 1
-}
-
-if [ $# -eq 0 ]
-then
-  usage
-fi
-
-if [ -f VERSION.txt ]
-then
-  VERSION=`cat VERSION.txt`
-else
-  VERSION=`cat ../../share/VERSION.txt`
-fi
-
-for target in "$@"
-do
-
-function do_clean(){
-  python3 setup.py clean
-  rm -rvf dist avro_python3.egg-info avro/*.avsc avro/VERSION.txt avro/__pycache__/ avro/tests/interop.avsc avro/tests/__pycache__/
-}
-
-case "$target" in
-  test)
-    python3 setup.py test
-    ;;
-
-  dist)
-     python3 setup.py sdist
-     cp -r dist ../../dist/py3
-    ;;
-
-  clean)
-    do_clean
-    ;;
-
-  *)
-    usage
-esac
-
-done
-
-exit 0
+include avro/HandshakeRequest.avsc
+include avro/HandshakeResponse.avsc
+include avro/VERSION.txt
+include avro/LICENSE
+include avro/NOTICE
diff --git a/lang/py3/build.sh b/lang/py3/build.sh
index fdb457a..e443985 100755
--- a/lang/py3/build.sh
+++ b/lang/py3/build.sh
@@ -17,49 +17,23 @@
 
 set -e # exit on error
 
-function usage {
+usage() {
   echo "Usage: $0 {test|dist|clean}"
-  exit 1
 }
 
-if [ $# -eq 0 ]
-then
-  usage
-fi
-
-if [ -f VERSION.txt ]
-then
-  VERSION=`cat VERSION.txt`
-else
-  VERSION=`cat ../../share/VERSION.txt`
-fi
-
-for target in "$@"
-do
-
-function do_clean(){
-  python3 setup.py clean
-  rm -rvf dist avro_python3.egg-info avro/*.avsc avro/VERSION.txt avro/__pycache__/ avro/tests/interop.avsc avro/tests/__pycache__/
-}
-
-case "$target" in
-  test)
-    python3 setup.py test
-    ;;
-
-  dist)
-     python3 setup.py sdist
-     cp -r dist ../../dist/py3
-    ;;
-
-  clean)
-    do_clean
-    ;;
-
-  *)
+main() {
+  local target
+  if (( $# == 0 )); then
     usage
-esac
-
-done
+    return 1
+  fi
+  for target; do
+    case "$target" in
+      clean|dist|test) : ;;
+      *) usage; return 1 ;;
+    esac
+  done
+  python3 setup.py "$@"
+}
 
-exit 0
+main "$@"
diff --git a/lang/py3/setup.cfg b/lang/py3/setup.cfg
new file mode 100644
index 0000000..9d1f437
--- /dev/null
+++ b/lang/py3/setup.cfg
@@ -0,0 +1,65 @@
+##
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+##
+# https://setuptools.readthedocs.io/en/latest/setuptools.html#configuring-setup-using-setup-cfg-files
+[metadata]
+name = avro-python3
+version = file: avro/VERSION.txt
+description = Avro is a serialization and RPC framework.
+long_description = file: README.txt
+keywords =
+    avro
+    serialization
+    rpc
+author = Apache Avro
+author_email = dev@avro.apache.org
+url = http://avro.apache.org/
+license = Apache License 2.0
+classifiers =
+    License :: OSI Approved :: Apache Software License
+    Programming Language :: Python :: 3 :: Only
+    Programming Language :: Python :: 3.4
+    Programming Language :: Python :: 3.5
+    Programming Language :: Python :: 3.6
+    Programming Language :: Python :: 3.7
+    Programming Language :: Python :: 3.8
+
+[options]
+package_dir =
+    avro = avro
+include_package_data = true
+packages = avro
+install_requires =
+zip_safe = true
+scripts =
+    scripts/avro
+python_requires = >=3.4
+test_suite = avro.tests.run_tests
+
+[options.package_data]
+avro =
+    HandshakeRequest.avsc
+    HandshakeResponse.avsc
+    VERSION.txt
+    LICENSE
+    NOTICE
+
+[options.extras_require]
+snappy = snappy
+
+[aliases]
+dist = sdist --dist-dir ../../dist/py3
diff --git a/lang/py3/setup.py b/lang/py3/setup.py
index 1b31223..6eb6e2e 100755
--- a/lang/py3/setup.py
+++ b/lang/py3/setup.py
@@ -26,133 +26,96 @@ The avro-python3 software is designed for Python 3, but this file and the packag
 https://pypi.org/project/avro-python3/
 """
 
-
+import distutils.command.clean
+import distutils.file_util
+import distutils.dir_util
+import distutils.log
+import fnmatch
 import os
-import shutil
-import stat
-import sys
 
 from setuptools import setup
 
-VERSION_FILE_NAME = 'VERSION.txt'
-LICENSE_FILE_NAME = 'LICENSE'
-NOTICE_FILE_NAME = 'NOTICE'
-
-def RunsFromSourceDist():
-  """Tests whether setup.py is invoked from a source distribution.
-
-  Returns:
-    True if setup.py runs from a source distribution.
-    False otherwise, ie. if setup.py runs from the SVN trunk.
-  """
-  setup_file_path = os.path.abspath(__file__)
-  # If a file PKG-INFO exists as a sibling of setup.py,
-  # assume we are running as source distribution:
-  pkg_info_file_path = \
-      os.path.join(os.path.dirname(setup_file_path), 'PKG-INFO')
-  return os.path.exists(pkg_info_file_path)
-
-
-def SetupSources():
-  """Prepares the source directory.
-
-  Runs when setup.py is invoked from the Avro SVN/Git source.
-  """
-  # Avro lang/py3/ source directory:
-  py3_dir = os.path.dirname(os.path.abspath(__file__))
-
-  # Avro top-level source directory:
-  root_dir = os.path.dirname(os.path.dirname(py3_dir))
-
-  # Read and copy Avro version:
-  version_file_path = os.path.join(root_dir, 'share', VERSION_FILE_NAME)
-  with open(version_file_path, 'r') as f:
-    avro_version = f.read().strip()
-  shutil.copy(
-      src=version_file_path,
-      dst=os.path.join(py3_dir, 'avro', VERSION_FILE_NAME),
-  )
-
-  # Copy necessary avsc files:
-  avsc_file_path = os.path.join(
-      root_dir, 'share', 'schemas',
-      'org', 'apache', 'avro', 'ipc', 'HandshakeRequest.avsc')
-  shutil.copy(
-      src=avsc_file_path,
-      dst=os.path.join(py3_dir, 'avro', 'HandshakeRequest.avsc'),
-  )
-
-  avsc_file_path = os.path.join(
-      root_dir, 'share', 'schemas',
-      'org', 'apache', 'avro', 'ipc', 'HandshakeResponse.avsc')
-  shutil.copy(
-      src=avsc_file_path,
-      dst=os.path.join(py3_dir, 'avro', 'HandshakeResponse.avsc'),
-  )
-
-  avsc_file_path = os.path.join(
-      root_dir, 'share', 'test', 'schemas', 'interop.avsc')
-  shutil.copy(
-      src=avsc_file_path,
-      dst=os.path.join(py3_dir, 'avro', 'tests', 'interop.avsc'),
-  )
-
-
-def ReadVersion():
-  """Returns: the content of the Avro version file."""
-  setup_file_path = os.path.abspath(__file__)
-  install_dir = os.path.dirname(setup_file_path)
-  version_file_path = os.path.join(install_dir, 'avro', VERSION_FILE_NAME)
-  with open(version_file_path, 'rt') as f:
-    avro_version = f.read().strip()
-  return avro_version
-
-
-def Main():
-  if not RunsFromSourceDist():
-    SetupSources()
-
-  avro_version = ReadVersion()
-
-  setup(
-      name = 'avro-python3',
-      version = avro_version,
-      packages = ['avro'],
-      package_dir = {'avro': 'avro'},
-      scripts = ['scripts/avro'],
-
-      package_data = {
-          'avro': [
-              'HandshakeRequest.avsc',
-              'HandshakeResponse.avsc',
-              VERSION_FILE_NAME,
-              LICENSE_FILE_NAME,
-              NOTICE_FILE_NAME,
-          ],
-      },
-
-      test_suite='avro.tests.run_tests',
-      tests_require=[],
-
-      # metadata for upload to PyPI
-      author = 'Apache Avro',
-      author_email = 'dev@avro.apache.org',
-      description = 'Avro is a serialization and RPC framework.',
-      license = 'Apache License 2.0',
-      keywords = 'avro serialization rpc',
-      url = 'http://avro.apache.org/',
-      classifiers=[
-          'License :: OSI Approved :: Apache Software License',
-          'Programming Language :: Python :: 3 :: Only',
-          'Programming Language :: Python :: 3.4',
-          'Programming Language :: Python :: 3.5',
-          'Programming Language :: Python :: 3.6',
-          'Programming Language :: Python :: 3.7',
-          'Programming Language :: Python :: 3.8',
-      ],
-      python_requires='>=3.4',
-  )
+_HERE = os.path.dirname(os.path.abspath(__file__))
+_AVRO_DIR = os.path.join(_HERE, 'avro')
+_VERSION_FILE_NAME = 'VERSION.txt'
+
+def _is_distribution():
+    """Tests whether setup.py is invoked from a distribution.
+
+    Returns:
+        True if setup.py runs from a distribution.
+        False otherwise, ie. if setup.py runs from a version control work tree.
+    """
+    # If a file PKG-INFO exists as a sibling of setup.py,
+    # assume we are running as source distribution:
+    return os.path.exists(os.path.join(_HERE, 'PKG-INFO'))
+
+
+def _generate_package_data():
+    """Generate package data.
+
+    This data will already exist in a distribution package,
+    so this function only runs for local version control work tree.
+    """
+    distutils.log.info('Generating package data')
+
+    # Avro top-level source directory:
+    root_dir = os.path.dirname(os.path.dirname(_HERE))
+
+    # Create a PEP440 compliant version file.
+    version_file_path = os.path.join(root_dir, 'share', _VERSION_FILE_NAME)
+    with open(version_file_path) as vin:
+        version = vin.read().replace('-', '+')
+    with open(os.path.join(_AVRO_DIR, _VERSION_FILE_NAME), 'w') as vout:
+        vout.write(version)
+
+    # Copy necessary avsc files:
+    avsc_files = (
+        (('schemas', 'org', 'apache', 'avro', 'ipc', 'HandshakeRequest.avsc'), ''),
+        (('schemas', 'org', 'apache', 'avro', 'ipc', 'HandshakeResponse.avsc'), ''),
+        (('test', 'schemas', 'interop.avsc'), ('tests',)),
+    )
+
+    for src, dst in avsc_files:
+        src = os.path.join(root_dir, 'share', *src)
+        dst = os.path.join(_AVRO_DIR, *dst)
+        distutils.file_util.copy_file(src, dst)
+
+
+class CleanCommand(distutils.command.clean.clean):
+    """A command to clean up install artifacts and replaceable, generated files."""
+
+    def _replaceable(self):
+        """Get the list of files to delete."""
+        for name in ('dist', 'avro_python3.egg-info', os.path.join(_AVRO_DIR, _VERSION_FILE_NAME)):
+            if os.path.exists(name):
+                yield name
+        for root, dirnames, filenames in os.walk(_AVRO_DIR):
+            if '__pycache__' in dirnames:
+                dirnames.remove('__pycache__')
+                yield os.path.join(root, '__pycache__')
+            for name in fnmatch.filter(filenames, '*.avsc'):
+                yield os.path.join(root, name)
+
+    def run(self):
+        super().run()
+        for name in self._replaceable():
+            if self.dry_run:
+                distutils.log.info('Would remove %s', name)
+            elif os.path.isdir(name):
+                # distutils logs this for us
+                distutils.dir_util.remove_tree(name)
+            else:
+                distutils.log.info('Removing %s', name)
+                os.remove(name)
+
+
+def main():
+    if not _is_distribution():
+        _generate_package_data()
+
+    setup(cmdclass={"clean": CleanCommand})
 
 
 if __name__ == '__main__':
-  Main()
+    main()