writing-code-snippets.rst 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. .. _writing-code-snippets_ref:
  2. ==========================
  3. How to write code snippets
  4. ==========================
  5. Users learn from example. So, whether you're writing a docstring or a user guide,
  6. include examples that illustrate the relevant APIs. Your examples should run
  7. out-of-the-box so that users can copy them and adapt them to their own needs.
  8. This page describes how to write code snippets so that they're tested in CI.
  9. .. note::
  10. The examples in this guide use reStructuredText. If you're writing
  11. Markdown, use MyST syntax. To learn more, read the
  12. `MyST documentation <https://myst-parser.readthedocs.io/en/latest/syntax/roles-and-directives.html#directives-a-block-level-extension-point>`_.
  13. -----------------
  14. Types of examples
  15. -----------------
  16. There are three types of examples: *doctest-style*, *code-output-style*, and *literalinclude*.
  17. *doctest-style* examples
  18. ========================
  19. *doctest-style* examples mimic interactive Python sessions. ::
  20. .. doctest::
  21. >>> def is_even(x):
  22. ... return (x % 2) == 0
  23. >>> is_even(0)
  24. True
  25. >>> is_even(1)
  26. False
  27. They're rendered like this:
  28. .. doctest::
  29. >>> def is_even(x):
  30. ... return (x % 2) == 0
  31. >>> is_even(0)
  32. True
  33. >>> is_even(1)
  34. False
  35. .. tip::
  36. If you're writing docstrings, exclude `.. doctest::` to simplify your code. ::
  37. Example:
  38. >>> def is_even(x):
  39. ... return (x % 2) == 0
  40. >>> is_even(0)
  41. True
  42. >>> is_even(1)
  43. False
  44. *code-output-style* examples
  45. ============================
  46. *code-output-style* examples contain ordinary Python code. ::
  47. .. testcode::
  48. def is_even(x):
  49. return (x % 2) == 0
  50. print(is_even(0))
  51. print(is_even(1))
  52. .. testoutput::
  53. True
  54. False
  55. They're rendered like this:
  56. .. testcode::
  57. def is_even(x):
  58. return (x % 2) == 0
  59. print(is_even(0))
  60. print(is_even(1))
  61. .. testoutput::
  62. True
  63. False
  64. *literalinclude* examples
  65. =========================
  66. *literalinclude* examples display Python modules. ::
  67. .. literalinclude:: ./doc_code/example_module.py
  68. :language: python
  69. :start-after: __is_even_begin__
  70. :end-before: __is_even_end__
  71. .. literalinclude:: ./doc_code/example_module.py
  72. :language: python
  73. They're rendered like this:
  74. .. literalinclude:: ./doc_code/example_module.py
  75. :language: python
  76. :start-after: __is_even_begin__
  77. :end-before: __is_even_end__
  78. ---------------------------------------
  79. Which type of example should you write?
  80. ---------------------------------------
  81. There's no hard rule about which style you should use. Choose the style that best
  82. illustrates your API.
  83. .. tip::
  84. If you're not sure which style to use, use *code-block-style*.
  85. When to use *doctest-style*
  86. ===========================
  87. If you're writing a small example that emphasizes object representations, or if you
  88. want to print intermediate objects, use *doctest-style*. ::
  89. .. doctest::
  90. >>> import ray
  91. >>> ds = ray.data.range(100)
  92. >>> ds.schema()
  93. Column Type
  94. ------ ----
  95. id int64
  96. >>> ds.take(5)
  97. [{'id': 0}, {'id': 1}, {'id': 2}, {'id': 3}, {'id': 4}]
  98. When to use *code-block-style*
  99. ==============================
  100. If you're writing a longer example, or if object representations aren't relevant to your example, use *code-block-style*. ::
  101. .. testcode::
  102. import pandas as pd
  103. import ray
  104. from ray.train.batch_predictor import BatchPredictor
  105. def calculate_accuracy(df):
  106. return pd.DataFrame({"correct": df["preds"] == df["label"]})
  107. # Create a batch predictor that returns identity as the predictions.
  108. batch_pred = BatchPredictor.from_pandas_udf(
  109. lambda data: pd.DataFrame({"preds": data["feature_1"]}))
  110. # Create a dummy dataset.
  111. ds = ray.data.from_pandas(pd.DataFrame({
  112. "feature_1": [1, 2, 3], "label": [1, 2, 3]}))
  113. # Execute batch prediction using this predictor.
  114. predictions = batch_pred.predict(ds,
  115. feature_columns=["feature_1"], keep_columns=["label"])
  116. # Calculate final accuracy
  117. correct = predictions.map_batches(calculate_accuracy)
  118. print(f"Final accuracy: {correct.sum(on='correct') / correct.count()}")
  119. .. testoutput::
  120. Final accuracy: 1.0
  121. When to use *literalinclude*
  122. ============================
  123. If you're writing an end-to-end examples and your examples doesn't contain outputs, use
  124. *literalinclude*.
  125. -----------------------------------
  126. How to handle hard-to-test examples
  127. -----------------------------------
  128. When is it okay to not test an example?
  129. =======================================
  130. You don't need to test examples that depend on external systems like Weights and Biases.
  131. Skipping *doctest-style* examples
  132. =================================
  133. To skip a *doctest-style* example, append `# doctest: +SKIP` to your Python code. ::
  134. .. doctest::
  135. >>> import ray
  136. >>> ray.data.read_images("s3://private-bucket") # doctest: +SKIP
  137. Skipping *code-block-style* examples
  138. ====================================
  139. To skip a *code-block-style* example, add `:skipif: True` to the `testoutput` block. ::
  140. .. testcode::
  141. :skipif: True
  142. from ray.air.integrations.wandb import WandbLoggerCallback
  143. callback = WandbLoggerCallback(
  144. project="Optimization_Project",
  145. api_key_file=...,
  146. log_config=True
  147. )
  148. ----------------------------------------------
  149. How to handle long or non-determnistic outputs
  150. ----------------------------------------------
  151. If your Python code is non-deterministic, or if your output is excessively long, you may want to skip all or part of an output.
  152. Ignoring *doctest-style* outputs
  153. ================================
  154. To ignore parts of a *doctest-style* output, replace problematic sections with ellipses. ::
  155. >>> import ray
  156. >>> ray.data.read_images("example://image-datasets/simple")
  157. Dataset(
  158. num_blocks=...,
  159. num_rows=...,
  160. schema={image: numpy.ndarray(shape=(32, 32, 3), dtype=uint8)}
  161. )
  162. To ignore an output altogether, write a *code-block-style* snippet. Don't use `# doctest: +SKIP`.
  163. Ignoring *code-block-style* outputs
  164. ===================================
  165. If parts of your output are long or non-deterministic, replace problematic sections
  166. with ellipses. ::
  167. .. testcode::
  168. import ray
  169. ds = ray.data.read_images("example://image-datasets/simple")
  170. print(ds)
  171. .. testoutput::
  172. Dataset(
  173. num_blocks=...,
  174. num_rows=...,
  175. schema={image: numpy.ndarray(shape=(32, 32, 3), dtype=uint8)}
  176. )
  177. If your output is nondeterministic and you want to display a sample output, add
  178. `:options: +MOCK`. ::
  179. .. testcode::
  180. import random
  181. print(random.random())
  182. .. testoutput::
  183. :options: +MOCK
  184. 0.969461416250246
  185. If your output is hard to test and you don't want to display a sample output, use
  186. ellipses and `:hide:`. ::
  187. .. testcode::
  188. print("This output is hidden and untested")
  189. .. testoutput::
  190. :hide:
  191. ...
  192. ------------------------------
  193. How to test examples with GPUs
  194. ------------------------------
  195. To configure Bazel to run an example with GPUs, complete the following steps:
  196. #. Open the corresponding ``BUILD`` file. If your example is in the ``doc/`` folder,
  197. open ``doc/BUILD``. If your example is in the ``python/`` folder, open a file like
  198. ``python/ray/train/BUILD``.
  199. #. Locate the ``doctest`` rule. It looks like this: ::
  200. doctest(
  201. files = glob(
  202. include=["source/**/*.rst"],
  203. ),
  204. size = "large",
  205. tags = ["team:none"]
  206. )
  207. #. Add the file that contains your example to the list of excluded files. ::
  208. doctest(
  209. files = glob(
  210. include=["source/**/*.rst"],
  211. exclude=["source/data/requires-gpus.rst"]
  212. ),
  213. tags = ["team:none"]
  214. )
  215. #. If it doesn't already exist, create a ``doctest`` rule with ``gpu`` set to ``True``. ::
  216. doctest(
  217. files = [],
  218. tags = ["team:none"],
  219. gpu = True
  220. )
  221. #. Add the file that contains your example to the GPU rule. ::
  222. doctest(
  223. files = ["source/data/requires-gpus.rst"]
  224. size = "large",
  225. tags = ["team:none"],
  226. gpu = True
  227. )
  228. For a practical example, see ``doc/BUILD`` or ``python/ray/train/BUILD``.
  229. ----------------------------
  230. How to locally test examples
  231. ----------------------------
  232. To locally test examples, install the Ray fork of `pytest-sphinx`.
  233. .. code-block:: bash
  234. pip install git+https://github.com/ray-project/pytest-sphinx
  235. Then, run pytest on a module, docstring, or user guide.
  236. .. code-block:: bash
  237. pytest --doctest-modules python/ray/data/read_api.py
  238. pytest --doctest-modules python/ray/data/read_api.py::ray.data.read_api.range
  239. pytest --doctest-modules doc/source/data/getting-started.rst