SeInE-orientation 0.1.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.
- seine_orientation-0.1.0/.github/workflows/release.yml +51 -0
- seine_orientation-0.1.0/.gitignore +11 -0
- seine_orientation-0.1.0/PKG-INFO +13 -0
- seine_orientation-0.1.0/README.md +1 -0
- seine_orientation-0.1.0/SeInE_orientation.egg-info/PKG-INFO +13 -0
- seine_orientation-0.1.0/SeInE_orientation.egg-info/SOURCES.txt +20 -0
- seine_orientation-0.1.0/SeInE_orientation.egg-info/dependency_links.txt +1 -0
- seine_orientation-0.1.0/SeInE_orientation.egg-info/requires.txt +4 -0
- seine_orientation-0.1.0/SeInE_orientation.egg-info/scm_file_list.json +16 -0
- seine_orientation-0.1.0/SeInE_orientation.egg-info/scm_version.json +8 -0
- seine_orientation-0.1.0/SeInE_orientation.egg-info/top_level.txt +1 -0
- seine_orientation-0.1.0/pyproject.toml +33 -0
- seine_orientation-0.1.0/seine_orientation/BayesModel.py +283 -0
- seine_orientation-0.1.0/seine_orientation/__init__.py +2 -0
- seine_orientation-0.1.0/seine_orientation/_version.py +24 -0
- seine_orientation-0.1.0/seine_orientation/process_session.py +269 -0
- seine_orientation-0.1.0/seine_orientation/utils/__init__.py +11 -0
- seine_orientation-0.1.0/seine_orientation/utils/display_inference_results.py +443 -0
- seine_orientation-0.1.0/seine_orientation/utils/utils_analysis.py +239 -0
- seine_orientation-0.1.0/seine_orientation/utils/utils_display.py +109 -0
- seine_orientation-0.1.0/seine_orientation/utils/utils_model.py +283 -0
- seine_orientation-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
with:
|
|
15
|
+
fetch-depth: 0
|
|
16
|
+
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.x"
|
|
20
|
+
|
|
21
|
+
- name: Install build tools
|
|
22
|
+
run: python -m pip install --upgrade build
|
|
23
|
+
|
|
24
|
+
- name: Build package
|
|
25
|
+
run: python -m build
|
|
26
|
+
|
|
27
|
+
- name: Upload distribution artifacts
|
|
28
|
+
uses: actions/upload-artifact@v4
|
|
29
|
+
with:
|
|
30
|
+
name: python-package-distributions
|
|
31
|
+
path: dist/
|
|
32
|
+
|
|
33
|
+
publish:
|
|
34
|
+
needs: build
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
|
|
37
|
+
environment:
|
|
38
|
+
name: pypi
|
|
39
|
+
|
|
40
|
+
permissions:
|
|
41
|
+
id-token: write
|
|
42
|
+
|
|
43
|
+
steps:
|
|
44
|
+
- name: Download distributions
|
|
45
|
+
uses: actions/download-artifact@v4
|
|
46
|
+
with:
|
|
47
|
+
name: python-package-distributions
|
|
48
|
+
path: dist/
|
|
49
|
+
|
|
50
|
+
- name: Publish to PyPI
|
|
51
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: SeInE-orientation
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Orientation Selectivity Inference from a Gabor model
|
|
5
|
+
Author: Alexander Schmidt
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: numpy
|
|
9
|
+
Requires-Dist: scipy
|
|
10
|
+
Requires-Dist: SeInE-HB>=0.1.3
|
|
11
|
+
Requires-Dist: event-estimator>=0.1.1
|
|
12
|
+
|
|
13
|
+
Inferring model parameters of tilted Gabor-filter with non-linear response rate and overdispersed spike count responses, using SeInE
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Inferring model parameters of tilted Gabor-filter with non-linear response rate and overdispersed spike count responses, using SeInE
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: SeInE-orientation
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Orientation Selectivity Inference from a Gabor model
|
|
5
|
+
Author: Alexander Schmidt
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: numpy
|
|
9
|
+
Requires-Dist: scipy
|
|
10
|
+
Requires-Dist: SeInE-HB>=0.1.3
|
|
11
|
+
Requires-Dist: event-estimator>=0.1.1
|
|
12
|
+
|
|
13
|
+
Inferring model parameters of tilted Gabor-filter with non-linear response rate and overdispersed spike count responses, using SeInE
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
.gitignore
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
.github/workflows/release.yml
|
|
5
|
+
SeInE_orientation.egg-info/PKG-INFO
|
|
6
|
+
SeInE_orientation.egg-info/SOURCES.txt
|
|
7
|
+
SeInE_orientation.egg-info/dependency_links.txt
|
|
8
|
+
SeInE_orientation.egg-info/requires.txt
|
|
9
|
+
SeInE_orientation.egg-info/scm_file_list.json
|
|
10
|
+
SeInE_orientation.egg-info/scm_version.json
|
|
11
|
+
SeInE_orientation.egg-info/top_level.txt
|
|
12
|
+
seine_orientation/BayesModel.py
|
|
13
|
+
seine_orientation/__init__.py
|
|
14
|
+
seine_orientation/_version.py
|
|
15
|
+
seine_orientation/process_session.py
|
|
16
|
+
seine_orientation/utils/__init__.py
|
|
17
|
+
seine_orientation/utils/display_inference_results.py
|
|
18
|
+
seine_orientation/utils/utils_analysis.py
|
|
19
|
+
seine_orientation/utils/utils_display.py
|
|
20
|
+
seine_orientation/utils/utils_model.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"files": [
|
|
3
|
+
".github/workflows/release.yml",
|
|
4
|
+
".gitignore",
|
|
5
|
+
"README.md",
|
|
6
|
+
"pyproject.toml",
|
|
7
|
+
"seine_orientation/BayesModel.py",
|
|
8
|
+
"seine_orientation/__init__.py",
|
|
9
|
+
"seine_orientation/process_session.py",
|
|
10
|
+
"seine_orientation/utils/__init__.py",
|
|
11
|
+
"seine_orientation/utils/display_inference_results.py",
|
|
12
|
+
"seine_orientation/utils/utils_analysis.py",
|
|
13
|
+
"seine_orientation/utils/utils_display.py",
|
|
14
|
+
"seine_orientation/utils/utils_model.py"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
seine_orientation
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = [
|
|
3
|
+
"setuptools>=77.0.3",
|
|
4
|
+
"setuptools-scm>=8",
|
|
5
|
+
]
|
|
6
|
+
build-backend = "setuptools.build_meta"
|
|
7
|
+
|
|
8
|
+
[project]
|
|
9
|
+
name = "SeInE-orientation"
|
|
10
|
+
dynamic = ["version"]
|
|
11
|
+
description = "Orientation Selectivity Inference from a Gabor model"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.11"
|
|
14
|
+
license = { file = "LICENSE" }
|
|
15
|
+
|
|
16
|
+
authors = [
|
|
17
|
+
{ name = "Alexander Schmidt" }
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
dependencies = [
|
|
21
|
+
"numpy",
|
|
22
|
+
"scipy",
|
|
23
|
+
"SeInE-HB>=0.1.3",
|
|
24
|
+
"event-estimator>=0.1.1"
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[tool.setuptools.packages.find]
|
|
28
|
+
where = ["."]
|
|
29
|
+
include = ["seine_orientation*"]
|
|
30
|
+
|
|
31
|
+
[tool.setuptools_scm]
|
|
32
|
+
version_file = "seine_orientation/_version.py"
|
|
33
|
+
local_scheme = "no-local-version"
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import time
|
|
3
|
+
import itertools
|
|
4
|
+
|
|
5
|
+
from seine.NestedSamplingMethods import (
|
|
6
|
+
run_sampling,
|
|
7
|
+
)
|
|
8
|
+
from seine import HierarchicalModel, functions as prior_fn
|
|
9
|
+
from seine.structures import (
|
|
10
|
+
prior_structure,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
from .utils import gabor_filter, gabor_response, sine_grating, softplus, ReLU, sigmoid
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class HierarchicalBayesInference(HierarchicalModel):
|
|
17
|
+
|
|
18
|
+
def set_gratings(self, measure_points, FoV_range, FoV_steps):
|
|
19
|
+
|
|
20
|
+
self.measure_points = measure_points
|
|
21
|
+
|
|
22
|
+
self.X_FoV, self.Y_FoV = np.meshgrid(
|
|
23
|
+
np.linspace(-FoV_range[0] / 2, FoV_range[0] / 2, FoV_steps),
|
|
24
|
+
np.linspace(-FoV_range[1] / 2, FoV_range[1] / 2, FoV_steps),
|
|
25
|
+
)
|
|
26
|
+
self.FoV_grid = np.dstack((self.X_FoV, self.Y_FoV))
|
|
27
|
+
|
|
28
|
+
FoV_steps = self.X_FoV.shape[0]
|
|
29
|
+
|
|
30
|
+
self.gratings = np.zeros(
|
|
31
|
+
(
|
|
32
|
+
*[len(mp) for mp in self.measure_points],
|
|
33
|
+
FoV_steps,
|
|
34
|
+
FoV_steps,
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
for prod in itertools.product(
|
|
38
|
+
enumerate(self.measure_points[0]),
|
|
39
|
+
enumerate(self.measure_points[1]),
|
|
40
|
+
enumerate(self.measure_points[2]),
|
|
41
|
+
):
|
|
42
|
+
idx, elems = zip(*prod)
|
|
43
|
+
phi_0, theta, f = elems
|
|
44
|
+
self.gratings[*idx, ...] = sine_grating(
|
|
45
|
+
self.X_FoV, # [0, ...],
|
|
46
|
+
self.Y_FoV, # [0, ...],
|
|
47
|
+
theta,
|
|
48
|
+
f,
|
|
49
|
+
phi_0,
|
|
50
|
+
square=True,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def set_priors(self, priors_init=None, coding="simple"):
|
|
54
|
+
|
|
55
|
+
if priors_init is None:
|
|
56
|
+
|
|
57
|
+
if hasattr(self, "data"):
|
|
58
|
+
fmap = self.data["observed_counts"] / self.data["T"]
|
|
59
|
+
A0_guess, A_guess = np.percentile(fmap, [50, 90])
|
|
60
|
+
A0_guess = np.maximum(A0_guess, 1.0)
|
|
61
|
+
A_guess = np.maximum(A_guess, 2.0)
|
|
62
|
+
else:
|
|
63
|
+
A0_guess, A_guess = 1.0, 3.0
|
|
64
|
+
self.priors_init = {}
|
|
65
|
+
# print("A guesses from data:", A0_guess, A_guess)
|
|
66
|
+
|
|
67
|
+
## define gabor model priors
|
|
68
|
+
if coding in ["simple", "complex"]:
|
|
69
|
+
self.priors_init["theta"] = prior_structure(
|
|
70
|
+
prior_fn.bounded_flat,
|
|
71
|
+
low=-np.pi / 2,
|
|
72
|
+
high=np.pi / 2,
|
|
73
|
+
label=r"$\theta$",
|
|
74
|
+
periodic=True,
|
|
75
|
+
)
|
|
76
|
+
self.priors_init["f"] = prior_structure(
|
|
77
|
+
prior_fn.halfnorm_ppf,
|
|
78
|
+
loc=0.0,
|
|
79
|
+
scale=5.0,
|
|
80
|
+
label=r"$f$",
|
|
81
|
+
)
|
|
82
|
+
if coding == "simple":
|
|
83
|
+
## not required for complex cell model
|
|
84
|
+
self.priors_init["phi_0"] = prior_structure(
|
|
85
|
+
prior_fn.bounded_flat,
|
|
86
|
+
low=-np.pi,
|
|
87
|
+
high=np.pi,
|
|
88
|
+
periodic=True,
|
|
89
|
+
label=r"$\phi_0$",
|
|
90
|
+
)
|
|
91
|
+
else:
|
|
92
|
+
self.priors_init["phi_0"] = prior_structure(
|
|
93
|
+
None,
|
|
94
|
+
value=0.0,
|
|
95
|
+
periodic=True,
|
|
96
|
+
label=r"$\phi_0$",
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
self.priors_init["sigma"] = prior_structure(
|
|
100
|
+
prior_fn.halfnorm_ppf,
|
|
101
|
+
loc=0.05,
|
|
102
|
+
scale=0.1,
|
|
103
|
+
label=r"$\sigma$",
|
|
104
|
+
)
|
|
105
|
+
self.priors_init["gamma"] = prior_structure(
|
|
106
|
+
prior_fn.halfnorm_ppf,
|
|
107
|
+
loc=1.0,
|
|
108
|
+
scale=1.0,
|
|
109
|
+
label=r"$\gamma$",
|
|
110
|
+
)
|
|
111
|
+
self.priors_init["theta_gauss"] = prior_structure(
|
|
112
|
+
prior_fn.bounded_flat,
|
|
113
|
+
low=-np.pi / 2,
|
|
114
|
+
high=np.pi / 2,
|
|
115
|
+
periodic=True,
|
|
116
|
+
label=r"$\theta_{gauss}$",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
## define nonlinearity priors - should start with "nl_" to be recognized by model response function
|
|
120
|
+
self.priors_init["nl_baseline"] = prior_structure(
|
|
121
|
+
prior_fn.halfnorm_ppf,
|
|
122
|
+
loc=0.0,
|
|
123
|
+
scale=A0_guess,
|
|
124
|
+
label=r"$A_{baseline}$",
|
|
125
|
+
)
|
|
126
|
+
if coding in ["simple", "complex"]:
|
|
127
|
+
self.priors_init["nl_transition"] = prior_structure(
|
|
128
|
+
prior_fn.halfnorm_ppf,
|
|
129
|
+
loc=0.0,
|
|
130
|
+
scale=1.0,
|
|
131
|
+
label=r"$A_{transition}$",
|
|
132
|
+
)
|
|
133
|
+
self.priors_init["nl_amplitude"] = prior_structure(
|
|
134
|
+
prior_fn.halfnorm_ppf,
|
|
135
|
+
loc=A0_guess * 0.2,
|
|
136
|
+
scale=A_guess - A0_guess,
|
|
137
|
+
label=r"$A_{amplitude}$",
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# parameters for loglikelihood
|
|
141
|
+
self.priors_init["logl_alpha"] = prior_structure(
|
|
142
|
+
prior_fn.halfnorm_ppf,
|
|
143
|
+
loc=0.0,
|
|
144
|
+
scale=1.0,
|
|
145
|
+
label=r"$\alpha_{logl}$",
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
else:
|
|
149
|
+
self.priors_init = priors_init
|
|
150
|
+
|
|
151
|
+
super().set_priors(self.priors_init)
|
|
152
|
+
|
|
153
|
+
def get_model_rate_response(self, params, coding="simple"):
|
|
154
|
+
|
|
155
|
+
## transform parameters, if not already provided in proper format
|
|
156
|
+
if not isinstance(params, dict):
|
|
157
|
+
params = self.get_params_from_p(params)
|
|
158
|
+
|
|
159
|
+
## get (normalized) model response
|
|
160
|
+
if coding == "random":
|
|
161
|
+
response = np.zeros(self.dimensions["shape"])
|
|
162
|
+
else:
|
|
163
|
+
response = gabor_response(
|
|
164
|
+
self.X_FoV,
|
|
165
|
+
self.Y_FoV,
|
|
166
|
+
params,
|
|
167
|
+
self.gratings,
|
|
168
|
+
mode=coding,
|
|
169
|
+
significance_threshold=0.01,
|
|
170
|
+
logger=self.log,
|
|
171
|
+
)
|
|
172
|
+
self.timeit("calculating model and response firing rate")
|
|
173
|
+
|
|
174
|
+
## apply nonlinearity to adjust to scale of firing rates and get final model response in firing rate units
|
|
175
|
+
rate_response = self.apply_nonlinearity(response, params)
|
|
176
|
+
return rate_response
|
|
177
|
+
|
|
178
|
+
def apply_nonlinearity(self, response, params, nonlinearity="softplus"):
|
|
179
|
+
|
|
180
|
+
if nonlinearity == "softplus":
|
|
181
|
+
# print(
|
|
182
|
+
# f"Applying softplus nonlinearity with parameters: baseline={params.get('nl_baseline', 0.0):.3f}, transition={params.get('nl_transition', 1.0):.3f}, amplitude={params.get('nl_amplitude', 1.0):.3f}"
|
|
183
|
+
# )
|
|
184
|
+
rate_response = softplus(
|
|
185
|
+
response * params.get("nl_amplitude", 1.0),
|
|
186
|
+
alpha=params.get("nl_transition", 1.0),
|
|
187
|
+
delta=params.get("nl_baseline", 0.0),
|
|
188
|
+
)
|
|
189
|
+
elif nonlinearity == "ReLU":
|
|
190
|
+
# rate_response =
|
|
191
|
+
raise NotImplementedError("ReLU nonlinearity not implemented yet")
|
|
192
|
+
elif nonlinearity == "sigmoid":
|
|
193
|
+
raise NotImplementedError("Sigmoid nonlinearity not implemented yet")
|
|
194
|
+
else:
|
|
195
|
+
raise ValueError(f"Unknown nonlinearity: {nonlinearity}")
|
|
196
|
+
|
|
197
|
+
self.timeit("applying nonlinearity")
|
|
198
|
+
return rate_response
|
|
199
|
+
|
|
200
|
+
def set_logp_func(self, coding="simple"):
|
|
201
|
+
"""
|
|
202
|
+
some nice description
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
def get_logp(p_in):
|
|
206
|
+
|
|
207
|
+
self.timeit()
|
|
208
|
+
"""
|
|
209
|
+
build switch between 3 models:
|
|
210
|
+
- gabor type model
|
|
211
|
+
- fourier component model (with n components in each direction)
|
|
212
|
+
- ellipse in rate space
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
params = self.get_params_from_p(p_in)
|
|
216
|
+
self.timeit("transforming parameters")
|
|
217
|
+
|
|
218
|
+
model_rate_response = self.get_model_rate_response(params, coding)
|
|
219
|
+
if not (model_rate_response.shape == self.data["observed_counts"].shape):
|
|
220
|
+
model_rate_response = model_rate_response[None, ...]
|
|
221
|
+
|
|
222
|
+
logp = self.probability_of_spike_observation(
|
|
223
|
+
model_rate_response,
|
|
224
|
+
model="negative_binomial",
|
|
225
|
+
**params,
|
|
226
|
+
)
|
|
227
|
+
self.timeit("calculating log probability of spike observation")
|
|
228
|
+
|
|
229
|
+
return logp.sum()
|
|
230
|
+
|
|
231
|
+
return get_logp
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def run_inference(
|
|
235
|
+
hbm: HierarchicalBayesInference,
|
|
236
|
+
coding="simple",
|
|
237
|
+
n_live=200,
|
|
238
|
+
nP=1,
|
|
239
|
+
dlogz=1.0,
|
|
240
|
+
show_status=True,
|
|
241
|
+
):
|
|
242
|
+
hbm.set_priors(coding=coding)
|
|
243
|
+
my_trafo = hbm.set_prior_transform()
|
|
244
|
+
my_logp = hbm.set_logp_func(coding=coding)
|
|
245
|
+
|
|
246
|
+
results, sampler = run_sampling(
|
|
247
|
+
my_trafo,
|
|
248
|
+
my_logp,
|
|
249
|
+
hbm.parameter_names_all,
|
|
250
|
+
hbm.periodic,
|
|
251
|
+
show_status=show_status,
|
|
252
|
+
n_live=n_live,
|
|
253
|
+
nP=nP,
|
|
254
|
+
dlogz=dlogz,
|
|
255
|
+
)
|
|
256
|
+
return results
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def run_model_comparison(data, dwelltime, measure_points, show_status=True, **kwargs):
|
|
260
|
+
|
|
261
|
+
t_start = time.time()
|
|
262
|
+
hbm = HierarchicalBayesInference()
|
|
263
|
+
|
|
264
|
+
hbm.set_gratings(
|
|
265
|
+
measure_points,
|
|
266
|
+
[np.deg2rad(140), np.deg2rad(114)],
|
|
267
|
+
FoV_steps=51,
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
hbm.prepare_data(
|
|
271
|
+
data,
|
|
272
|
+
dwelltime,
|
|
273
|
+
iter_dims=False,
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
results = {}
|
|
277
|
+
for coding in ["random", "simple", "complex"]:
|
|
278
|
+
results[coding] = run_inference(
|
|
279
|
+
hbm, coding=coding, show_status=show_status, **kwargs
|
|
280
|
+
)
|
|
281
|
+
t_end = time.time()
|
|
282
|
+
print(f"Model comparison done after {t_end - t_start:.2f} seconds")
|
|
283
|
+
return results
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '0.1.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 0)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = 'gffe43a317'
|