fitscube 0.2.2__tar.gz → 0.3.1__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.
- {fitscube-0.2.2 → fitscube-0.3.1}/PKG-INFO +13 -11
- {fitscube-0.2.2 → fitscube-0.3.1}/README.md +10 -9
- fitscube-0.3.1/fitscube/__init__.py +4 -0
- {fitscube-0.2.2 → fitscube-0.3.1}/fitscube/fitscube.py +104 -7
- {fitscube-0.2.2 → fitscube-0.3.1}/fitscube/stokescube.py +2 -3
- {fitscube-0.2.2 → fitscube-0.3.1}/pyproject.toml +2 -2
- fitscube-0.2.2/fitscube/__init__.py +0 -4
- fitscube-0.2.2/setup.py +0 -35
- {fitscube-0.2.2 → fitscube-0.3.1}/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fitscube
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Thomson, Alec (S&A, Kensington)
|
|
6
6
|
Author-email: AlecThomson@users.noreply.github.com
|
|
@@ -11,7 +11,8 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.9
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.10
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
-
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Dist: astropy (>=5)
|
|
15
16
|
Requires-Dist: numpy (>=1.20,<2.0)
|
|
16
17
|
Requires-Dist: tqdm
|
|
17
18
|
Description-Content-Type: text/markdown
|
|
@@ -46,18 +47,19 @@ pip install git+https://github.com/AlecThomson/fitscube.git
|
|
|
46
47
|
Command line:
|
|
47
48
|
```bash
|
|
48
49
|
fitscube -h
|
|
49
|
-
# usage: fitscube [-h] [-o] [--freq-file FREQ_FILE | --freqs FREQS [FREQS ...] | --ignore-freq] file_list [file_list ...] out_cube
|
|
50
|
+
# usage: fitscube [-h] [-o] [--create-blanks] [--freq-file FREQ_FILE | --freqs FREQS [FREQS ...] | --ignore-freq] file_list [file_list ...] out_cube
|
|
50
51
|
|
|
51
|
-
# Fitscube: Combine single-frequency FITS files into a cube. Assumes: - All files have the same WCS - All files have the same shape / pixel grid -
|
|
52
|
-
#
|
|
52
|
+
# Fitscube: Combine single-frequency FITS files into a cube. Assumes: - All files have the same WCS - All files have the same shape / pixel grid - Frequency is either a WCS
|
|
53
|
+
# axis or in the REFFREQ header keyword - All the relevant information is in the first header of the first image
|
|
53
54
|
|
|
54
55
|
# positional arguments:
|
|
55
56
|
# file_list List of FITS files to combine (in frequency order)
|
|
56
57
|
# out_cube Output FITS file
|
|
57
58
|
|
|
58
|
-
#
|
|
59
|
+
# options:
|
|
59
60
|
# -h, --help show this help message and exit
|
|
60
61
|
# -o, --overwrite Overwrite output file if it exists
|
|
62
|
+
# --create-blanks Try to create a blank cube with evenly spaced frequencies
|
|
61
63
|
# --freq-file FREQ_FILE
|
|
62
64
|
# File containing frequencies in Hz
|
|
63
65
|
# --freqs FREQS [FREQS ...]
|
|
@@ -65,10 +67,10 @@ fitscube -h
|
|
|
65
67
|
# --ignore-freq Ignore frequency information and just stack (probably not what you want)
|
|
66
68
|
|
|
67
69
|
stokescube -h
|
|
68
|
-
# usage: stokescube [-h] [-v STOKES_V_FILE] [
|
|
70
|
+
# usage: stokescube [-h] [-v STOKES_V_FILE] [-o] stokes_I_file stokes_Q_file stokes_U_file output_file
|
|
69
71
|
|
|
70
|
-
# Fitscube: Combine single-Stokes FITS files into a Stokes cube. Assumes: - All files have the same WCS - All files have the same shape / pixel
|
|
71
|
-
#
|
|
72
|
+
# Fitscube: Combine single-Stokes FITS files into a Stokes cube. Assumes: - All files have the same WCS - All files have the same shape / pixel grid - All the relevant
|
|
73
|
+
# information is in the first header of the first image
|
|
72
74
|
|
|
73
75
|
# positional arguments:
|
|
74
76
|
# stokes_I_file Stokes I file
|
|
@@ -76,11 +78,11 @@ stokescube -h
|
|
|
76
78
|
# stokes_U_file Stokes U file
|
|
77
79
|
# output_file Output file
|
|
78
80
|
|
|
79
|
-
#
|
|
81
|
+
# options:
|
|
80
82
|
# -h, --help show this help message and exit
|
|
81
83
|
# -v STOKES_V_FILE, --stokes_V_file STOKES_V_FILE
|
|
82
84
|
# Stokes V file
|
|
83
|
-
# --overwrite
|
|
85
|
+
# -o, --overwrite Overwrite output file if it exists
|
|
84
86
|
```
|
|
85
87
|
|
|
86
88
|
Python:
|
|
@@ -28,18 +28,19 @@ pip install git+https://github.com/AlecThomson/fitscube.git
|
|
|
28
28
|
Command line:
|
|
29
29
|
```bash
|
|
30
30
|
fitscube -h
|
|
31
|
-
# usage: fitscube [-h] [-o] [--freq-file FREQ_FILE | --freqs FREQS [FREQS ...] | --ignore-freq] file_list [file_list ...] out_cube
|
|
31
|
+
# usage: fitscube [-h] [-o] [--create-blanks] [--freq-file FREQ_FILE | --freqs FREQS [FREQS ...] | --ignore-freq] file_list [file_list ...] out_cube
|
|
32
32
|
|
|
33
|
-
# Fitscube: Combine single-frequency FITS files into a cube. Assumes: - All files have the same WCS - All files have the same shape / pixel grid -
|
|
34
|
-
#
|
|
33
|
+
# Fitscube: Combine single-frequency FITS files into a cube. Assumes: - All files have the same WCS - All files have the same shape / pixel grid - Frequency is either a WCS
|
|
34
|
+
# axis or in the REFFREQ header keyword - All the relevant information is in the first header of the first image
|
|
35
35
|
|
|
36
36
|
# positional arguments:
|
|
37
37
|
# file_list List of FITS files to combine (in frequency order)
|
|
38
38
|
# out_cube Output FITS file
|
|
39
39
|
|
|
40
|
-
#
|
|
40
|
+
# options:
|
|
41
41
|
# -h, --help show this help message and exit
|
|
42
42
|
# -o, --overwrite Overwrite output file if it exists
|
|
43
|
+
# --create-blanks Try to create a blank cube with evenly spaced frequencies
|
|
43
44
|
# --freq-file FREQ_FILE
|
|
44
45
|
# File containing frequencies in Hz
|
|
45
46
|
# --freqs FREQS [FREQS ...]
|
|
@@ -47,10 +48,10 @@ fitscube -h
|
|
|
47
48
|
# --ignore-freq Ignore frequency information and just stack (probably not what you want)
|
|
48
49
|
|
|
49
50
|
stokescube -h
|
|
50
|
-
# usage: stokescube [-h] [-v STOKES_V_FILE] [
|
|
51
|
+
# usage: stokescube [-h] [-v STOKES_V_FILE] [-o] stokes_I_file stokes_Q_file stokes_U_file output_file
|
|
51
52
|
|
|
52
|
-
# Fitscube: Combine single-Stokes FITS files into a Stokes cube. Assumes: - All files have the same WCS - All files have the same shape / pixel
|
|
53
|
-
#
|
|
53
|
+
# Fitscube: Combine single-Stokes FITS files into a Stokes cube. Assumes: - All files have the same WCS - All files have the same shape / pixel grid - All the relevant
|
|
54
|
+
# information is in the first header of the first image
|
|
54
55
|
|
|
55
56
|
# positional arguments:
|
|
56
57
|
# stokes_I_file Stokes I file
|
|
@@ -58,11 +59,11 @@ stokescube -h
|
|
|
58
59
|
# stokes_U_file Stokes U file
|
|
59
60
|
# output_file Output file
|
|
60
61
|
|
|
61
|
-
#
|
|
62
|
+
# options:
|
|
62
63
|
# -h, --help show this help message and exit
|
|
63
64
|
# -v STOKES_V_FILE, --stokes_V_file STOKES_V_FILE
|
|
64
65
|
# Stokes V file
|
|
65
|
-
# --overwrite
|
|
66
|
+
# -o, --overwrite Overwrite output file if it exists
|
|
66
67
|
```
|
|
67
68
|
|
|
68
69
|
Python:
|
|
@@ -10,8 +10,7 @@ Assumes:
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
import os
|
|
13
|
-
from
|
|
14
|
-
from typing import List, Tuple, Union
|
|
13
|
+
from typing import List, NamedTuple, Optional, Tuple, Union
|
|
15
14
|
|
|
16
15
|
import astropy.units as u
|
|
17
16
|
import numpy as np
|
|
@@ -19,9 +18,88 @@ from astropy.io import fits
|
|
|
19
18
|
from astropy.wcs import WCS
|
|
20
19
|
from tqdm.auto import tqdm
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
|
|
22
|
+
class InitResult(NamedTuple):
|
|
23
|
+
data_cube: np.ndarray
|
|
24
|
+
"""Output data cube"""
|
|
25
|
+
header: fits.Header
|
|
26
|
+
"""Output header"""
|
|
27
|
+
idx: int
|
|
28
|
+
"""Index of frequency axis"""
|
|
29
|
+
fits_idx: int
|
|
30
|
+
"""FITS index of frequency axis"""
|
|
31
|
+
is_2d: bool
|
|
32
|
+
"""Whether the input is 2D"""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def isin_close(element: np.ndarray, test_element: np.ndarray) -> np.ndarray:
|
|
36
|
+
"""Check if element is in test_element, within a tolerance.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
element (np.ndarray): Element to check
|
|
40
|
+
test_element (np.ndarray): Element to check against
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
np.ndarray: Boolean array
|
|
44
|
+
"""
|
|
45
|
+
return np.isclose(element[:, None], test_element).any(1)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def even_spacing(freqs: u.Quantity) -> Tuple[u.Quantity, np.ndarray]:
|
|
49
|
+
"""Make the frequencies evenly spaced.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
freqs (u.Quantity): Original frequencies
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Tuple[u.Quantity, np.ndarray]: Evenly spaced frequencies and missing channel indices
|
|
56
|
+
"""
|
|
57
|
+
freqs_arr = freqs.value.astype(np.longdouble)
|
|
58
|
+
diffs = np.diff(freqs_arr)
|
|
59
|
+
min_diff = np.min(diffs)
|
|
60
|
+
# Create a new array with the minimum difference
|
|
61
|
+
new_freqs = np.arange(freqs_arr[0], freqs_arr[-1], min_diff)
|
|
62
|
+
missing_chan_idx = ~isin_close(new_freqs, freqs_arr)
|
|
63
|
+
|
|
64
|
+
return new_freqs * freqs.unit, missing_chan_idx
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def create_blank_data(
|
|
68
|
+
data_cube: np.ndarray,
|
|
69
|
+
freqs: u.Quantity,
|
|
70
|
+
idx: int,
|
|
71
|
+
) -> Tuple[Optional[np.ndarray], u.Quantity]:
|
|
72
|
+
"""Create a new data cube with evenly spaced frequencies, and fill in the missing channels with NaNs.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
data_cube (np.ndarray): Original data cube
|
|
76
|
+
freqs (u.Quantity): Original frequencies
|
|
77
|
+
idx: Index of frequency axis
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Tuple[Optional[np.ndarray], u.Quantity]: New data cube and frequencies
|
|
81
|
+
"""
|
|
82
|
+
new_freqs, missing_chan_idx = even_spacing(freqs)
|
|
83
|
+
# Check if all frequencies present
|
|
84
|
+
all_there = isin_close(freqs, new_freqs).all()
|
|
85
|
+
if not all_there:
|
|
86
|
+
return None, new_freqs
|
|
87
|
+
|
|
88
|
+
# Create a new data cube with the new frequencies
|
|
89
|
+
new_shape = list(data_cube.shape)
|
|
90
|
+
new_shape[idx] = len(new_freqs)
|
|
91
|
+
new_data_cube = np.empty(new_shape) * np.nan
|
|
92
|
+
for old_chan, freq in enumerate(freqs):
|
|
93
|
+
new_chans = np.where(np.isclose(new_freqs, freq))[0]
|
|
94
|
+
assert len(new_chans) == 1, "Too many matching channels"
|
|
95
|
+
new_chan = new_chans[0]
|
|
96
|
+
new_slice = [slice(None)] * len(new_shape)
|
|
97
|
+
new_slice[idx] = new_chan
|
|
98
|
+
old_slice = [slice(None)] * len(new_shape)
|
|
99
|
+
old_slice[idx] = old_chan
|
|
100
|
+
new_data_cube[tuple(new_slice)] = data_cube[tuple(old_slice)]
|
|
101
|
+
|
|
102
|
+
return new_data_cube, new_freqs
|
|
25
103
|
|
|
26
104
|
|
|
27
105
|
def init_cube(
|
|
@@ -131,11 +209,12 @@ def parse_freqs(
|
|
|
131
209
|
return freqs
|
|
132
210
|
|
|
133
211
|
|
|
134
|
-
def
|
|
212
|
+
def combine_fits(
|
|
135
213
|
file_list: List[str],
|
|
136
214
|
freq_file: Union[str, None] = None,
|
|
137
215
|
freq_list: Union[List[float], None] = None,
|
|
138
216
|
ignore_freq: bool = False,
|
|
217
|
+
create_blanks: bool = False,
|
|
139
218
|
) -> Tuple[fits.HDUList, u.Quantity]:
|
|
140
219
|
"""Combine FITS files into a cube.
|
|
141
220
|
|
|
@@ -197,6 +276,18 @@ def main(
|
|
|
197
276
|
data_cube[tuple(slicer)] = plane
|
|
198
277
|
# Write out cubes
|
|
199
278
|
even_freq = np.diff(freqs).std() < 1e-6 * u.Hz
|
|
279
|
+
if not even_freq and create_blanks:
|
|
280
|
+
print("Trying to create a blank cube with evenly spaced frequencies")
|
|
281
|
+
new_data_cube, new_freqs = create_blank_data(
|
|
282
|
+
data_cube=data_cube,
|
|
283
|
+
freqs=freqs,
|
|
284
|
+
idx=idx,
|
|
285
|
+
)
|
|
286
|
+
if new_data_cube is not None:
|
|
287
|
+
even_freq = True
|
|
288
|
+
data_cube = new_data_cube
|
|
289
|
+
freqs = new_freqs
|
|
290
|
+
|
|
200
291
|
if not even_freq:
|
|
201
292
|
print("WARNING: Frequencies are not evenly spaced")
|
|
202
293
|
print("Use the frequency file to specify the frequencies")
|
|
@@ -235,6 +326,11 @@ def cli():
|
|
|
235
326
|
action="store_true",
|
|
236
327
|
help="Overwrite output file if it exists",
|
|
237
328
|
)
|
|
329
|
+
parser.add_argument(
|
|
330
|
+
"--create-blanks",
|
|
331
|
+
action="store_true",
|
|
332
|
+
help="Try to create a blank cube with evenly spaced frequencies",
|
|
333
|
+
)
|
|
238
334
|
# Add options for specifying frequencies
|
|
239
335
|
group = parser.add_mutually_exclusive_group()
|
|
240
336
|
group.add_argument(
|
|
@@ -274,11 +370,12 @@ def cli():
|
|
|
274
370
|
if overwrite:
|
|
275
371
|
print("Overwriting output files")
|
|
276
372
|
|
|
277
|
-
hdul, freqs =
|
|
373
|
+
hdul, freqs = combine_fits(
|
|
278
374
|
file_list=args.file_list,
|
|
279
375
|
freq_file=args.freq_file,
|
|
280
376
|
freq_list=args.freqs,
|
|
281
377
|
ignore_freq=args.ignore_freq,
|
|
378
|
+
create_blanks=args.create_blanks,
|
|
282
379
|
)
|
|
283
380
|
|
|
284
381
|
hdul.writeto(out_cube, overwrite=overwrite)
|
|
@@ -16,13 +16,12 @@ from astropy.io import fits
|
|
|
16
16
|
from astropy.wcs import WCS
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
def
|
|
19
|
+
def combine_stokes(
|
|
20
20
|
stokes_I_file: str,
|
|
21
21
|
stokes_Q_file: str,
|
|
22
22
|
stokes_U_file: str,
|
|
23
23
|
stokes_V_file: Union[str, None] = None,
|
|
24
24
|
) -> fits.HDUList:
|
|
25
|
-
|
|
26
25
|
# Read in the data
|
|
27
26
|
stokes_I = fits.getdata(stokes_I_file)
|
|
28
27
|
stokes_Q = fits.getdata(stokes_Q_file)
|
|
@@ -115,7 +114,7 @@ def cli():
|
|
|
115
114
|
f"Output file {output_file} already exists. Use --overwrite to overwrite."
|
|
116
115
|
)
|
|
117
116
|
|
|
118
|
-
hdul =
|
|
117
|
+
hdul = combine_stokes(
|
|
119
118
|
stokes_I_file=args.stokes_I_file,
|
|
120
119
|
stokes_Q_file=args.stokes_Q_file,
|
|
121
120
|
stokes_U_file=args.stokes_U_file,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "fitscube"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.1"
|
|
4
4
|
description = ""
|
|
5
5
|
authors = ["Thomson, Alec (S&A, Kensington) <AlecThomson@users.noreply.github.com>"]
|
|
6
6
|
readme = "README.md"
|
|
7
7
|
|
|
8
8
|
[tool.poetry.dependencies]
|
|
9
9
|
python = "^3.7"
|
|
10
|
-
astropy = "
|
|
10
|
+
astropy = ">=5"
|
|
11
11
|
numpy = "^1.20"
|
|
12
12
|
tqdm = "*"
|
|
13
13
|
|
fitscube-0.2.2/setup.py
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
from setuptools import setup
|
|
3
|
-
|
|
4
|
-
packages = \
|
|
5
|
-
['fitscube']
|
|
6
|
-
|
|
7
|
-
package_data = \
|
|
8
|
-
{'': ['*']}
|
|
9
|
-
|
|
10
|
-
install_requires = \
|
|
11
|
-
['astropy>=5.0,<6.0', 'numpy>=1.20,<2.0', 'tqdm']
|
|
12
|
-
|
|
13
|
-
entry_points = \
|
|
14
|
-
{'console_scripts': ['fitscube = fitscube.fitscube:cli',
|
|
15
|
-
'stokescube = fitscube.stokescube:cli']}
|
|
16
|
-
|
|
17
|
-
setup_kwargs = {
|
|
18
|
-
'name': 'fitscube',
|
|
19
|
-
'version': '0.2.2',
|
|
20
|
-
'description': '',
|
|
21
|
-
'long_description': "# FITSCUBE\n\nFrom the [wsclean](https://wsclean.readthedocs.io/) docs:\n> WSClean does not output these images in a normal “imaging cube” like CASA does, i.e., a single fits file with several images in it. For now I’ve decided not to implement this (one of the reasons for this is that information about the synthesized beam is not properly stored in a multi-frequency fits file). One has of course the option to combine the output manually, e.g. with a simple Python script.\n\nThis is a simple Python script to combine (single-frequency or single-Stokes) FITS images manually.\n\nCurrent assumptions:\n- All files have the same WCS\n- All files have the same shape / pixel grid\n- Frequency is either a WCS axis or in the REFFREQ header keyword\n- All the relevant information is in the first header of the first image\n\n## Installation\n\nInstall from PyPI (stable):\n```\npip install fitscube\n```\n\nOr, onstall from this git repo (latest):\n```bash\npip install git+https://github.com/AlecThomson/fitscube.git\n```\n\n## Usage\n\nCommand line:\n```bash\nfitscube -h\n# usage: fitscube [-h] [-o] [--freq-file FREQ_FILE | --freqs FREQS [FREQS ...] | --ignore-freq] file_list [file_list ...] out_cube\n\n# Fitscube: Combine single-frequency FITS files into a cube. Assumes: - All files have the same WCS - All files have the same shape / pixel grid -\n# Frequency is either a WCS axis or in the REFFREQ header keyword - All the relevant information is in the first header of the first image\n\n# positional arguments:\n# file_list List of FITS files to combine (in frequency order)\n# out_cube Output FITS file\n\n# optional arguments:\n# -h, --help show this help message and exit\n# -o, --overwrite Overwrite output file if it exists\n# --freq-file FREQ_FILE\n# File containing frequencies in Hz\n# --freqs FREQS [FREQS ...]\n# List of frequencies in Hz\n# --ignore-freq Ignore frequency information and just stack (probably not what you want)\n\nstokescube -h\n# usage: stokescube [-h] [-v STOKES_V_FILE] [--overwrite] stokes_I_file stokes_Q_file stokes_U_file output_file\n\n# Fitscube: Combine single-Stokes FITS files into a Stokes cube. Assumes: - All files have the same WCS - All files have the same shape / pixel\n# grid - All the relevant information is in the first header of the first image\n\n# positional arguments:\n# stokes_I_file Stokes I file\n# stokes_Q_file Stokes Q file\n# stokes_U_file Stokes U file\n# output_file Output file\n\n# optional arguments:\n# -h, --help show this help message and exit\n# -v STOKES_V_FILE, --stokes_V_file STOKES_V_FILE\n# Stokes V file\n# --overwrite Overwrite output file if it exists\n```\n\nPython:\n```python\nfrom fitscube import combine_fits, combine_stokes\n\nhdu_list, frequencies = combine_fits(\n ['file1.fits', 'file2.fits', 'file3.fits'],\n)\nhdus_list = combine_stokes(\n 'stokes_I.fits',\n 'stokes_Q.fits',\n 'stokes_U.fits',\n)\n\n```\n\n## Convolving to a common resolution\nSee [RACS-Tools](https://github.com/AlecThomson/RACS-tools).\n\n## License\nMIT\n\n## Contributing\nContributions are welcome. Please open an issue or pull request.\n\n## TODO\n- [ ] Add support for non-frequency axes\n- [ ] Add tracking of the PSF in header / beamtable\n- [ ] Add convolution to a common resolution via RACS-Tools",
|
|
22
|
-
'author': 'Thomson, Alec (S&A, Kensington)',
|
|
23
|
-
'author_email': 'AlecThomson@users.noreply.github.com',
|
|
24
|
-
'maintainer': 'None',
|
|
25
|
-
'maintainer_email': 'None',
|
|
26
|
-
'url': 'None',
|
|
27
|
-
'packages': packages,
|
|
28
|
-
'package_data': package_data,
|
|
29
|
-
'install_requires': install_requires,
|
|
30
|
-
'entry_points': entry_points,
|
|
31
|
-
'python_requires': '>=3.7,<4.0',
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
setup(**setup_kwargs)
|
|
File without changes
|