timerit 1.1.0__tar.gz → 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ include requirements/*.txt
@@ -1,33 +1,43 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: timerit
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: A powerful multiline alternative to timeit
5
- Home-page: https://github.com/Erotemic/timerit
6
- Author: Jon Crall
7
- Author-email: erotemic@gmail.com
8
- License: Apache 2
9
- Platform: UNKNOWN
5
+ Author-email: Jon Crall <erotemic@gmail.com>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/Erotemic/timerit
10
8
  Classifier: Development Status :: 5 - Production/Stable
11
9
  Classifier: Intended Audience :: Developers
12
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
- Classifier: Topic :: Utilities
14
- Classifier: License :: OSI Approved :: Apache Software License
15
- Classifier: Programming Language :: Python :: 3.6
16
- Classifier: Programming Language :: Python :: 3.7
17
- Classifier: Programming Language :: Python :: 3.8
18
- Classifier: Programming Language :: Python :: 3.9
19
10
  Classifier: Programming Language :: Python :: 3.10
20
11
  Classifier: Programming Language :: Python :: 3.11
21
- Requires-Python: >=3.6
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Classifier: Programming Language :: Python :: 3.15
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Classifier: Topic :: Utilities
18
+ Requires-Python: >=3.10
22
19
  Description-Content-Type: text/x-rst
20
+ License-File: LICENSE
23
21
  Provides-Extra: all
24
- Provides-Extra: all-strict
22
+ Requires-Dist: pandas; extra == "all"
23
+ Requires-Dist: kwplot; extra == "all"
24
+ Provides-Extra: docs
25
+ Requires-Dist: sphinx>=5.0.1; extra == "docs"
26
+ Requires-Dist: sphinx-autobuild>=2021.3.14; extra == "docs"
27
+ Requires-Dist: sphinx_rtd_theme>=1.0.0; extra == "docs"
28
+ Requires-Dist: sphinxcontrib-napoleon>=0.7; extra == "docs"
29
+ Requires-Dist: sphinx-autoapi>=1.8.4; extra == "docs"
30
+ Requires-Dist: Pygments>=2.9.0; extra == "docs"
31
+ Requires-Dist: myst_parser>=0.18.0; extra == "docs"
32
+ Requires-Dist: sphinx-reredirects>=0.0.1; extra == "docs"
25
33
  Provides-Extra: optional
26
- Provides-Extra: optional-strict
27
- Provides-Extra: runtime-strict
34
+ Requires-Dist: pandas; extra == "optional"
35
+ Requires-Dist: kwplot; extra == "optional"
28
36
  Provides-Extra: tests
29
- Provides-Extra: tests-strict
30
- License-File: LICENSE
37
+ Requires-Dist: xdoctest>=1.1.0; extra == "tests"
38
+ Requires-Dist: pytest>=6.2.5; extra == "tests"
39
+ Requires-Dist: pytest-cov>=3.0.0; extra == "tests"
40
+ Dynamic: license-file
31
41
 
32
42
 
33
43
  |GithubActions| |Appveyor| |Codecov| |Pypi| |Downloads| |ReadTheDocs|
@@ -36,7 +46,7 @@ License-File: LICENSE
36
46
  Timerit
37
47
  =======
38
48
 
39
- A powerful multiline alternative to Python's builtin ``timeit`` module.
49
+ A powerful multiline alternative to Python's builtin `timeit <https://docs.python.org/3/library/timeit.html>`_ module.
40
50
 
41
51
  Docs are published at https://timerit.readthedocs.io/en/latest/ but this README
42
52
  and code comments contain a walkthrough.
@@ -97,7 +107,7 @@ Here's what each of the numbers means:
97
107
  that you can get slow times if the something in the background is consuming
98
108
  resources, so you're generally only interested in the fastest times. This
99
109
  idea is also described in the
100
- `timeit <https://docs.python.org/3/library/timeit.html#timeit.Timer.repeat>`_ docs.
110
+ `timeit docs <https://docs.python.org/3/library/timeit.html#timeit.Timer.repeat>`_.
101
111
 
102
112
  - "best=616.740 µs": How long the fastest iteration took to run. For the reasons
103
113
  described above, this is usually the most consistent number, and the primary
@@ -310,6 +320,16 @@ Benchmark Recipe
310
320
  ax.set_ylabel('y-variable description')
311
321
 
312
322
 
323
+ Related Work
324
+ ============
325
+
326
+ * `timeit <https://docs.python.org/3/library/timeit.html>`_: The builtin timeit module for profiling single statements.
327
+
328
+ * `line_profiler <https://github.com/pyutils/line_profiler>`_: Line-by-line profiling.
329
+
330
+ * `ubelt <https://github.com/Erotemic/ubelt>`_: This library was original developed as a component of ubelt, but has since become a standalone module.
331
+
332
+
313
333
  .. |Travis| image:: https://img.shields.io/travis/Erotemic/timerit/master.svg?label=Travis%20CI
314
334
  :target: https://travis-ci.org/Erotemic/timerit?branch=master
315
335
  .. |Codecov| image:: https://codecov.io/github/Erotemic/timerit/badge.svg?branch=master&service=github
@@ -331,5 +351,3 @@ Benchmark Recipe
331
351
 
332
352
  .. _PYTHONSTARTUP: https://docs.python.org/3/using/cmdline.html?highlight=pythonstartup#envvar-PYTHONSTARTUP
333
353
 
334
-
335
-
@@ -5,7 +5,7 @@
5
5
  Timerit
6
6
  =======
7
7
 
8
- A powerful multiline alternative to Python's builtin ``timeit`` module.
8
+ A powerful multiline alternative to Python's builtin `timeit <https://docs.python.org/3/library/timeit.html>`_ module.
9
9
 
10
10
  Docs are published at https://timerit.readthedocs.io/en/latest/ but this README
11
11
  and code comments contain a walkthrough.
@@ -66,7 +66,7 @@ Here's what each of the numbers means:
66
66
  that you can get slow times if the something in the background is consuming
67
67
  resources, so you're generally only interested in the fastest times. This
68
68
  idea is also described in the
69
- `timeit <https://docs.python.org/3/library/timeit.html#timeit.Timer.repeat>`_ docs.
69
+ `timeit docs <https://docs.python.org/3/library/timeit.html#timeit.Timer.repeat>`_.
70
70
 
71
71
  - "best=616.740 µs": How long the fastest iteration took to run. For the reasons
72
72
  described above, this is usually the most consistent number, and the primary
@@ -279,6 +279,16 @@ Benchmark Recipe
279
279
  ax.set_ylabel('y-variable description')
280
280
 
281
281
 
282
+ Related Work
283
+ ============
284
+
285
+ * `timeit <https://docs.python.org/3/library/timeit.html>`_: The builtin timeit module for profiling single statements.
286
+
287
+ * `line_profiler <https://github.com/pyutils/line_profiler>`_: Line-by-line profiling.
288
+
289
+ * `ubelt <https://github.com/Erotemic/ubelt>`_: This library was original developed as a component of ubelt, but has since become a standalone module.
290
+
291
+
282
292
  .. |Travis| image:: https://img.shields.io/travis/Erotemic/timerit/master.svg?label=Travis%20CI
283
293
  :target: https://travis-ci.org/Erotemic/timerit?branch=master
284
294
  .. |Codecov| image:: https://codecov.io/github/Erotemic/timerit/badge.svg?branch=master&service=github
@@ -0,0 +1,135 @@
1
+ [build-system]
2
+ build-backend = "setuptools.build_meta"
3
+ requires = [
4
+ "setuptools>=41.0.1",
5
+ "setuptools>=77",
6
+ ]
7
+
8
+ [project]
9
+ name = "timerit"
10
+ description = "A powerful multiline alternative to timeit"
11
+ license = "Apache-2.0"
12
+ license-files = [
13
+ "LICENSE",
14
+ ]
15
+ authors = [ { name = "Jon Crall", email = "erotemic@gmail.com" } ]
16
+ requires-python = ">=3.10"
17
+ classifiers = [
18
+ "Development Status :: 5 - Production/Stable",
19
+ "Intended Audience :: Developers",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Programming Language :: Python :: 3.14",
25
+ "Programming Language :: Python :: 3.15",
26
+ "Topic :: Software Development :: Libraries :: Python Modules",
27
+ "Topic :: Utilities",
28
+ ]
29
+ dynamic = [
30
+ "dependencies",
31
+ "optional-dependencies",
32
+ "readme",
33
+ "version",
34
+ ]
35
+ urls.Homepage = "https://github.com/Erotemic/timerit"
36
+
37
+ [tool.setuptools]
38
+ include-package-data = true
39
+ dynamic.dependencies.file = [
40
+ "requirements/runtime.txt",
41
+ ]
42
+ dynamic.optional-dependencies.all.file = [
43
+ "requirements/optional.txt",
44
+ ]
45
+ dynamic.optional-dependencies.docs.file = [
46
+ "requirements/docs.txt",
47
+ ]
48
+ dynamic.optional-dependencies.optional.file = [
49
+ "requirements/optional.txt",
50
+ ]
51
+ dynamic.optional-dependencies.tests.file = [
52
+ "requirements/tests.txt",
53
+ ]
54
+ dynamic.readme.file = [
55
+ "README.rst",
56
+ ]
57
+ dynamic.readme.content-type = "text/x-rst"
58
+ dynamic.version.attr = "timerit.__version__"
59
+ package-data."*" = [
60
+ "requirements/*.txt",
61
+ ]
62
+ package-data.timerit = [
63
+ "py.typed",
64
+ ]
65
+ packages.find.where = [
66
+ ".",
67
+ ]
68
+ packages.find.include = [
69
+ "timerit*",
70
+ ]
71
+
72
+ [tool.mypy]
73
+ ignore_missing_imports = true
74
+
75
+ [tool.pytest]
76
+ ini_options.addopts = "-p no:doctest --xdoctest --xdoctest-style=google --ignore-glob=setup.py --ignore-glob=dev --ignore-glob=docs"
77
+ ini_options.norecursedirs = ".git ignore build __pycache__ dev _skbuild docs"
78
+ ini_options.filterwarnings = [
79
+ "default",
80
+ "ignore:.*No cfgstr given in Cacher constructor or call.*:Warning",
81
+ "ignore:.*Define the __nice__ method for.*:Warning",
82
+ "ignore:.*private pytest class or function.*:Warning",
83
+ ]
84
+
85
+ [tool.coverage]
86
+ run.branch = true
87
+ report.exclude_lines = [
88
+ ".* # nocover",
89
+ ".* # pragma: no cover",
90
+ ".*if six.PY2:",
91
+ "^ *pass *$",
92
+ "^ *raise",
93
+ "def __repr__",
94
+ "if __name__ == .__main__.:",
95
+ "if _debug:",
96
+ "if 0:",
97
+ "if trace is not None",
98
+ "pragma: no cover",
99
+ "raise AssertionError",
100
+ "raise NotImplementedError",
101
+ "verbose = .*",
102
+ ]
103
+ report.omit = [
104
+ "*/setup.py",
105
+ "timerit/__main__.py",
106
+ ]
107
+
108
+ [tool.xcookie]
109
+ tags = [
110
+ "erotemic",
111
+ "purepy",
112
+ "github",
113
+ ]
114
+ mod_name = "timerit"
115
+ repo_name = "timerit"
116
+ rel_mod_parent_dpath = "."
117
+ os = [
118
+ "linux",
119
+ "osx",
120
+ "win",
121
+ ]
122
+ min_python = "3.10"
123
+ version = "{mod_dpath}/__init__.py::__version__"
124
+ url = "https://github.com/Erotemic/timerit"
125
+ author = "Jon Crall"
126
+ author_email = "erotemic@gmail.com"
127
+ description = "A powerful multiline alternative to timeit"
128
+ license = "Apache 2"
129
+ dev_status = "stable"
130
+ typed = true
131
+ workspace_members = []
132
+ workspace_sync_versions = false
133
+ use_setup_py = false
134
+ use_pyproject_requirements = false
135
+ enable_gpg = true
@@ -0,0 +1,8 @@
1
+ sphinx >= 5.0.1
2
+ sphinx-autobuild >= 2021.3.14
3
+ sphinx_rtd_theme >= 1.0.0
4
+ sphinxcontrib-napoleon >= 0.7
5
+ sphinx-autoapi >= 1.8.4
6
+ Pygments >= 2.9.0
7
+ myst_parser >= 0.18.0
8
+ sphinx-reredirects >= 0.0.1
@@ -0,0 +1,2 @@
1
+ pandas
2
+ kwplot
@@ -0,0 +1,3 @@
1
+ xdoctest >= 1.1.0
2
+ pytest >= 6.2.5
3
+ pytest-cov >= 3.0.0
@@ -0,0 +1,164 @@
1
+ from timerit.benchmarker import Benchmarker
2
+
3
+
4
+ def test_benchmarker_heterogeneous_signatures_and_adapters():
5
+ calls = []
6
+ adapter_calls = []
7
+
8
+ bm = Benchmarker(num_trials=2, bestof=1, record_samples=False, verbose=0)
9
+
10
+ @bm.register
11
+ def direct(x):
12
+ calls.append(('direct', x))
13
+
14
+ @bm.register
15
+ def adapted(value):
16
+ calls.append(('adapted', value))
17
+
18
+ @bm.register_data_adapter(for_method='adapted')
19
+ def adapt(x):
20
+ adapter_calls.append(x)
21
+ return {'value': x + 10}
22
+
23
+ bm.set_basis({'x': [1, 2]})
24
+ bm.run()
25
+
26
+ assert calls.count(('direct', 1)) == 2
27
+ assert calls.count(('direct', 2)) == 2
28
+ assert calls.count(('adapted', 11)) == 2
29
+ assert calls.count(('adapted', 12)) == 2
30
+ assert adapter_calls == [1, 1, 2, 2]
31
+ assert len(bm.stats) == 4
32
+ assert len(bm.rows) == 4
33
+
34
+
35
+ def test_benchmarker_records_robust_samples():
36
+ bm = Benchmarker(num_trials=4, bestof=2, record_samples=True, verbose=0)
37
+
38
+ @bm.register
39
+ def method1(n):
40
+ return n + 1
41
+
42
+ @bm.register
43
+ def method2(n):
44
+ return n * 2
45
+
46
+ bm.set_basis({'n': [1, 2]})
47
+ bm.run()
48
+
49
+ # 2 methods * 2 parameter values * (4 trials / bestof 2)
50
+ assert len(bm.rows) == 8
51
+ assert len(bm.stats) == 4
52
+ assert all('time' in row for row in bm.rows)
53
+ assert all(row['mean_speedup_vs_slowest'] >= 1 for row in bm.stats)
54
+ assert all(row['min_speedup_vs_slowest'] >= 1 for row in bm.stats)
55
+
56
+
57
+ def test_benchmarker_allows_method_only_benchmark():
58
+ bm = Benchmarker(num_trials=1, bestof=1, record_samples=False, verbose=0)
59
+
60
+ @bm.register
61
+ def first():
62
+ pass
63
+
64
+ @bm.register
65
+ def second():
66
+ pass
67
+
68
+ bm.set_basis({})
69
+ bm.run()
70
+
71
+ assert {row['method'] for row in bm.stats} == {'first', 'second'}
72
+ assert len(bm.stats) == 2
73
+
74
+
75
+ def test_benchmarker_run_does_not_require_plot_configuration():
76
+ bm = Benchmarker(num_trials=1, bestof=1, verbose=0)
77
+
78
+ @bm.register
79
+ def method(n):
80
+ return n
81
+
82
+ bm.set_basis({'n': [1]})
83
+ result = bm.run()
84
+ assert result is bm
85
+
86
+
87
+ def test_benchmarker_rejects_reserved_basis_name():
88
+ bm = Benchmarker(verbose=0)
89
+ try:
90
+ bm.set_basis({'method': ['foo']})
91
+ except ValueError:
92
+ pass
93
+ else:
94
+ raise AssertionError('expected method basis name to be reserved')
95
+
96
+
97
+ def test_benchmarker_callable_object_requires_or_accepts_name():
98
+ class CallableMethod:
99
+ def __call__(self, n):
100
+ return n
101
+
102
+ bm = Benchmarker(num_trials=1, bestof=1, verbose=0)
103
+ method = CallableMethod()
104
+
105
+ try:
106
+ bm.register(method)
107
+ except TypeError:
108
+ pass
109
+ else:
110
+ raise AssertionError('unnamed callable object should require name=')
111
+
112
+ bm.register(method, name='callable_method')
113
+ bm.set_basis({'n': [1]})
114
+ bm.run()
115
+ assert bm.stats[0]['method'] == 'callable_method'
116
+
117
+
118
+ def test_benchmarker_rejects_adapter_for_unknown_method():
119
+ bm = Benchmarker(num_trials=1, bestof=1, verbose=0)
120
+
121
+ @bm.register
122
+ def known(n):
123
+ return n
124
+
125
+ @bm.register_data_adapter(for_method='typo')
126
+ def adapter(n):
127
+ return {'n': n}
128
+
129
+ bm.set_basis({'n': [1]})
130
+ try:
131
+ bm.run()
132
+ except KeyError as ex:
133
+ assert 'typo' in str(ex)
134
+ else:
135
+ raise AssertionError('unknown adapter target should be rejected')
136
+
137
+
138
+ def test_benchmarker_plot_configuration_can_change_after_run():
139
+ bm = Benchmarker(num_trials=1, bestof=1, verbose=0)
140
+
141
+ @bm.register
142
+ def first(n):
143
+ return n
144
+
145
+ @bm.register
146
+ def second(n):
147
+ return n
148
+
149
+ bm.set_basis({'n': [1, 2]})
150
+ bm.run()
151
+ bm.set_plot_semantics(x='n', hue='method')
152
+
153
+ # Plot metadata is derived from stored statistics after measurement rather
154
+ # than being baked into the timing rows during run(). This helper requires
155
+ # pandas, so only check the independence at the plain-data level here.
156
+ assert all('hue_key' not in row for row in bm.rows)
157
+ assert all('hue_key' not in row for row in bm.stats)
158
+
159
+ def test_benchmarker_is_not_top_level_api():
160
+ import timerit
161
+
162
+ assert 'Benchmarker' not in timerit.__all__
163
+ assert not hasattr(timerit, 'Benchmarker')
164
+
@@ -0,0 +1,2 @@
1
+ def test_import():
2
+ import timerit