easydev 0.13.3__tar.gz → 0.15.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.
Files changed (53) hide show
  1. easydev-0.15.0/PKG-INFO +222 -0
  2. easydev-0.15.0/README.rst +184 -0
  3. {easydev-0.13.3 → easydev-0.15.0}/easydev/appdirs.py +0 -3
  4. {easydev-0.13.3 → easydev-0.15.0}/easydev/browser.py +6 -10
  5. {easydev-0.13.3 → easydev-0.15.0}/easydev/chunks.py +0 -6
  6. {easydev-0.13.3 → easydev-0.15.0}/easydev/codecs.py +1 -1
  7. {easydev-0.13.3 → easydev-0.15.0}/easydev/config_tools.py +6 -6
  8. {easydev-0.13.3 → easydev-0.15.0}/easydev/console.py +1 -1
  9. {easydev-0.13.3 → easydev-0.15.0}/easydev/copybutton.py +1 -1
  10. {easydev-0.13.3 → easydev-0.15.0}/easydev/decorators.py +5 -5
  11. {easydev-0.13.3 → easydev-0.15.0}/easydev/easytest.py +18 -3
  12. {easydev-0.13.3 → easydev-0.15.0}/easydev/logging_tools.py +0 -1
  13. {easydev-0.13.3 → easydev-0.15.0}/easydev/misc.py +3 -9
  14. {easydev-0.13.3 → easydev-0.15.0}/easydev/multicore.py +8 -7
  15. {easydev-0.13.3 → easydev-0.15.0}/easydev/paths.py +6 -7
  16. {easydev-0.13.3 → easydev-0.15.0}/easydev/platform.py +12 -20
  17. {easydev-0.13.3 → easydev-0.15.0}/easydev/sphinx_themes.py +1 -1
  18. {easydev-0.13.3 → easydev-0.15.0}/easydev/tools.py +13 -14
  19. {easydev-0.13.3 → easydev-0.15.0}/easydev/url.py +3 -6
  20. {easydev-0.13.3 → easydev-0.15.0}/pyproject.toml +6 -4
  21. easydev-0.13.3/PKG-INFO +0 -92
  22. easydev-0.13.3/README.rst +0 -57
  23. {easydev-0.13.3 → easydev-0.15.0}/COPYING +0 -0
  24. {easydev-0.13.3 → easydev-0.15.0}/easydev/__init__.py +0 -0
  25. {easydev-0.13.3 → easydev-0.15.0}/easydev/dependencies.py +0 -0
  26. {easydev-0.13.3 → easydev-0.15.0}/easydev/doc.py +0 -0
  27. {easydev-0.13.3 → easydev-0.15.0}/easydev/md5tools.py +0 -0
  28. {easydev-0.13.3 → easydev-0.15.0}/easydev/options.py +0 -0
  29. {easydev-0.13.3 → easydev-0.15.0}/easydev/profiler.py +0 -0
  30. {easydev-0.13.3 → easydev-0.15.0}/easydev/progressbar.py +0 -0
  31. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/__init__.py +0 -0
  32. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/copybutton.js +0 -0
  33. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/cno/google_footer.html +0 -0
  34. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/cno/google_head.html +0 -0
  35. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/cno/index.html +0 -0
  36. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/cno/indexsidebar.html +0 -0
  37. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/cno/layout.html +0 -0
  38. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/cno/static/bgfooter.png +0 -0
  39. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/cno/static/bgtop.png +0 -0
  40. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/cno/static/software.css_t +0 -0
  41. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/cno/static/warning.jpg +0 -0
  42. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/cno/theme.conf +0 -0
  43. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/standard/google_footer.html +0 -0
  44. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/standard/google_head.html +0 -0
  45. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/standard/index.html +0 -0
  46. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/standard/indexsidebar.html +0 -0
  47. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/standard/layout.html +0 -0
  48. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/standard/static/bgfooter.png +0 -0
  49. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/standard/static/bgtop.png +0 -0
  50. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/standard/static/software.css_t +0 -0
  51. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/standard/static/warning.jpg +0 -0
  52. {easydev-0.13.3 → easydev-0.15.0}/easydev/share/themes/standard/theme.conf +0 -0
  53. {easydev-0.13.3 → easydev-0.15.0}/easydev/timer.py +0 -0
@@ -0,0 +1,222 @@
1
+ Metadata-Version: 2.4
2
+ Name: easydev
3
+ Version: 0.15.0
4
+ Summary: Common utilities to ease development of Python packages
5
+ License-Expression: BSD-3-Clause
6
+ License-File: COPYING
7
+ Keywords: config,decorators,development
8
+ Author: Thomas Cokelaer
9
+ Author-email: thomas.cokelaer@pasteur.fr
10
+ Requires-Python: >=3.9,<4.0
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Education
13
+ Classifier: Intended Audience :: End Users/Desktop
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: BSD License
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
26
+ Classifier: Topic :: Scientific/Engineering :: Information Analysis
27
+ Requires-Dist: colorama (>=0.4.6,<0.5.0)
28
+ Requires-Dist: colorlog (>=6.8.2,<7.0.0)
29
+ Requires-Dist: line-profiler (>=5.0.0,<6.0.0)
30
+ Requires-Dist: pexpect (>=4.9.0,<5.0.0)
31
+ Requires-Dist: platformdirs (>=4.2.0,<5.0.0)
32
+ Project-URL: Documentation, https://easydev.readthedocs.io
33
+ Project-URL: Homepage, https://easydev.readthedocs.io
34
+ Project-URL: Issues, https://github.com/cokelaer/easydev/issues
35
+ Project-URL: Repository, https://github.com/cokelaer/easydev
36
+ Description-Content-Type: text/x-rst
37
+
38
+ easydev
39
+ ##########
40
+
41
+ .. image:: https://badge.fury.io/py/easydev.svg
42
+ :target: https://pypi.python.org/pypi/easydev
43
+
44
+ .. image:: https://github.com/cokelaer/easydev/actions/workflows/main.yml/badge.svg
45
+ :target: https://github.com/cokelaer/easydev/actions/workflows/main.yml
46
+
47
+ .. image:: https://coveralls.io/repos/cokelaer/easydev/badge.svg?branch=main
48
+ :target: https://coveralls.io/r/cokelaer/easydev?branch=main
49
+
50
+ .. image:: https://static.pepy.tech/personalized-badge/easydev?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads
51
+ :target: https://pepy.tech/projects/easydev
52
+
53
+ :documentation: http://easydev-python.readthedocs.io/en/latest/
54
+ :contributions: Please join https://github.com/cokelaer/easydev
55
+ :source: Please use https://github.com/cokelaer/easydev
56
+ :issues: Please use https://github.com/cokelaer/easydev/issues
57
+ :Python version supported: 3.9, 3.10, 3.11, 3.12, 3.13, 3.14
58
+
59
+ Overview
60
+ --------
61
+
62
+ The `easydev <http://pypi.python.org/pypi/easydev/>`_ package provides
63
+ miscellaneous utility functions and classes that are repeatedly useful during
64
+ the development of Python packages. The goal is to help developers speed up
65
+ their work by providing ready-to-use tools for common tasks such as parameter
66
+ validation, logging, progress bars, configuration files, multiprocessing, and
67
+ more.
68
+
69
+ It has been used as an incubator for other packages (e.g.,
70
+ `colormap <http://pypi.python.org/pypi/colormap>`_) and is used in projects
71
+ such as `bioservices <https://pypi.python.org/pypi/bioservices>`_,
72
+ `sequana <https://sequana.readthedocs.io>`_, and
73
+ `GDSCTools <https://gdsctools.readthedocs.io>`_.
74
+
75
+ Installation
76
+ ------------
77
+
78
+ Install the latest release from PyPI::
79
+
80
+ pip install easydev
81
+
82
+ Features
83
+ --------
84
+
85
+ - **Parameter validation** – ``check_param_in_list``, ``check_range``
86
+ - **Dictionary utilities** – ``swapdict``, ``AttrDict`` (access dict keys as attributes, supports nested dicts)
87
+ - **Logging** – coloured logging via ``Logging`` class
88
+ - **Progress bar** – ``Progress`` works in Python, IPython, and Jupyter notebooks
89
+ - **Timer** – measure elapsed time with the ``Timer`` context manager
90
+ - **Profiling** – ``do_profile`` decorator using ``line_profiler``
91
+ - **Configuration files** – ``CustomConfig`` and ``DynamicConfigParser`` for INI-style config management
92
+ - **Shell commands** – ``shellcmd`` and ``execute`` wrappers around subprocess/pexpect
93
+ - **File utilities** – ``touch``, ``mkdirs``, ``md5``
94
+ - **Multiprocessing** – ``MultiProcessing`` class for easy parallel job execution
95
+ - **Codecs** – ``to_list``, ``list2string`` and other conversion helpers
96
+ - **URL utilities** – ``isurl_reachable`` and related helpers
97
+ - **Sphinx integration** – bundled Sphinx theme and ``copybutton`` extension
98
+
99
+ Quick Start
100
+ -----------
101
+
102
+ Parameter validation::
103
+
104
+ from easydev import check_param_in_list, check_range
105
+
106
+ check_param_in_list("on", ["on", "off"]) # passes silently
107
+ check_range(0.5, 0, 1) # passes silently
108
+
109
+ AttrDict – access nested dictionary keys as attributes::
110
+
111
+ from easydev import AttrDict
112
+
113
+ d = AttrDict(**{"server": {"host": "localhost", "port": 8080}})
114
+ print(d.server.host) # localhost
115
+ d.server.port = 9090
116
+
117
+ Coloured logging::
118
+
119
+ from easydev import Logging
120
+
121
+ logger = Logging("myapp", "WARNING")
122
+ logger.warning("something went wrong")
123
+ logger.debug("not shown at WARNING level")
124
+ logger.level = "DEBUG"
125
+ logger.debug("now it is shown")
126
+
127
+ Progress bar::
128
+
129
+ from easydev import Progress
130
+
131
+ pb = Progress(100)
132
+ for i in range(100):
133
+ # do work here
134
+ pb.animate(i + 1)
135
+
136
+ Timer::
137
+
138
+ from easydev import Timer
139
+ import time
140
+
141
+ times = []
142
+ with Timer(times):
143
+ time.sleep(0.1)
144
+ print(f"elapsed: {times[0]:.2f}s")
145
+
146
+ Multiprocessing::
147
+
148
+ from easydev.multicore import MultiProcessing
149
+
150
+ def square(n):
151
+ return n * n
152
+
153
+ t = MultiProcessing(maxcpu=4)
154
+ for i in range(10):
155
+ t.add_job(square, i)
156
+ t.run()
157
+ print(t.results)
158
+
159
+ Moving away from easydev
160
+ ------------------------
161
+
162
+ easydev dates from a time when Python lacked many small conveniences. Most of
163
+ its tools now have a standard-library or well-maintained third-party
164
+ replacement, and new projects should not depend on easydev. The full
165
+ module-by-module guide is in the
166
+ `documentation <https://easydev.readthedocs.io/en/latest/migration.html>`_
167
+ (``doc/source/migration.rst``). Main replacements:
168
+
169
+ ========================================= ======================================================
170
+ easydev Use instead
171
+ ========================================= ======================================================
172
+ ``CustomConfig``, ``AppDirs`` ``platformdirs``
173
+ ``DynamicConfigParser`` ``configparser``
174
+ ``AttrDict`` ``types.SimpleNamespace`` / ``dataclasses``
175
+ ``Logging`` ``logging`` (+ ``colorlog``)
176
+ ``Progress`` ``tqdm``
177
+ ``MultiProcessing`` ``concurrent.futures.ProcessPoolExecutor``
178
+ ``shellcmd``, ``execute`` ``subprocess.run``
179
+ ``mkdirs``, ``touch``, ``get_home`` ``pathlib`` / ``os.makedirs(exist_ok=True)``
180
+ ``cmd_exists`` ``shutil.which``
181
+ ``md5`` ``hashlib.file_digest`` (Python 3.11+)
182
+ ``browse`` ``webbrowser.open``
183
+ ``get_dependencies`` ``importlib.metadata.requires``
184
+ ``get_share_file`` ``importlib.resources.files``
185
+ ========================================= ======================================================
186
+
187
+ For example, replacing ``CustomConfig``::
188
+
189
+ # before
190
+ from easydev import CustomConfig
191
+ config_dir = CustomConfig("myapp").user_config_dir
192
+
193
+ # after
194
+ from pathlib import Path
195
+ from platformdirs import user_config_dir
196
+
197
+ config_dir = Path(user_config_dir("myapp"))
198
+ config_dir.mkdir(parents=True, exist_ok=True)
199
+
200
+ Changelog
201
+ ---------
202
+
203
+ ========= ==========================================================================
204
+ Version Description
205
+ ========= ==========================================================================
206
+ 0.15.0 * fix ``is_mac`` (always returned False)
207
+ * ``assert_list_almost_equal`` now warns (FutureWarning) when called without
208
+ ``places``/``deltas`` (nothing is compared); raises ``ListMismatchError``
209
+ (both ValueError and AssertionError)
210
+ * add a migration guide (README and documentation) explaining how to
211
+ replace easydev tools with the standard library, platformdirs, etc.
212
+ * require Python >= 3.9
213
+ 0.13.3 * update pyproject with contribs from @s-t-e-v-e-n-k see PR37
214
+ 0.13.2 * replace mock with unittest.mock (fixes
215
+ https://github.com/cokelaer/easydev/issues/20)
216
+ 0.13.1 * fix get_dependencies
217
+ 0.13.0 * fix requirements (line_profiler) and CI
218
+ 0.12.2 * For developers: move to pyproject. add precommit
219
+ * replace pkg_resources (deprecated) with importlib
220
+ * replace appdirs with more generic platformdirs
221
+ ========= ==========================================================================
222
+
@@ -0,0 +1,184 @@
1
+ easydev
2
+ ##########
3
+
4
+ .. image:: https://badge.fury.io/py/easydev.svg
5
+ :target: https://pypi.python.org/pypi/easydev
6
+
7
+ .. image:: https://github.com/cokelaer/easydev/actions/workflows/main.yml/badge.svg
8
+ :target: https://github.com/cokelaer/easydev/actions/workflows/main.yml
9
+
10
+ .. image:: https://coveralls.io/repos/cokelaer/easydev/badge.svg?branch=main
11
+ :target: https://coveralls.io/r/cokelaer/easydev?branch=main
12
+
13
+ .. image:: https://static.pepy.tech/personalized-badge/easydev?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads
14
+ :target: https://pepy.tech/projects/easydev
15
+
16
+ :documentation: http://easydev-python.readthedocs.io/en/latest/
17
+ :contributions: Please join https://github.com/cokelaer/easydev
18
+ :source: Please use https://github.com/cokelaer/easydev
19
+ :issues: Please use https://github.com/cokelaer/easydev/issues
20
+ :Python version supported: 3.9, 3.10, 3.11, 3.12, 3.13, 3.14
21
+
22
+ Overview
23
+ --------
24
+
25
+ The `easydev <http://pypi.python.org/pypi/easydev/>`_ package provides
26
+ miscellaneous utility functions and classes that are repeatedly useful during
27
+ the development of Python packages. The goal is to help developers speed up
28
+ their work by providing ready-to-use tools for common tasks such as parameter
29
+ validation, logging, progress bars, configuration files, multiprocessing, and
30
+ more.
31
+
32
+ It has been used as an incubator for other packages (e.g.,
33
+ `colormap <http://pypi.python.org/pypi/colormap>`_) and is used in projects
34
+ such as `bioservices <https://pypi.python.org/pypi/bioservices>`_,
35
+ `sequana <https://sequana.readthedocs.io>`_, and
36
+ `GDSCTools <https://gdsctools.readthedocs.io>`_.
37
+
38
+ Installation
39
+ ------------
40
+
41
+ Install the latest release from PyPI::
42
+
43
+ pip install easydev
44
+
45
+ Features
46
+ --------
47
+
48
+ - **Parameter validation** – ``check_param_in_list``, ``check_range``
49
+ - **Dictionary utilities** – ``swapdict``, ``AttrDict`` (access dict keys as attributes, supports nested dicts)
50
+ - **Logging** – coloured logging via ``Logging`` class
51
+ - **Progress bar** – ``Progress`` works in Python, IPython, and Jupyter notebooks
52
+ - **Timer** – measure elapsed time with the ``Timer`` context manager
53
+ - **Profiling** – ``do_profile`` decorator using ``line_profiler``
54
+ - **Configuration files** – ``CustomConfig`` and ``DynamicConfigParser`` for INI-style config management
55
+ - **Shell commands** – ``shellcmd`` and ``execute`` wrappers around subprocess/pexpect
56
+ - **File utilities** – ``touch``, ``mkdirs``, ``md5``
57
+ - **Multiprocessing** – ``MultiProcessing`` class for easy parallel job execution
58
+ - **Codecs** – ``to_list``, ``list2string`` and other conversion helpers
59
+ - **URL utilities** – ``isurl_reachable`` and related helpers
60
+ - **Sphinx integration** – bundled Sphinx theme and ``copybutton`` extension
61
+
62
+ Quick Start
63
+ -----------
64
+
65
+ Parameter validation::
66
+
67
+ from easydev import check_param_in_list, check_range
68
+
69
+ check_param_in_list("on", ["on", "off"]) # passes silently
70
+ check_range(0.5, 0, 1) # passes silently
71
+
72
+ AttrDict – access nested dictionary keys as attributes::
73
+
74
+ from easydev import AttrDict
75
+
76
+ d = AttrDict(**{"server": {"host": "localhost", "port": 8080}})
77
+ print(d.server.host) # localhost
78
+ d.server.port = 9090
79
+
80
+ Coloured logging::
81
+
82
+ from easydev import Logging
83
+
84
+ logger = Logging("myapp", "WARNING")
85
+ logger.warning("something went wrong")
86
+ logger.debug("not shown at WARNING level")
87
+ logger.level = "DEBUG"
88
+ logger.debug("now it is shown")
89
+
90
+ Progress bar::
91
+
92
+ from easydev import Progress
93
+
94
+ pb = Progress(100)
95
+ for i in range(100):
96
+ # do work here
97
+ pb.animate(i + 1)
98
+
99
+ Timer::
100
+
101
+ from easydev import Timer
102
+ import time
103
+
104
+ times = []
105
+ with Timer(times):
106
+ time.sleep(0.1)
107
+ print(f"elapsed: {times[0]:.2f}s")
108
+
109
+ Multiprocessing::
110
+
111
+ from easydev.multicore import MultiProcessing
112
+
113
+ def square(n):
114
+ return n * n
115
+
116
+ t = MultiProcessing(maxcpu=4)
117
+ for i in range(10):
118
+ t.add_job(square, i)
119
+ t.run()
120
+ print(t.results)
121
+
122
+ Moving away from easydev
123
+ ------------------------
124
+
125
+ easydev dates from a time when Python lacked many small conveniences. Most of
126
+ its tools now have a standard-library or well-maintained third-party
127
+ replacement, and new projects should not depend on easydev. The full
128
+ module-by-module guide is in the
129
+ `documentation <https://easydev.readthedocs.io/en/latest/migration.html>`_
130
+ (``doc/source/migration.rst``). Main replacements:
131
+
132
+ ========================================= ======================================================
133
+ easydev Use instead
134
+ ========================================= ======================================================
135
+ ``CustomConfig``, ``AppDirs`` ``platformdirs``
136
+ ``DynamicConfigParser`` ``configparser``
137
+ ``AttrDict`` ``types.SimpleNamespace`` / ``dataclasses``
138
+ ``Logging`` ``logging`` (+ ``colorlog``)
139
+ ``Progress`` ``tqdm``
140
+ ``MultiProcessing`` ``concurrent.futures.ProcessPoolExecutor``
141
+ ``shellcmd``, ``execute`` ``subprocess.run``
142
+ ``mkdirs``, ``touch``, ``get_home`` ``pathlib`` / ``os.makedirs(exist_ok=True)``
143
+ ``cmd_exists`` ``shutil.which``
144
+ ``md5`` ``hashlib.file_digest`` (Python 3.11+)
145
+ ``browse`` ``webbrowser.open``
146
+ ``get_dependencies`` ``importlib.metadata.requires``
147
+ ``get_share_file`` ``importlib.resources.files``
148
+ ========================================= ======================================================
149
+
150
+ For example, replacing ``CustomConfig``::
151
+
152
+ # before
153
+ from easydev import CustomConfig
154
+ config_dir = CustomConfig("myapp").user_config_dir
155
+
156
+ # after
157
+ from pathlib import Path
158
+ from platformdirs import user_config_dir
159
+
160
+ config_dir = Path(user_config_dir("myapp"))
161
+ config_dir.mkdir(parents=True, exist_ok=True)
162
+
163
+ Changelog
164
+ ---------
165
+
166
+ ========= ==========================================================================
167
+ Version Description
168
+ ========= ==========================================================================
169
+ 0.15.0 * fix ``is_mac`` (always returned False)
170
+ * ``assert_list_almost_equal`` now warns (FutureWarning) when called without
171
+ ``places``/``deltas`` (nothing is compared); raises ``ListMismatchError``
172
+ (both ValueError and AssertionError)
173
+ * add a migration guide (README and documentation) explaining how to
174
+ replace easydev tools with the standard library, platformdirs, etc.
175
+ * require Python >= 3.9
176
+ 0.13.3 * update pyproject with contribs from @s-t-e-v-e-n-k see PR37
177
+ 0.13.2 * replace mock with unittest.mock (fixes
178
+ https://github.com/cokelaer/easydev/issues/20)
179
+ 0.13.1 * fix get_dependencies
180
+ 0.13.0 * fix requirements (line_profiler) and CI
181
+ 0.12.2 * For developers: move to pyproject. add precommit
182
+ * replace pkg_resources (deprecated) with importlib
183
+ * replace appdirs with more generic platformdirs
184
+ ========= ==========================================================================
@@ -1,6 +1,3 @@
1
- import os
2
- import sys
3
-
4
1
  from platformdirs import (
5
2
  site_config_dir,
6
3
  site_data_dir,
@@ -61,11 +61,9 @@ There is also an alias **onweb**::
61
61
  from easydev import onweb
62
62
 
63
63
  """
64
- import argparse
65
64
  import os
66
65
  import sys
67
66
  import webbrowser
68
- from optparse import OptionParser
69
67
 
70
68
 
71
69
  def browse(url, verbose=True):
@@ -93,23 +91,23 @@ def _browse_mac(url, verbose=True): # pragma: no cover
93
91
  try:
94
92
  os.system("open /Applications/Safari.app {}".format(url))
95
93
  return
96
- except:
94
+ except Exception:
97
95
  pass
98
96
 
99
97
  try:
100
98
  os.system("open /Applications/Safari.app {}".format("http://" + url))
101
99
  return
102
- except:
100
+ except Exception:
103
101
  pass
104
102
 
105
103
  try:
106
104
  webbrowser.open_new(url)
107
- except:
105
+ except Exception:
108
106
  if verbose:
109
107
  print("Could not open %s. Trying to append http://" % url)
110
108
  try:
111
109
  webbrowser.open_new("open http://{}".format(url))
112
- except:
110
+ except Exception:
113
111
  print("Could not open http://%s" % url)
114
112
  raise Exception
115
113
 
@@ -120,7 +118,7 @@ def _browse_linux(url, verbose=True): # pragma: no cover
120
118
  try:
121
119
  webbrowser.open(url)
122
120
  return
123
- except:
121
+ except Exception:
124
122
  pass
125
123
 
126
124
  try:
@@ -128,7 +126,7 @@ def _browse_linux(url, verbose=True): # pragma: no cover
128
126
  print("Could not open %s" % url)
129
127
  webbrowser.open("http://" + url)
130
128
  return
131
- except:
129
+ except Exception:
132
130
  pass
133
131
 
134
132
  raise Exception("Could not open http://{}".format(url))
@@ -172,6 +170,4 @@ def main(args=None): # pragma: no cover
172
170
 
173
171
 
174
172
  if __name__ == "__main__": # pragma: no cover
175
- import sys
176
-
177
173
  main(sys.argv)
@@ -29,12 +29,6 @@
29
29
  __all__ = ["split_into_chunks"]
30
30
 
31
31
 
32
- try:
33
- range = xrange # py2
34
- except:
35
- pass # py3
36
-
37
-
38
32
  def split_into_chunks(items, maxchunks=10):
39
33
  """Split a list evenly into N chunks
40
34
 
@@ -56,7 +56,7 @@ def to_list(data, verbose=True):
56
56
  try:
57
57
  data = data.tolist()
58
58
  return data
59
- except:
59
+ except Exception:
60
60
  if verbose:
61
61
  print("not known type. Trying to cast into a list")
62
62
  return list(data)
@@ -125,14 +125,14 @@ class DynamicConfigParser(ConfigParser):
125
125
  self.read(self._filename)
126
126
  elif isinstance(config_or_filename, ConfigParser):
127
127
  self._replace_config(config_or_filename)
128
- elif config_or_filename == None:
128
+ elif config_or_filename is None:
129
129
  pass
130
130
  else:
131
131
  raise TypeError("config_or_filename must be a valid filename or valid ConfigParser instance")
132
132
 
133
133
  def read(self, filename):
134
134
  """Load a new config from a filename (remove all previous sections)"""
135
- if os.path.isfile(filename) == False:
135
+ if not os.path.isfile(filename):
136
136
  raise IOError("filename {0} not found".format(filename))
137
137
 
138
138
  config = ConfigParser()
@@ -220,9 +220,9 @@ class DynamicConfigParser(ConfigParser):
220
220
  try: # numbers
221
221
  try:
222
222
  options[option] = self.getint(section, option)
223
- except:
223
+ except Exception:
224
224
  options[option] = self.getfloat(section, option)
225
- except: # string
225
+ except Exception: # string
226
226
  options[option] = self.get(section, option, raw=True)
227
227
  return options
228
228
 
@@ -238,7 +238,7 @@ class DynamicConfigParser(ConfigParser):
238
238
 
239
239
  """
240
240
  try:
241
- if os.path.exists(filename) == True:
241
+ if os.path.exists(filename):
242
242
  print("Warning: over-writing %s " % filename)
243
243
  fp = open(filename, "w")
244
244
  except Exception as err: # pragma: no cover
@@ -311,7 +311,7 @@ class DynamicConfigParser(ConfigParser):
311
311
  if str(self.get(section, option, raw=True)) != str(data.get(section, option, raw=True)):
312
312
  print("option %s in section %s differ" % (option, section))
313
313
  return False
314
- except: # pragma: no cover
314
+ except Exception: # pragma: no cover
315
315
  return False
316
316
  return True
317
317
 
@@ -48,7 +48,7 @@ def get_terminal_width():
48
48
  terminal_width = width
49
49
  except (SystemExit, KeyboardInterrupt): # pragma: no cover
50
50
  raise
51
- except:
51
+ except Exception:
52
52
  # FALLBACK
53
53
  terminal_width = int(os.environ.get("COLUMNS", 80)) - 1
54
54
  return terminal_width
@@ -91,7 +91,7 @@ def get_copybutton_path():
91
91
  try:
92
92
  packagedir = easydev.__path__[0]
93
93
  packagedir = os.path.realpath(pj(packagedir, "..", "share"))
94
- except:
94
+ except Exception:
95
95
  raise IOError("could not find data directory")
96
96
  return pj(packagedir, "copybutton.js")
97
97
 
@@ -14,7 +14,6 @@
14
14
  #
15
15
  ##############################################################################
16
16
  """Handy decorators"""
17
- import threading
18
17
  from functools import wraps
19
18
 
20
19
  __all__ = ["ifpylab", "requires", "ifpandas"]
@@ -100,6 +99,7 @@ def _blocking(not_avail):
100
99
  return blocking
101
100
  """
102
101
 
102
+
103
103
  # same as require decorator but works with list of stirngs of
104
104
  # single string and uses the functools utilities
105
105
  def requires(requires, msg=""):
@@ -122,7 +122,7 @@ def requires(requires, msg=""):
122
122
  """
123
123
  if isinstance(requires, str):
124
124
  requires = [requires]
125
- elif isinstance(requires, list) == False:
125
+ elif not isinstance(requires, list):
126
126
  raise TypeError(
127
127
  "First argument of the /requires/ decorator must be a"
128
128
  + "string or list of string representing the required attributes"
@@ -134,7 +134,7 @@ def requires(requires, msg=""):
134
134
  @wraps(f)
135
135
  def wrapper(*args, **kwds):
136
136
  for require in requires:
137
- if hasattr(args[0], require) == False:
137
+ if not hasattr(args[0], require):
138
138
  raise AttributeError("{} not found in {}. ".format(require, args[0]) + msg)
139
139
  return f(*args, **kwds)
140
140
 
@@ -157,7 +157,7 @@ def ifpandas(func):
157
157
  return func(*args, **kwds)
158
158
 
159
159
  try:
160
- import pandas
160
+ import pandas # noqa: F401
161
161
 
162
162
  return wrapper
163
163
  except Exception: # pragma: no cover
@@ -179,7 +179,7 @@ def ifpylab(func):
179
179
 
180
180
  # for methods
181
181
  try:
182
- import pylab
182
+ import pylab # noqa: F401
183
183
 
184
184
  return wrapper
185
185
  except Exception: # pragma: no cover
@@ -16,14 +16,22 @@
16
16
  # $:Id $
17
17
 
18
18
  import tempfile
19
+ import warnings
19
20
 
20
21
  __all__ = ["assert_list_almost_equal", "trysetattr", "TempFile"]
21
22
 
22
23
 
24
+ class ListMismatchError(ValueError, AssertionError):
25
+ """Raised by :func:`assert_list_almost_equal` (ValueError kept for backward compatibility)"""
26
+
27
+
23
28
  def assert_list_almost_equal(first, second, places=None, deltas=None):
24
29
  """Combined version nose.tools.assert_almost_equal and assert_list_equal
25
30
 
26
31
  This function checks that 2 lists contain identical items.
32
+ Without *places* or *deltas* nothing is compared and a FutureWarning is
33
+ issued. On mismatch, :class:`ListMismatchError` is raised (it derives from
34
+ both ValueError, for backward compatibility, and AssertionError).
27
35
  The equality between pair of items is checked with assert_almost_equal
28
36
  function, which means you can check for the places argument
29
37
 
@@ -44,7 +52,14 @@ def assert_list_almost_equal(first, second, places=None, deltas=None):
44
52
  if deltas:
45
53
  for x, y in zip(first, second):
46
54
  if abs(x - y) > deltas:
47
- raise ValueError
55
+ raise ListMismatchError("{} != {} within tolerance {}".format(x, y, deltas))
56
+ else:
57
+ warnings.warn(
58
+ "assert_list_almost_equal called without places or deltas: nothing is compared. "
59
+ "This will become a strict comparison in a future release.",
60
+ FutureWarning,
61
+ stacklevel=2,
62
+ )
48
63
 
49
64
 
50
65
  def trysetattr(this, attrname, value, possible):
@@ -71,7 +86,7 @@ def trysetattr(this, attrname, value, possible):
71
86
  AssertionError
72
87
 
73
88
  """
74
- if possible == True:
89
+ if possible is True:
75
90
  a1 = True
76
91
  a2 = False
77
92
  else:
@@ -102,7 +117,7 @@ class TempFile(object):
102
117
  def delete(self):
103
118
  try:
104
119
  self.temp._closer.delete = True
105
- except: # pragma: no cover
120
+ except AttributeError: # pragma: no cover
106
121
  self.temp.delete = True
107
122
  self.temp.close()
108
123
 
@@ -59,7 +59,6 @@ class Logging(object):
59
59
  def _set_name(self, name):
60
60
  level = self.level
61
61
  self._name = name
62
- logger = colorlog.getLogger(self._name)
63
62
  if level == 0:
64
63
  self._set_level("WARNING")
65
64
  else:
@@ -20,16 +20,10 @@ __all__ = ["get_home", "cmd_exists"]
20
20
 
21
21
  def get_home():
22
22
  """Return path of the HOME"""
23
- # This function should be robust
24
23
  # First, let us try with expanduser
25
- try:
26
- homedir = os.path.expanduser("~")
27
- except ImportError: # pragma: no cover
28
- # This may happen.
29
- pass
30
- else:
31
- if os.path.isdir(homedir):
32
- return homedir
24
+ homedir = os.path.expanduser("~")
25
+ if os.path.isdir(homedir):
26
+ return homedir
33
27
  # Then, with getenv
34
28
  for this in ("HOME", "USERPROFILE", "TMP"): # pragma: no cover
35
29
  # getenv is same as os.environ.get
@@ -19,6 +19,12 @@ from multiprocessing import Pool, Process, Queue, cpu_count
19
19
  __all__ = ["MultiProcessing"]
20
20
 
21
21
 
22
+ def _init_worker():
23
+ import signal
24
+
25
+ signal.signal(signal.SIGINT, signal.SIG_IGN)
26
+
27
+
22
28
  class MultiProcessing(object):
23
29
  """Class to run jobs in an asynchronous manner.
24
30
 
@@ -53,7 +59,7 @@ class MultiProcessing(object):
53
59
 
54
60
 
55
61
  """
56
- if maxcpu == None:
62
+ if maxcpu is None:
57
63
  maxcpu = cpu_count()
58
64
 
59
65
  self.maxcpu = maxcpu
@@ -102,13 +108,8 @@ class MultiProcessing(object):
102
108
  self.pb = Progress(len(self.jobs), 1)
103
109
  self.pb.animate(0)
104
110
 
105
- def init_worker():
106
- import signal
107
-
108
- signal.signal(signal.SIGINT, signal.SIG_IGN)
109
-
110
111
  self.results = []
111
- self.pool = Pool(self.maxcpu, init_worker)
112
+ self.pool = Pool(self.maxcpu, _init_worker)
112
113
 
113
114
  for process in self.jobs:
114
115
  self.pool.apply_async(process._target, process._args, process._kwargs, callback=self._cb)
@@ -18,7 +18,6 @@
18
18
  import importlib
19
19
  import os
20
20
  from os.path import join as pj
21
- from pathlib import Path
22
21
 
23
22
  __all__ = [
24
23
  "get_shared_directory_path",
@@ -53,7 +52,7 @@ def get_shared_directory_path(package):
53
52
 
54
53
  # print("install mode ? ")
55
54
  sharedir = os.path.realpath(pj(location, package, "share"))
56
- if os.path.isdir(sharedir) == True:
55
+ if os.path.isdir(sharedir):
57
56
  # looks like we have found the share directory so it is an install mode
58
57
  # print ("yes")
59
58
  return sharedir
@@ -63,13 +62,13 @@ def get_shared_directory_path(package):
63
62
  # FIXME: do we need the 3 cases ??
64
63
  # probably just 2 are required, one for develop and one for install mode
65
64
  sharedir = os.path.realpath(pj(location, "..", "share"))
66
- if os.path.isdir(sharedir) == True:
65
+ if os.path.isdir(sharedir):
67
66
  return sharedir
68
67
  sharedir = os.path.realpath(pj(location, "..", "..", "share"))
69
- if os.path.isdir(sharedir) == True:
68
+ if os.path.isdir(sharedir):
70
69
  return sharedir
71
70
  sharedir = os.path.realpath(pj(location, "..", "..", "..", "share"))
72
- if os.path.isdir(sharedir) == True:
71
+ if os.path.isdir(sharedir):
73
72
  return sharedir
74
73
  # could not be found,
75
74
  sharedir = []
@@ -117,10 +116,10 @@ def get_share_file(package, datadir, filename):
117
116
  packagedir = get_shared_directory_path(package)
118
117
  fullpath = os.path.join(packagedir, datadir)
119
118
  # check that it exists
120
- if os.path.isdir(fullpath) == False: # pragma: no cover
119
+ if not os.path.isdir(fullpath): # pragma: no cover
121
120
  raise ValueError("The directory %s in package %s does not seem to exist" % (packagedir, fullpath))
122
121
  filename_path = os.path.join(fullpath, filename)
123
- if os.path.isfile(filename_path) == False:
122
+ if not os.path.isfile(filename_path):
124
123
  correct_files = [x for x in os.listdir(fullpath) if os.path.isfile(x)]
125
124
  msg = "The file %s does not exists. Correct filenames found in %s/%s are:\n" % (
126
125
  filename_path,
@@ -14,7 +14,6 @@
14
14
  #
15
15
  ##############################################################################
16
16
 
17
- import os
18
17
  import sys
19
18
 
20
19
  __all__ = ["get_platform"]
@@ -36,24 +35,17 @@ def get_platform(): # pragma: no cover
36
35
 
37
36
  """
38
37
  print("//easydev.get_platform() Will be deprecated in future version of easydev")
39
- try:
40
- platform = plf.system()
41
- return platform
42
- except:
43
- # platform is not available under all systems (e.g., WLST tool
44
- # see http://stackoverflow.com/questions/1854/python-what-os-am-i-running-on
45
- # so, let us try sys.platform
46
- platform = sys.platform
47
- if platform.startswith("linux"):
48
- platform = "Linux"
49
- elif platform.startswith("java"):
50
- platform = "Java"
51
- elif platform.startswith("win"):
52
- platform = "Windows"
53
- elif platform.startswith("darwin"):
54
- platform = "Darwin"
55
- else:
56
- print("platform not parsed. Return raw value of sys.platform.")
38
+ platform = sys.platform
39
+ if platform.startswith("linux"):
40
+ platform = "Linux"
41
+ elif platform.startswith("java"):
42
+ platform = "Java"
43
+ elif platform.startswith("win"):
44
+ platform = "Windows"
45
+ elif platform.startswith("darwin"):
46
+ platform = "Darwin"
47
+ else:
48
+ print("platform not parsed. Return raw value of sys.platform.")
57
49
  return platform
58
50
 
59
51
 
@@ -72,7 +64,7 @@ def is_linux():
72
64
 
73
65
 
74
66
  def is_mac():
75
- if get_platform() == "Mac":
67
+ if get_platform() in ("Darwin", "Mac"):
76
68
  return True
77
69
  else:
78
70
  return False
@@ -51,5 +51,5 @@ def get_sphinx_themes():
51
51
 
52
52
  sharedir = get_shared_directory_path("easydev")
53
53
  sharedir = pj(sharedir, "themes")
54
- themes = [x for x in os.listdir(sharedir) if x.startswith(".") == False]
54
+ themes = [x for x in os.listdir(sharedir) if not x.startswith(".")]
55
55
  return themes
@@ -33,7 +33,7 @@ __all__ = [
33
33
 
34
34
 
35
35
  def precision(data, digit=2):
36
- """Round values in a list keeping only N digits precision
36
+ """Truncate a value (not round) keeping only N digits precision
37
37
 
38
38
  ::
39
39
 
@@ -116,24 +116,26 @@ def shellcmd(cmd, show=False, verbose=False, ignore_errors=False):
116
116
  :param str cmd: the command to call
117
117
  :param bool show: print the command
118
118
  :param bool verbose: print the output
119
+ :param bool ignore_errors: do not raise when the command writes to stderr
119
120
 
120
- :return: the output as a string
121
+ :return: the output as bytes (stripped)
121
122
  """
122
123
  if show:
123
124
  print(cmd)
124
125
  try:
125
126
  ret = subprocess.Popen([cmd], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
126
127
 
127
- output = ret.stdout.read().strip()
128
- error = ret.stderr.read().strip()
129
- ret.wait()
128
+ output, error = ret.communicate()
129
+ output = output.strip()
130
+ error = error.strip()
130
131
 
132
+ # Legacy behaviour kept on purpose (many packages rely on it): any
133
+ # output on stderr is an error, the exit status is not checked.
131
134
  if len(error) > 0:
132
135
  if ignore_errors is False:
133
136
  raise Exception(error)
134
- else:
135
- if verbose is True:
136
- print("Errors/Warning" + str(error))
137
+ elif verbose is True:
138
+ print("Errors/Warning" + str(error))
137
139
 
138
140
  if verbose is True:
139
141
  print(output)
@@ -161,7 +163,7 @@ def execute(cmd, showcmd=True, verbose=True):
161
163
  if verbose:
162
164
  try:
163
165
  sys.stdout.write(line.decode())
164
- except:
166
+ except Exception:
165
167
  sys.stdout.write(line)
166
168
 
167
169
  sys.stdout.flush()
@@ -279,12 +281,9 @@ class AttrDict(dict):
279
281
 
280
282
  :param dict content: a valid dictionary
281
283
  """
282
- # accepts dict and attrdict classes
283
- try:
284
- from collections import OrderedDict
285
- except:
286
- OrderedDict = AttrDict
284
+ from collections import OrderedDict
287
285
 
286
+ # accepts dict and attrdict classes
288
287
  if content.__class__ not in [dict, OrderedDict, AttrDict]:
289
288
  raise TypeError
290
289
 
@@ -14,10 +14,7 @@
14
14
  #
15
15
  ##############################################################################
16
16
  """Utilities related to the web"""
17
- try:
18
- import httplib
19
- except ImportError:
20
- import http.client as httplib
17
+ import http.client as httplib
21
18
 
22
19
  __all__ = ["isurl_reachable"]
23
20
 
@@ -39,13 +36,13 @@ def isurl_reachable(url, timeout=10, path="/"): # pragma: no cover
39
36
  conn = httplib.HTTPConnection(url, timeout=timeout)
40
37
  try:
41
38
  conn.request("HEAD", path)
42
- except:
39
+ except Exception:
43
40
  return False
44
41
  # 302 is a redirection
45
42
  # 200 is okay
46
43
  try:
47
44
  response = conn.getresponse()
48
- except:
45
+ except Exception:
49
46
  return False
50
47
 
51
48
  if response.status in [200, 302]:
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [project]
6
6
  name = "easydev"
7
- version = "0.13.3"
7
+ version = "0.15.0"
8
8
  description = "Common utilities to ease development of Python packages"
9
9
  authors = [
10
10
  { "name" = "Thomas Cokelaer", "email" = "thomas.cokelaer@pasteur.fr" },
@@ -21,10 +21,12 @@ classifiers = [
21
21
  "Intended Audience :: Science/Research",
22
22
  "License :: OSI Approved :: BSD License",
23
23
  "Operating System :: POSIX :: Linux",
24
- "Programming Language :: Python :: 3.8",
25
24
  "Programming Language :: Python :: 3.9",
26
25
  "Programming Language :: Python :: 3.10",
27
26
  "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "Programming Language :: Python :: 3.13",
29
+ "Programming Language :: Python :: 3.14",
28
30
  "Topic :: Software Development :: Libraries :: Python Modules",
29
31
  "Topic :: Scientific/Engineering :: Bio-Informatics",
30
32
  "Topic :: Scientific/Engineering :: Information Analysis",
@@ -46,12 +48,12 @@ Documentation = "https://easydev.readthedocs.io"
46
48
 
47
49
 
48
50
  [tool.poetry.dependencies]
49
- python = "^3.8"
51
+ python = "^3.9"
50
52
  colorama = "^0.4.6"
51
53
  colorlog = "^6.8.2"
52
54
  pexpect = "^4.9.0"
53
55
  platformdirs = "^4.2.0"
54
- line-profiler = "^4.1.2"
56
+ line-profiler = "^5.0.0"
55
57
 
56
58
 
57
59
 
easydev-0.13.3/PKG-INFO DELETED
@@ -1,92 +0,0 @@
1
- Metadata-Version: 2.3
2
- Name: easydev
3
- Version: 0.13.3
4
- Summary: Common utilities to ease development of Python packages
5
- Home-page: https://easydev.readthedocs.io
6
- License: BSD-3-Clause
7
- Keywords: config,decorators,development
8
- Author: Thomas Cokelaer
9
- Author-email: thomas.cokelaer@pasteur.fr
10
- Requires-Python: >=3.8,<4.0
11
- Classifier: Development Status :: 5 - Production/Stable
12
- Classifier: Intended Audience :: Education
13
- Classifier: Intended Audience :: End Users/Desktop
14
- Classifier: Intended Audience :: Developers
15
- Classifier: Intended Audience :: Science/Research
16
- Classifier: License :: OSI Approved :: BSD License
17
- Classifier: Operating System :: POSIX :: Linux
18
- Classifier: Programming Language :: Python :: 3.8
19
- Classifier: Programming Language :: Python :: 3.9
20
- Classifier: Programming Language :: Python :: 3.10
21
- Classifier: Programming Language :: Python :: 3.11
22
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
- Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
24
- Classifier: Topic :: Scientific/Engineering :: Information Analysis
25
- Requires-Dist: colorama (>=0.4.6,<0.5.0)
26
- Requires-Dist: colorlog (>=6.8.2,<7.0.0)
27
- Requires-Dist: line-profiler (>=4.1.2,<5.0.0)
28
- Requires-Dist: pexpect (>=4.9.0,<5.0.0)
29
- Requires-Dist: platformdirs (>=4.2.0,<5.0.0)
30
- Project-URL: Documentation, https://easydev.readthedocs.io
31
- Project-URL: Issues, https://github.com/cokelaer/easydev/issues
32
- Project-URL: Repository, https://github.com/cokelaer/easydev
33
- Description-Content-Type: text/x-rst
34
-
35
- easydev
36
- ##########
37
-
38
- .. image:: https://badge.fury.io/py/easydev.svg
39
- :target: https://pypi.python.org/pypi/easydev
40
-
41
- .. image:: https://github.com/cokelaer/easydev/actions/workflows/main.yml/badge.svg
42
- :target: https://github.com/cokelaer/easydev/actions/workflows/main.yml
43
-
44
-
45
- .. image:: https://coveralls.io/repos/cokelaer/easydev/badge.svg?branch=main
46
- :target: https://coveralls.io/r/cokelaer/easydev?branch=main
47
-
48
-
49
-
50
-
51
- :documentation: http://easydev-python.readthedocs.io/en/latest/
52
- :contributions: Please join https://github.com/cokelaer/easydev
53
- :source: Please use https://github.com/cokelaer/easydev
54
- :issues: Please use https://github.com/cokelaer/easydev/issues
55
- :Python version supported: 3.9, 3.10, 3.11, 3.12
56
-
57
-
58
- The `easydev <http://pypi.python.org/pypi/easydev/>`_ package
59
- provides miscellaneous functions that are repeatidly used during
60
- the development of Python packages. The goal is to help developers on
61
- speeding up their own dev. It has been used also as an incubator for other
62
- packages (e.g., http://pypi.python.org/pypi/colormap) and is stable.
63
-
64
- .. warning:: I'm not pretending to provide universal and bug-free tools. The
65
- tools provided may also change. However, **easydev** is used
66
- in a few other packages such as
67
- `bioservices <https://pypi.python.org/pypi/bioservices>`_,
68
- `sequana <https://sequana.readthedocs.io>`_ or
69
- `GDSCTools <https://sequana.readthedocs.io>`_ to give a few
70
- examples.
71
-
72
-
73
- Note 10/01/2025: Although I tried to keep back-compatibility as much as possible, test can be done only on newest version. support for python 3.7 and 3.8 were droppe because the continuous integration does not support it. However, easydev may still be python3.7 and 3.8 compatible. Have a try.
74
-
75
-
76
-
77
- Changelog
78
- ~~~~~~~~~
79
-
80
- ========= ==========================================================================
81
- Version Description
82
- ========= ==========================================================================
83
- 0.13.3 * update pyproject with contribs from @s-t-e-v-e-n-k see PR37
84
- 0.13.2 * replace mock with unittest.mock (fixes
85
- https://github.com/cokelaer/easydev/issues/20)
86
- 0.13.1 * fix get_dependencies
87
- 0.13.0 * fix requirements (line_profiler) and CI
88
- 0.12.2 * For developers: move to pyprojet. add precomit
89
- * replace pkg_resources (deprecated) with importlib
90
- * replace appdirs with more generic platformdirs
91
- ========= ==========================================================================
92
-
easydev-0.13.3/README.rst DELETED
@@ -1,57 +0,0 @@
1
- easydev
2
- ##########
3
-
4
- .. image:: https://badge.fury.io/py/easydev.svg
5
- :target: https://pypi.python.org/pypi/easydev
6
-
7
- .. image:: https://github.com/cokelaer/easydev/actions/workflows/main.yml/badge.svg
8
- :target: https://github.com/cokelaer/easydev/actions/workflows/main.yml
9
-
10
-
11
- .. image:: https://coveralls.io/repos/cokelaer/easydev/badge.svg?branch=main
12
- :target: https://coveralls.io/r/cokelaer/easydev?branch=main
13
-
14
-
15
-
16
-
17
- :documentation: http://easydev-python.readthedocs.io/en/latest/
18
- :contributions: Please join https://github.com/cokelaer/easydev
19
- :source: Please use https://github.com/cokelaer/easydev
20
- :issues: Please use https://github.com/cokelaer/easydev/issues
21
- :Python version supported: 3.9, 3.10, 3.11, 3.12
22
-
23
-
24
- The `easydev <http://pypi.python.org/pypi/easydev/>`_ package
25
- provides miscellaneous functions that are repeatidly used during
26
- the development of Python packages. The goal is to help developers on
27
- speeding up their own dev. It has been used also as an incubator for other
28
- packages (e.g., http://pypi.python.org/pypi/colormap) and is stable.
29
-
30
- .. warning:: I'm not pretending to provide universal and bug-free tools. The
31
- tools provided may also change. However, **easydev** is used
32
- in a few other packages such as
33
- `bioservices <https://pypi.python.org/pypi/bioservices>`_,
34
- `sequana <https://sequana.readthedocs.io>`_ or
35
- `GDSCTools <https://sequana.readthedocs.io>`_ to give a few
36
- examples.
37
-
38
-
39
- Note 10/01/2025: Although I tried to keep back-compatibility as much as possible, test can be done only on newest version. support for python 3.7 and 3.8 were droppe because the continuous integration does not support it. However, easydev may still be python3.7 and 3.8 compatible. Have a try.
40
-
41
-
42
-
43
- Changelog
44
- ~~~~~~~~~
45
-
46
- ========= ==========================================================================
47
- Version Description
48
- ========= ==========================================================================
49
- 0.13.3 * update pyproject with contribs from @s-t-e-v-e-n-k see PR37
50
- 0.13.2 * replace mock with unittest.mock (fixes
51
- https://github.com/cokelaer/easydev/issues/20)
52
- 0.13.1 * fix get_dependencies
53
- 0.13.0 * fix requirements (line_profiler) and CI
54
- 0.12.2 * For developers: move to pyprojet. add precomit
55
- * replace pkg_resources (deprecated) with importlib
56
- * replace appdirs with more generic platformdirs
57
- ========= ==========================================================================
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes