Skip to content

Commit a0d4442

Browse files
committed
Squashed commit of the following:
commit 4581953 Merge: d6335b2 eaa13a0 Author: Phil Starkey <philipstarkey@users.noreply.github.com> Date: Mon Nov 2 16:27:23 2020 +1100 Merge pull request #72 from philipstarkey/feature/versions-module-docs Added API docs for versions submodule added in #65 commit eaa13a0 Author: Phil Starkey <philipstarkey@users.noreply.github.com> Date: Mon Nov 2 16:24:02 2020 +1100 Second attempt at fixing the missing site package functions. This time we explicitly mock the missing functions using a lambda that returns an empty version of whatever types the methods usually return (hard coded into conf.py) commit d6335b2 Merge: f1c0962 720003b Author: Phil Starkey <philipstarkey@users.noreply.github.com> Date: Mon Nov 2 15:58:56 2020 +1100 Merge pull request #73 from philipstarkey/bugfix/setuptools_scm Removes setuptools_scm configuration from pyproject.toml commit 720003b Author: Phil Starkey <philipstarkey@users.noreply.github.com> Date: Mon Nov 2 15:57:33 2020 +1100 Removes setuptools_scm configuration from pyproject.toml As such, I see no way to utilise pyproject.toml for these settings, and am reverting to using the configuration specified in setup.py (restored in #71) commit f1c0962 Merge: dce6ac8 fa2654c Author: Phil Starkey <philipstarkey@users.noreply.github.com> Date: Mon Nov 2 13:06:10 2020 +1100 Merge pull request #71 from philipstarkey/bugfix/setuptools_scm Bugfixes for the mistakes in #70 commit 83c6ded Author: Phil Starkey <philipstarkey@users.noreply.github.com> Date: Mon Nov 2 13:04:42 2020 +1100 Attempt to fix the site module issue on readthedocs. commit 2c433e2 Author: Phil Starkey <philipstarkey@users.noreply.github.com> Date: Mon Nov 2 12:51:48 2020 +1100 Added API docs for versions submodule added in #65 Formatted docstrings to match sphinx Doogle style and added rst file to docs to display them. commit fa2654c Author: Phil Starkey <philipstarkey@users.noreply.github.com> Date: Mon Nov 2 11:09:10 2020 +1100 Bugfixes for the mistakes in #70 labscript-suite/labscript-suite#53 erroenously removed the env var that removed the local version (required for uploading to test PyPI). Contrary to my statements in #62, the packaging library does not seem to be a dependency of setuptools. Instead they have vendored it as an internal submodule. Rather than rely on that, packaging is now a dependency of labscript-utils directly.
1 parent dce6ac8 commit a0d4442

File tree

9 files changed

+133
-26
lines changed

9 files changed

+133
-26
lines changed

.github/workflows/release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ defaults:
1515

1616
env:
1717
PACKAGE_NAME: labscript-utils
18+
SCM_LOCAL_SCHEME: no-local-version
1819
ANACONDA_USER: labscript-suite
1920

2021
# Configuration for a package with compiled extensions:

docs/source/api/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,4 @@ Module and File Tools
6060
double_import_denier
6161
filewatcher
6262
modulewatcher
63+
versions

docs/source/api/versions.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
============================
2+
labscript_utils.versions
3+
============================
4+
5+
.. automodule:: labscript_utils.versions
6+
:members:
7+
:undoc-members:
8+
:private-members:

docs/source/conf.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
# add these directories to sys.path here. If the directory is relative to the
1111
# documentation root, use os.path.abspath to make it absolute, like shown here.
1212
#
13+
import copy
1314
import os
1415
from pathlib import Path
1516
from m2r import MdInclude
@@ -50,6 +51,23 @@
5051

5152
autodoc_typehints = 'description'
5253

54+
# mock missing site packages methods
55+
import site
56+
mock_site_methods = {
57+
# Format:
58+
# method name: return value
59+
'getusersitepackages': '',
60+
'getsitepackages': []
61+
}
62+
__fn = None
63+
for __name, __rval in mock_site_methods.items():
64+
if not hasattr(site, __name):
65+
__fn = lambda *args, __rval=copy.deepcopy(__rval), **kwargs: __rval
66+
setattr(site, __name, __fn)
67+
del __name
68+
del __rval
69+
del __fn
70+
5371
# Prefix each autosectionlabel with the name of the document it is in and a colon
5472
autosectionlabel_prefix_document = True
5573

labscript_utils/modulewatcher.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@
3333

3434

3535
class ModuleWatcher(object):
36+
"""A watcher that reloads modules that have been modified on disk
37+
38+
Only reloads modules imported after instantiation. Does not reload C extensions.
39+
40+
Args:
41+
debug (bool, optional): When :code:`True`, prints debugging information
42+
when reloading modules.
43+
"""
3644
def __init__(self, debug=False):
3745
self.debug = debug
3846
# A lock to hold whenever you don't want modules unloaded:

labscript_utils/versions.py

Lines changed: 90 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,20 @@ class BrokenInstall(RuntimeError):
4848

4949
def get_import_path(import_name):
5050
"""Get which entry in sys.path a module would be imported from, without importing
51-
it."""
51+
it.
52+
53+
Args:
54+
import_name (str): The module name.
55+
56+
Raises:
57+
ModuleNotFoundError: Raised if the module is not installed.
58+
NotImplementedError: Raised if the module is a "namespace package".
59+
Support for namepsace packages is not currently availabled.
60+
61+
Returns:
62+
str: The path to the folder containing the module.
63+
64+
"""
5265
spec = importlib.util.find_spec(import_name)
5366
if spec is None:
5467
raise ModuleNotFoundError(import_name)
@@ -66,8 +79,22 @@ def get_import_path(import_name):
6679

6780

6881
def _get_metadata_version(project_name, import_path):
69-
"""Return the metadata version for a package with the given project name located at
70-
the given import path, or None if there is no such package."""
82+
"""Gets the package metadata version.
83+
84+
Args:
85+
project_name (str): The package name (e.g. the name used when pip installing
86+
the package).
87+
import_path (str): The path to the folder containing the installed package.
88+
89+
Raises:
90+
:exc:`BrokenInstall`: Raised if the package installation is corrupted (multiple
91+
packages matching the given arguments were found). May occur if
92+
(un)installation for a particular package version only partially completed.
93+
94+
Returns:
95+
The metadata version for a package with the given project name located at
96+
the given import path, or None if there is no such package.
97+
"""
7198

7299
for finder in sys.meta_path:
73100
if hasattr(finder, 'find_distributions'):
@@ -84,8 +111,14 @@ def _get_metadata_version(project_name, import_path):
84111

85112

86113
def _get_literal_version(filename):
87-
"""Tokenize a source file and return any __version__ = <version> literal defined in
88-
it.
114+
"""Tokenize a source file and return any :code:`__version__ = <version>` literal
115+
defined in it.
116+
117+
Args:
118+
filename (str): The path to the file to tokenize.
119+
120+
Returns:
121+
Any version literal found matching the above criteria, or None.
89122
"""
90123
if not os.path.exists(filename):
91124
return None
@@ -110,17 +143,34 @@ def _get_literal_version(filename):
110143

111144

112145
def get_version(import_name, project_name=None, import_path=None):
113-
"""Try very hard to get the version of a package without importing it. if
114-
import_path is not given, first find where it would be imported from, without
146+
"""Try very hard to get the version of a package without importing it.
147+
148+
If import_path is not given, first find where it would be imported from, without
115149
importing it. Then look for metadata in the same import path with the given project
116150
name (note: this is not always the same as the import name, it is the name for
117151
example you would ask pip to install). If that is found, return the version info
118-
from it. Otherwise look for a __version__.py file in the package directory, or a
119-
__version__ = <version> literal defined in the package source (without executing
120-
it).
152+
from it. Otherwise look for a :code:`__version__.py` file in the package directory,
153+
or a :code:`__version__ = <version>` literal defined in the package source (without
154+
executing it).
155+
156+
Args:
157+
import_name (str): The module name.
158+
project_name (str, optional): The package name (e.g. the name used when pip
159+
installing the package). This must be specified if it does not match the
160+
module name.
161+
import_path (str, optional): The path to the folder containing the installed
162+
package.
163+
164+
Raises:
165+
NotImplementedError: Raised if the module name contains a period. Only
166+
top-level packages are supported at this time.
121167
122-
Return NotFound if the package cannot be found, and NoVersionInfo if the version
123-
cannot be obtained in the above way, or if it was found but was None."""
168+
Returns:
169+
The version literal of the package.
170+
If the package cannot be found, :class:`NotFound` is returned.
171+
If the version cannot be obtained in the above way, or if the version was found
172+
but was :code:`None`, :class:`NoVersionInfo` is returned.
173+
"""
124174
if project_name is None:
125175
project_name = import_name
126176
if '.' in import_name:
@@ -162,15 +212,34 @@ def get_version(import_name, project_name=None, import_path=None):
162212

163213

164214
def check_version(module_name, at_least, less_than, version=None, project_name=None):
165-
"""Check that the version of the given module is at least and less than the given
166-
version strings, and raise VersionException if not. Raise VersionException if the
167-
module was not found or its version could not be determined. This function uses
168-
get_version to determine version numbers without importing modules. In order to do
169-
this, project_name must be provided if it differs from module_name. For example,
170-
pyserial is imported as 'serial', but the project name, as passed to a 'pip install'
171-
command, is 'pyserial'. Therefore to check the version of pyserial, pass in
172-
module_name='serial' and project_name='pyserial'. You can also pass in a version
173-
string yourself, in which case no inspection of packages will take place.
215+
"""Checks if a module version is within specified bounds.
216+
217+
Checks that the version of the given module is at least and less than the given
218+
version strings. This function uses :func:`get_version` to determine version
219+
numbers without importing modules. In order to do this, :code:`project_name` must
220+
be provided if it differs from :code:`module_name`. For example, pyserial is
221+
imported as 'serial', but the project name, as passed to a 'pip install' command,
222+
is 'pyserial'. Therefore to check the version of pyserial, pass in
223+
:code:`module_name='serial'` and :code:`project_name='pyserial'`.
224+
You can also pass in a version string yourself, in which case no inspection of
225+
packages will take place.
226+
227+
Args:
228+
module_name (str): The name of the module to check.
229+
at_least (str): The minimum acceptable module version.
230+
less_than (str): The minimum unacceptable module version. Usually this would be
231+
the next major version if the package follows
232+
`semver <https://semver.org>`_.
233+
version (str, optional): The current version of the installed package. Useful when the
234+
package version is stored in a non-standard location.
235+
project_name (str, optional): The package name (e.g. the name used when pip
236+
installing the package). This must be specified if it does not match the
237+
module name.
238+
239+
Raises:
240+
:exc:`VersionException`: if the module was not found or its version could not
241+
be determined.
242+
174243
"""
175244
if version is None:
176245
version = get_version(module_name, project_name)

pyproject.toml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
11
[build-system]
22
requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=4.1.0"]
33
build-backend = "setuptools.build_meta"
4-
5-
[tool.setuptools_scm]
6-
version_scheme = "release-branch-semver"
7-
local_scheme = "node-and-date"

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ install_requires =
2828
importlib_metadata>=1.0
2929
h5py>=2.9
3030
numpy>=1.15
31+
packaging>=20.4
3132
pyqtgraph>=0.11.0rc0
3233
qtutils>=2.2.3
3334
scipy

setup.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,9 @@ def run(self):
1616
self.copy_file('labscript-suite.pth', path)
1717

1818

19-
setup(cmdclass={'develop': develop_command})
19+
VERSION_SCHEME = {
20+
"version_scheme": os.getenv("SCM_VERSION_SCHEME", "release-branch-semver"),
21+
"local_scheme": os.getenv("SCM_LOCAL_SCHEME", "node-and-date"),
22+
}
23+
24+
setup(use_scm_version=VERSION_SCHEME, cmdclass={'develop': develop_command})

0 commit comments

Comments
 (0)