소스 검색

Merge pull request #7150 from tswast/issue4498-readthedocs

python: publish sphinx docs to read the docs
David L. Jones 5 년 전
부모
커밋
4ff0fb841c

+ 22 - 0
.readthedocs.yml

@@ -0,0 +1,22 @@
+# .readthedocs.yml
+# Read the Docs configuration file
+# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
+
+# Required
+version: 2
+
+sphinx:
+  configuration: python/docs/conf.py
+  fail_on_warning: false
+
+# Setup build requirements for docs.
+# Use conda so that we can install the latest libprotobuf package without
+# having to build from scratch just for docs builds.
+conda:
+  environment: python/docs/environment.yml
+
+python:
+  version: 3.7
+  install:
+    - method: setuptools
+      path: python

+ 16 - 1
python/docs/conf.py

@@ -41,7 +41,7 @@
 # add these directories to sys.path here. If the directory is relative to the
 # add these directories to sys.path here. If the directory is relative to the
 # documentation root, use os.path.abspath to make it absolute, like shown here.
 # documentation root, use os.path.abspath to make it absolute, like shown here.
 #
 #
-# import os
+import os
 # import sys
 # import sys
 # sys.path.insert(0, os.path.abspath('.'))
 # sys.path.insert(0, os.path.abspath('.'))
 import google.protobuf
 import google.protobuf
@@ -69,6 +69,7 @@ release = google.protobuf.__version__
 # ones.
 # ones.
 extensions = [
 extensions = [
   "sphinx.ext.autosummary",
   "sphinx.ext.autosummary",
+  "sphinx.ext.ifconfig",
   "sphinx.ext.intersphinx",
   "sphinx.ext.intersphinx",
   "sphinxcontrib.napoleon",
   "sphinxcontrib.napoleon",
 ]
 ]
@@ -237,3 +238,17 @@ autosummary_generate = True
 
 
 # Example configuration for intersphinx: refer to the Python standard library.
 # Example configuration for intersphinx: refer to the Python standard library.
 intersphinx_mapping = {"https://docs.python.org/": None}
 intersphinx_mapping = {"https://docs.python.org/": None}
+
+# -- Config values -----------------------------------------------------------
+# The setup() function is needed to add configuration values to the Sphinx
+# builder. We use this to show a banner when built on Read the Docs.
+# https://www.sphinx-doc.org/en/master/usage/extensions/ifconfig.html
+
+def setup(app):
+  app.add_config_value(
+    "build_env",
+    # Read the Docs sets a READTHEDOCS environment during builds.
+    # https://docs.readthedocs.io/en/stable/builds.html#build-environment
+    "readthedocs" if os.getenv("READTHEDOCS") else "",
+    "env"
+  )

+ 12 - 0
python/docs/generate_docs.py

@@ -95,6 +95,18 @@ TOC_TEMPLATE = """.. START REFTOC, generated by generate_docs.py.
 
 
 AUTOMODULE_TEMPLATE = """.. DO NOT EDIT, generated by generate_docs.py.
 AUTOMODULE_TEMPLATE = """.. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 {module}
 {module}
 {underline}
 {underline}
 
 

+ 12 - 0
python/docs/google/protobuf.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf
 google.protobuf
 ===============
 ===============
 
 

+ 12 - 0
python/docs/google/protobuf/any_pb2.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.any_pb2
 google.protobuf.any_pb2
 =======================
 =======================
 
 

+ 12 - 0
python/docs/google/protobuf/descriptor.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.descriptor
 google.protobuf.descriptor
 ==========================
 ==========================
 
 

+ 12 - 0
python/docs/google/protobuf/descriptor_database.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.descriptor_database
 google.protobuf.descriptor_database
 ===================================
 ===================================
 
 

+ 12 - 0
python/docs/google/protobuf/descriptor_pb2.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.descriptor_pb2
 google.protobuf.descriptor_pb2
 ==============================
 ==============================
 
 

+ 12 - 0
python/docs/google/protobuf/descriptor_pool.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.descriptor_pool
 google.protobuf.descriptor_pool
 ===============================
 ===============================
 
 

+ 12 - 0
python/docs/google/protobuf/duration_pb2.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.duration_pb2
 google.protobuf.duration_pb2
 ============================
 ============================
 
 

+ 12 - 0
python/docs/google/protobuf/empty_pb2.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.empty_pb2
 google.protobuf.empty_pb2
 =========================
 =========================
 
 

+ 12 - 0
python/docs/google/protobuf/field_mask_pb2.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.field_mask_pb2
 google.protobuf.field_mask_pb2
 ==============================
 ==============================
 
 

+ 12 - 0
python/docs/google/protobuf/json_format.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.json_format
 google.protobuf.json_format
 ===========================
 ===========================
 
 

+ 12 - 0
python/docs/google/protobuf/message.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.message
 google.protobuf.message
 =======================
 =======================
 
 

+ 12 - 0
python/docs/google/protobuf/message_factory.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.message_factory
 google.protobuf.message_factory
 ===============================
 ===============================
 
 

+ 12 - 0
python/docs/google/protobuf/proto_builder.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.proto_builder
 google.protobuf.proto_builder
 =============================
 =============================
 
 

+ 12 - 0
python/docs/google/protobuf/reflection.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.reflection
 google.protobuf.reflection
 ==========================
 ==========================
 
 

+ 12 - 0
python/docs/google/protobuf/service.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.service
 google.protobuf.service
 =======================
 =======================
 
 

+ 12 - 0
python/docs/google/protobuf/service_reflection.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.service_reflection
 google.protobuf.service_reflection
 ==================================
 ==================================
 
 

+ 12 - 0
python/docs/google/protobuf/struct_pb2.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.struct_pb2
 google.protobuf.struct_pb2
 ==========================
 ==========================
 
 

+ 12 - 0
python/docs/google/protobuf/symbol_database.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.symbol_database
 google.protobuf.symbol_database
 ===============================
 ===============================
 
 

+ 12 - 0
python/docs/google/protobuf/text_encoding.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.text_encoding
 google.protobuf.text_encoding
 =============================
 =============================
 
 

+ 12 - 0
python/docs/google/protobuf/text_format.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.text_format
 google.protobuf.text_format
 ===========================
 ===========================
 
 

+ 12 - 0
python/docs/google/protobuf/timestamp_pb2.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.timestamp_pb2
 google.protobuf.timestamp_pb2
 =============================
 =============================
 
 

+ 12 - 0
python/docs/google/protobuf/type_pb2.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.type_pb2
 google.protobuf.type_pb2
 ========================
 ========================
 
 

+ 12 - 0
python/docs/google/protobuf/wrappers_pb2.rst

@@ -1,5 +1,17 @@
 .. DO NOT EDIT, generated by generate_docs.py.
 .. DO NOT EDIT, generated by generate_docs.py.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 google.protobuf.wrappers_pb2
 google.protobuf.wrappers_pb2
 ============================
 ============================
 
 

+ 12 - 0
python/docs/index.rst

@@ -3,6 +3,18 @@
    You can adapt this file completely to your liking, but it should at least
    You can adapt this file completely to your liking, but it should at least
    contain the root `toctree` directive.
    contain the root `toctree` directive.
 
 
+.. ifconfig:: build_env == 'readthedocs'
+
+   .. warning::
+
+      You are reading the documentation for the `latest committed changes
+      <https://github.com/protocolbuffers/protobuf/tree/master/python>`_ of
+      the `Protocol Buffers package for Python
+      <https://developers.google.com/protocol-buffers/docs/pythontutorial>`_.
+      Some features may not yet be released. Read the documentation for the
+      latest released package at `googleapis.dev
+      <https://googleapis.dev/python/protobuf/latest/>`_.
+
 Protocol Buffers Python API Reference
 Protocol Buffers Python API Reference
 =====================================
 =====================================
 
 

+ 38 - 13
python/setup.py

@@ -19,17 +19,23 @@ from distutils.command.build_py import build_py as _build_py
 from distutils.command.clean import clean as _clean
 from distutils.command.clean import clean as _clean
 from distutils.spawn import find_executable
 from distutils.spawn import find_executable
 
 
+
+current_dir = os.path.dirname(__file__)
+current_dir_relative = os.path.relpath(current_dir)
+src_dir = os.path.abspath(os.path.join(current_dir, "..", "src"))
+vsprojects_dir = os.path.abspath(os.path.join(current_dir, "..", "vsprojects"))
+
 # Find the Protocol Compiler.
 # Find the Protocol Compiler.
 if 'PROTOC' in os.environ and os.path.exists(os.environ['PROTOC']):
 if 'PROTOC' in os.environ and os.path.exists(os.environ['PROTOC']):
   protoc = os.environ['PROTOC']
   protoc = os.environ['PROTOC']
-elif os.path.exists("../src/protoc"):
-  protoc = "../src/protoc"
-elif os.path.exists("../src/protoc.exe"):
-  protoc = "../src/protoc.exe"
-elif os.path.exists("../vsprojects/Debug/protoc.exe"):
-  protoc = "../vsprojects/Debug/protoc.exe"
-elif os.path.exists("../vsprojects/Release/protoc.exe"):
-  protoc = "../vsprojects/Release/protoc.exe"
+elif os.path.exists(os.path.join(src_dir, "protoc")):
+  protoc = os.path.join(src_dir, "protoc")
+elif os.path.exists(os.path.join(src_dir, "protoc.exe")):
+  protoc = os.path.join(src_dir, "protoc.exe")
+elif os.path.exists(os.path.join(vsprojects_dir, "Debug", "protoc.exe")):
+  protoc = os.path.join(vsprojects_dir, "Debug", "protoc.exe")
+elif os.path.exists(os.path.join(vsprojects_dir, "Release", "protoc.exe")):
+  protoc = os.path.join(vsprojects_dir, "Release", "protoc.exe")
 else:
 else:
   protoc = find_executable("protoc")
   protoc = find_executable("protoc")
 
 
@@ -40,7 +46,7 @@ def GetVersion():
   Do not import google.protobuf.__init__ directly, because an installed
   Do not import google.protobuf.__init__ directly, because an installed
   protobuf library may be loaded instead."""
   protobuf library may be loaded instead."""
 
 
-  with open(os.path.join('google', 'protobuf', '__init__.py')) as version_file:
+  with open(os.path.join(current_dir, 'google', 'protobuf', '__init__.py')) as version_file:
     exec(version_file.read(), globals())
     exec(version_file.read(), globals())
     global __version__
     global __version__
     return __version__
     return __version__
@@ -51,15 +57,21 @@ def generate_proto(source, require = True):
   .proto file.  Does nothing if the output already exists and is newer than
   .proto file.  Does nothing if the output already exists and is newer than
   the input."""
   the input."""
 
 
+  original_source = source
+  source = source.replace("../src", src_dir)
+
   if not require and not os.path.exists(source):
   if not require and not os.path.exists(source):
     return
     return
 
 
-  output = source.replace(".proto", "_pb2.py").replace("../src/", "")
+  output = os.path.join(
+    current_dir,
+    original_source.replace(".proto", "_pb2.py").replace("../src/", "")
+  )
 
 
   if (not os.path.exists(output) or
   if (not os.path.exists(output) or
       (os.path.exists(source) and
       (os.path.exists(source) and
        os.path.getmtime(source) > os.path.getmtime(output))):
        os.path.getmtime(source) > os.path.getmtime(output))):
-    print("Generating %s..." % output)
+    print("Generating %s..." % os.path.relpath(output))
 
 
     if not os.path.exists(source):
     if not os.path.exists(source):
       sys.stderr.write("Can't find required file: %s\n" % source)
       sys.stderr.write("Can't find required file: %s\n" % source)
@@ -71,7 +83,13 @@ def generate_proto(source, require = True):
           "or install the binary package.\n")
           "or install the binary package.\n")
       sys.exit(-1)
       sys.exit(-1)
 
 
-    protoc_command = [ protoc, "-I../src", "-I.", "--python_out=.", source ]
+    protoc_command = [
+      protoc,
+      "-I{}".format(src_dir),
+      "-I{}".format(current_dir),
+      "--python_out={}".format(current_dir),
+      source,
+    ]
     if subprocess.call(protoc_command) != 0:
     if subprocess.call(protoc_command) != 0:
       sys.exit(-1)
       sys.exit(-1)
 
 
@@ -116,7 +134,7 @@ def GenerateUnittestProtos():
 class clean(_clean):
 class clean(_clean):
   def run(self):
   def run(self):
     # Delete generated files in the code tree.
     # Delete generated files in the code tree.
-    for (dirpath, dirnames, filenames) in os.walk("."):
+    for (dirpath, dirnames, filenames) in os.walk(current_dir):
       for filename in filenames:
       for filename in filenames:
         filepath = os.path.join(dirpath, filename)
         filepath = os.path.join(dirpath, filename)
         if filepath.endswith("_pb2.py") or filepath.endswith(".pyc") or \
         if filepath.endswith("_pb2.py") or filepath.endswith(".pyc") or \
@@ -269,7 +287,14 @@ if __name__ == '__main__':
         "Programming Language :: Python :: 3.7",
         "Programming Language :: Python :: 3.7",
         ],
         ],
       namespace_packages=['google'],
       namespace_packages=['google'],
+      # package_dir is required when setup.py is not run from the python/
+      # directory (such as from the ReadTheDocs build). See
+      # https://setuptools.readthedocs.io/en/latest/setuptools.html#using-find-packages
+      # package_dir must be a relative path. See:
+      # https://stackoverflow.com/a/53547931/101923
+      package_dir={"": current_dir_relative},
       packages=find_packages(
       packages=find_packages(
+          where=current_dir,
           exclude=[
           exclude=[
               'import_test_package',
               'import_test_package',
           ],
           ],