Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

conftest.py 5.7 KB

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  1. import random
  2. import numpy as np
  3. import pytest
  4. import torch
  5. from common_utils import (
  6. CUDA_NOT_AVAILABLE_MSG,
  7. IN_FBCODE,
  8. IN_OSS_CI,
  9. IN_RE_WORKER,
  10. MPS_NOT_AVAILABLE_MSG,
  11. OSS_CI_GPU_NO_CUDA_MSG,
  12. )
  13. def pytest_configure(config):
  14. # register an additional marker (see pytest_collection_modifyitems)
  15. config.addinivalue_line("markers", "needs_cuda: mark for tests that rely on a CUDA device")
  16. config.addinivalue_line("markers", "needs_mps: mark for tests that rely on a MPS device")
  17. config.addinivalue_line("markers", "dont_collect: mark for tests that should not be collected")
  18. config.addinivalue_line("markers", "opcheck_only_one: only opcheck one parametrization")
  19. def pytest_collection_modifyitems(items):
  20. # This hook is called by pytest after it has collected the tests (google its name to check out its doc!)
  21. # We can ignore some tests as we see fit here, or add marks, such as a skip mark.
  22. #
  23. # Typically, here, we try to optimize CI time. In particular, the GPU CI instances don't need to run the
  24. # tests that don't need CUDA, because those tests are extensively tested in the CPU CI instances already.
  25. # This is true for both OSS CI and the fbcode internal CI.
  26. # In the fbcode CI, we have an additional constraint: we try to avoid skipping tests. So instead of relying on
  27. # pytest.mark.skip, in fbcode we literally just remove those tests from the `items` list, and it's as if
  28. # these tests never existed.
  29. out_items = []
  30. for item in items:
  31. # The needs_cuda mark will exist if the test was explicitly decorated with
  32. # the @needs_cuda decorator. It will also exist if it was parametrized with a
  33. # parameter that has the mark: for example if a test is parametrized with
  34. # @pytest.mark.parametrize('device', cpu_and_cuda())
  35. # the "instances" of the tests where device == 'cuda' will have the 'needs_cuda' mark,
  36. # and the ones with device == 'cpu' won't have the mark.
  37. needs_cuda = item.get_closest_marker("needs_cuda") is not None
  38. needs_mps = item.get_closest_marker("needs_mps") is not None
  39. if needs_cuda and not torch.cuda.is_available():
  40. # In general, we skip cuda tests on machines without a GPU
  41. # There are special cases though, see below
  42. item.add_marker(pytest.mark.skip(reason=CUDA_NOT_AVAILABLE_MSG))
  43. if needs_mps and not torch.backends.mps.is_available():
  44. item.add_marker(pytest.mark.skip(reason=MPS_NOT_AVAILABLE_MSG))
  45. if IN_FBCODE:
  46. # fbcode doesn't like skipping tests, so instead we just don't collect the test
  47. # so that they don't even "exist", hence the continue statements.
  48. if not needs_cuda and IN_RE_WORKER:
  49. # The RE workers are the machines with GPU, we don't want them to run CPU-only tests.
  50. continue
  51. if needs_cuda and not torch.cuda.is_available():
  52. # On the test machines without a GPU, we want to ignore the tests that need cuda.
  53. # TODO: something more robust would be to do that only in a sandcastle instance,
  54. # so that we can still see the test being skipped when testing locally from a devvm
  55. continue
  56. if needs_mps and not torch.backends.mps.is_available():
  57. # Same as above, but for MPS
  58. continue
  59. elif IN_OSS_CI:
  60. # Here we're not in fbcode, so we can safely collect and skip tests.
  61. if not needs_cuda and torch.cuda.is_available():
  62. # Similar to what happens in RE workers: we don't need the OSS CI GPU machines
  63. # to run the CPU-only tests.
  64. item.add_marker(pytest.mark.skip(reason=OSS_CI_GPU_NO_CUDA_MSG))
  65. if item.get_closest_marker("dont_collect") is not None:
  66. # currently, this is only used for some tests we're sure we don't want to run on fbcode
  67. continue
  68. out_items.append(item)
  69. items[:] = out_items
  70. def pytest_sessionfinish(session, exitstatus):
  71. # This hook is called after all tests have run, and just before returning an exit status.
  72. # We here change exit code 5 into 0.
  73. #
  74. # 5 is issued when no tests were actually run, e.g. if you use `pytest -k some_regex_that_is_never_matched`.
  75. #
  76. # Having no test being run for a given test rule is a common scenario in fbcode, and typically happens on
  77. # the GPU test machines which don't run the CPU-only tests (see pytest_collection_modifyitems above). For
  78. # example `test_transforms.py` doesn't contain any CUDA test at the time of
  79. # writing, so on a GPU test machine, testpilot would invoke pytest on this file and no test would be run.
  80. # This would result in pytest returning 5, causing testpilot to raise an error.
  81. # To avoid this, we transform this 5 into a 0 to make testpilot happy.
  82. if exitstatus == 5:
  83. session.exitstatus = 0
  84. @pytest.fixture(autouse=True)
  85. def prevent_leaking_rng():
  86. # Prevent each test from leaking the rng to all other test when they call
  87. # torch.manual_seed() or random.seed() or np.random.seed().
  88. # Note: the numpy rngs should never leak anyway, as we never use
  89. # np.random.seed() and instead rely on np.random.RandomState instances (see
  90. # issue #4247). We still do it for extra precaution.
  91. torch_rng_state = torch.get_rng_state()
  92. builtin_rng_state = random.getstate()
  93. nunmpy_rng_state = np.random.get_state()
  94. if torch.cuda.is_available():
  95. cuda_rng_state = torch.cuda.get_rng_state()
  96. yield
  97. torch.set_rng_state(torch_rng_state)
  98. random.setstate(builtin_rng_state)
  99. np.random.set_state(nunmpy_rng_state)
  100. if torch.cuda.is_available():
  101. torch.cuda.set_rng_state(cuda_rng_state)
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...