pyFOCI 0.2.2__tar.gz → 0.3.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.
- {pyfoci-0.2.2 → pyfoci-0.3.0}/.github/workflows/deploy-gh-pages.yml +1 -1
- {pyfoci-0.2.2 → pyfoci-0.3.0}/.github/workflows/lint.yml +1 -1
- {pyfoci-0.2.2 → pyfoci-0.3.0}/.github/workflows/python-app.yml +1 -1
- {pyfoci-0.2.2 → pyfoci-0.3.0}/.github/workflows/release.yml +4 -4
- {pyfoci-0.2.2 → pyfoci-0.3.0}/CHANGELOG.md +17 -2
- {pyfoci-0.2.2/pyFOCI.egg-info → pyfoci-0.3.0}/PKG-INFO +1 -1
- {pyfoci-0.2.2 → pyfoci-0.3.0}/dev-readme.txt +12 -4
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyFOCI/_foci.py +91 -21
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyFOCI/_version.py +3 -3
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyFOCI/tests/test_foci.py +35 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0/pyFOCI.egg-info}/PKG-INFO +1 -1
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyFOCI.egg-info/SOURCES.txt +2 -0
- pyfoci-0.3.0/pyFOCI.egg-info/scm_file_list.json +49 -0
- pyfoci-0.3.0/pyFOCI.egg-info/scm_version.json +8 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/.codecov.yml +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/.coveragerc +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/.github/dependabot.yml +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/.gitignore +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/.pre-commit-config.yaml +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/CITATION.cff +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/LICENSE +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/README.md +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/Makefile +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/_static/css/project-template.css +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/_static/img/index_api.svg +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/_static/img/index_examples.svg +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/_static/img/index_getting_started.svg +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/_static/img/index_user_guide.svg +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/_static/img/logo.png +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/_static/js/copybutton.js +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/_templates/class.rst +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/_templates/function.rst +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/_templates/numpydoc_docstring.py +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/_templates/sidebar-search-bs.html +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/api.rst +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/conf.py +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/index.rst +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/make.bat +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/quick_start.rst +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/doc/user_guide.rst +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/examples/README.txt +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/examples/plot_FOCISelector.py +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pixi.lock +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyFOCI/__init__.py +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyFOCI/tests/__init__.py +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyFOCI/tests/test_common.py +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyFOCI/utils/__init__.py +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyFOCI/utils/discovery.py +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyFOCI/utils/tests/__init__.py +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyFOCI/utils/tests/test_discovery.py +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyFOCI.egg-info/dependency_links.txt +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyFOCI.egg-info/requires.txt +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyFOCI.egg-info/top_level.txt +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/pyproject.toml +0 -0
- {pyfoci-0.2.2 → pyfoci-0.3.0}/setup.cfg +0 -0
|
@@ -12,7 +12,7 @@ jobs:
|
|
|
12
12
|
|
|
13
13
|
steps:
|
|
14
14
|
- name: Checkout
|
|
15
|
-
uses: actions/checkout@
|
|
15
|
+
uses: actions/checkout@v7
|
|
16
16
|
|
|
17
17
|
- name: Install Pixi
|
|
18
18
|
uses: prefix-dev/setup-pixi@v0.9.6
|
|
@@ -85,7 +85,7 @@ jobs:
|
|
|
85
85
|
if: startsWith(github.ref, 'refs/tags/')
|
|
86
86
|
steps:
|
|
87
87
|
- name: Checkout
|
|
88
|
-
uses: actions/checkout@
|
|
88
|
+
uses: actions/checkout@v7 # needed so we can read CHANGELOG.md
|
|
89
89
|
|
|
90
90
|
- name: Download artifacts
|
|
91
91
|
uses: actions/download-artifact@v8
|
|
@@ -122,14 +122,14 @@ jobs:
|
|
|
122
122
|
|
|
123
123
|
- name: Create release (from CHANGELOG)
|
|
124
124
|
if: steps.changelog.outputs.body_path != ''
|
|
125
|
-
uses: softprops/action-gh-release@
|
|
125
|
+
uses: softprops/action-gh-release@v3
|
|
126
126
|
with:
|
|
127
127
|
body_path: release_body.md
|
|
128
128
|
files: dist/*
|
|
129
129
|
|
|
130
130
|
- name: Create release (auto-generated notes fallback)
|
|
131
131
|
if: steps.changelog.outputs.use_auto_notes == 'true'
|
|
132
|
-
uses: softprops/action-gh-release@
|
|
132
|
+
uses: softprops/action-gh-release@v3
|
|
133
133
|
with:
|
|
134
134
|
generate_release_notes: true
|
|
135
135
|
files: dist/*
|
|
@@ -5,16 +5,31 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/2.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.3.0] - 2026-06-26
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Introduced an alternative nearest neighbors selection algorithm, similar to the R reference implementation.
|
|
12
|
+
It is exposed with the new keyword-only `FOCISelector` parameter `nn_strategy="grouping"`.
|
|
13
|
+
The original algorithm remains available with `nn_strategy="radius"`.
|
|
14
|
+
|
|
15
|
+
## Changed
|
|
16
|
+
- Made `nn_strategy="grouping"` the new default, because it is faster.
|
|
17
|
+
|
|
18
|
+
## [0.2.3] - 2026-06-23
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- Updated Action for creating GitHub releases.
|
|
22
|
+
|
|
8
23
|
## [0.2.2] - 2026-06-17
|
|
9
24
|
|
|
10
25
|
### Added
|
|
11
|
-
- There is now a changelog, which is also used for the
|
|
26
|
+
- There is now a changelog, which is also used for the GitHub releases.
|
|
12
27
|
|
|
13
28
|
## [0.2.1] - 2026-06-17
|
|
14
29
|
|
|
15
30
|
### Changed
|
|
16
31
|
- Input features are now N(0,1)-normalized by default.
|
|
17
|
-
This can be switched off with the new parameter `standardize` by setting it to
|
|
32
|
+
This can be switched off with the new parameter `standardize` by setting it to `None`.
|
|
18
33
|
|
|
19
34
|
## [0.2.0] - 2026-06-16
|
|
20
35
|
|
|
@@ -9,6 +9,7 @@ pixi run -e test test
|
|
|
9
9
|
# Also examine the resulting coverage.xml.
|
|
10
10
|
|
|
11
11
|
pixi run -e doc build-doc
|
|
12
|
+
# Also examine the resulting example plot.
|
|
12
13
|
|
|
13
14
|
Commit to a dev branch.
|
|
14
15
|
|
|
@@ -17,7 +18,7 @@ pixi run build
|
|
|
17
18
|
|
|
18
19
|
2. CI:
|
|
19
20
|
|
|
20
|
-
Push dev branch to
|
|
21
|
+
Push dev branch to GitHub.
|
|
21
22
|
|
|
22
23
|
Create pull request to trigger CI tests.
|
|
23
24
|
|
|
@@ -26,13 +27,20 @@ Create pull request to trigger CI tests.
|
|
|
26
27
|
printf 'Fast-forwarding main to dev: '; git merge-base --is-ancestor main dev && git branch -f main dev && echo OK || echo ERROR
|
|
27
28
|
|
|
28
29
|
git push origin main:main
|
|
29
|
-
# By this, The
|
|
30
|
+
# By this, The GitHub repo setting "Automatically delete head branches"
|
|
30
31
|
# deletes the dev branch in the pull request, for easier creation of the next pull request from dev.
|
|
31
32
|
|
|
33
|
+
Update the [Unreleased] changelog section
|
|
34
|
+
|
|
32
35
|
|
|
33
36
|
Releasing:
|
|
34
37
|
==========
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
Select a version like `0.1.2`, following [Semantic Versioning](https://semver.org/).
|
|
40
|
+
|
|
41
|
+
Update the changelog, commit with "Release 0.1.2".
|
|
42
|
+
|
|
43
|
+
Tag the commit as "v0.1.2" and push it, including the tag.
|
|
44
|
+
|
|
45
|
+
GitHub actions will then update the online docs and publish this release on GitHub and PyPI.
|
|
38
46
|
|
|
@@ -51,7 +51,78 @@ def _rank_max(y):
|
|
|
51
51
|
return ranks
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
def
|
|
54
|
+
def _nn_radius_based(X_sub, random_state):
|
|
55
|
+
"""Radius-based NN selection with random tie breaking."""
|
|
56
|
+
X_sub = np.asarray(X_sub)
|
|
57
|
+
n = X_sub.shape[0]
|
|
58
|
+
|
|
59
|
+
# Fit NN on X_sub
|
|
60
|
+
nbrs = sklearn.neighbors.NearestNeighbors(n_neighbors=2, algorithm="ball_tree")
|
|
61
|
+
nbrs.fit(X_sub)
|
|
62
|
+
|
|
63
|
+
# Get min distances
|
|
64
|
+
distances, _ = nbrs.kneighbors(n_neighbors=1)
|
|
65
|
+
min_distance = distances[:, 0]
|
|
66
|
+
|
|
67
|
+
eps = 1e-13 # to get all neighbors of min distance
|
|
68
|
+
# For each i, collect all min-dist neighbors, remove self, pick one at random
|
|
69
|
+
nbr_i = np.empty(n, dtype=int)
|
|
70
|
+
for i in range(n):
|
|
71
|
+
# Query neighbors in the tight radius around the nearest neighbor distance
|
|
72
|
+
neighbors = nbrs.radius_neighbors(
|
|
73
|
+
X_sub[i, :].reshape(1, -1), min_distance[i] + eps, return_distance=False
|
|
74
|
+
)[0]
|
|
75
|
+
# Remove self index if present
|
|
76
|
+
neighbors = neighbors[neighbors != i]
|
|
77
|
+
nbr_i[i] = random_state.choice(neighbors)
|
|
78
|
+
|
|
79
|
+
return nbr_i
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _nn_grouping_based(X_sub, random_state):
|
|
83
|
+
"""Grouping-based NN selection with random tie-breaking.
|
|
84
|
+
|
|
85
|
+
Precondition: n_samples >= 2.
|
|
86
|
+
"""
|
|
87
|
+
X_sub = np.asarray(X_sub)
|
|
88
|
+
n = X_sub.shape[0]
|
|
89
|
+
|
|
90
|
+
# 1) Group exactly identical rows
|
|
91
|
+
Xu, inv = np.unique(X_sub, axis=0, return_inverse=True) # Xu: (m, p)
|
|
92
|
+
m = Xu.shape[0]
|
|
93
|
+
|
|
94
|
+
groups = [[] for _ in range(m)]
|
|
95
|
+
for i, g in enumerate(inv):
|
|
96
|
+
groups[g].append(i)
|
|
97
|
+
groups = [np.asarray(g, dtype=int) for g in groups]
|
|
98
|
+
|
|
99
|
+
nbr_i = np.empty(n, dtype=int)
|
|
100
|
+
|
|
101
|
+
for i in range(n):
|
|
102
|
+
gi = inv[i]
|
|
103
|
+
members = groups[gi]
|
|
104
|
+
|
|
105
|
+
# repeated data: choose another member of same group at random
|
|
106
|
+
if members.size >= 2:
|
|
107
|
+
choices = members[members != i]
|
|
108
|
+
nbr_i[i] = int(random_state.choice(choices))
|
|
109
|
+
continue
|
|
110
|
+
|
|
111
|
+
# per-query brute-force distances to all unique rows
|
|
112
|
+
diff = Xu - Xu[gi] # (m, p)
|
|
113
|
+
d2 = (diff * diff).sum(axis=1) # rowwise dot products
|
|
114
|
+
d2[gi] = np.inf # exclude self
|
|
115
|
+
|
|
116
|
+
# Choose among all original indices whose (unique) row is at minimal distance
|
|
117
|
+
dmin = d2.min()
|
|
118
|
+
tied = np.flatnonzero(d2 == dmin) # tied unique rows
|
|
119
|
+
candidates = np.concatenate([groups[u] for u in tied])
|
|
120
|
+
nbr_i[i] = int(random_state.choice(candidates))
|
|
121
|
+
|
|
122
|
+
return nbr_i
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _Tn(X_sub, y_rank, random_state, *, nn_strategy="grouping"):
|
|
55
126
|
"""Compute :math:`T_n` following Fuchs (2024).
|
|
56
127
|
|
|
57
128
|
The implementation uses the expression for :math:`T_n` given in
|
|
@@ -70,6 +141,8 @@ def _Tn(X_sub, y_rank, random_state):
|
|
|
70
141
|
:func:`_rank_max`.
|
|
71
142
|
random_state : numpy.random.RandomState
|
|
72
143
|
Random number generator used to break nearest-neighbor ties.
|
|
144
|
+
nn_strategy : {"grouping", "radius"}, default="grouping"
|
|
145
|
+
Strategy used to select the nearest neighbor indices.
|
|
73
146
|
|
|
74
147
|
Returns
|
|
75
148
|
-------
|
|
@@ -78,25 +151,12 @@ def _Tn(X_sub, y_rank, random_state):
|
|
|
78
151
|
"""
|
|
79
152
|
X_sub = np.asarray(X_sub)
|
|
80
153
|
n = X_sub.shape[0]
|
|
81
|
-
# Fit NN on X_sub
|
|
82
|
-
nbrs = sklearn.neighbors.NearestNeighbors(n_neighbors=2, algorithm="ball_tree")
|
|
83
|
-
nbrs.fit(X_sub)
|
|
84
|
-
|
|
85
|
-
# Get min distances
|
|
86
|
-
distances, _ = nbrs.kneighbors(n_neighbors=1)
|
|
87
|
-
min_distance = distances[:, 0]
|
|
88
154
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
neighbors = nbrs.radius_neighbors(
|
|
95
|
-
X_sub[i, :].reshape(1, -1), min_distance[i] + eps, return_distance=False
|
|
96
|
-
)[0]
|
|
97
|
-
# Remove self index if present
|
|
98
|
-
neighbors = neighbors[neighbors != i]
|
|
99
|
-
nbr_i[i] = random_state.choice(neighbors)
|
|
155
|
+
if nn_strategy == "grouping":
|
|
156
|
+
nbr_i = _nn_grouping_based(X_sub, random_state)
|
|
157
|
+
else:
|
|
158
|
+
assert nn_strategy == "radius"
|
|
159
|
+
nbr_i = _nn_radius_based(X_sub, random_state)
|
|
100
160
|
|
|
101
161
|
# Apply the formula (indices are 0-based; y_rank is 1-based)
|
|
102
162
|
term1 = np.sum(np.abs(y_rank - y_rank[nbr_i]))
|
|
@@ -146,6 +206,9 @@ class FOCISelector(SelectorMixin, BaseEstimator):
|
|
|
146
206
|
variance before computing nearest neighbors. If None, X is used as-is.
|
|
147
207
|
Columns with zero variance are left unchanged.
|
|
148
208
|
|
|
209
|
+
nn_strategy : {"grouping", "radius"}, default="grouping"
|
|
210
|
+
Strategy used to select nearest neighbors for computing :math:`T_n`.
|
|
211
|
+
|
|
149
212
|
random_state : int, RandomState instance or None, default=None
|
|
150
213
|
Controls the random tie-breaking among nearest neighbors. Pass an int
|
|
151
214
|
for reproducible results across multiple calls. If None, the global
|
|
@@ -180,15 +243,22 @@ class FOCISelector(SelectorMixin, BaseEstimator):
|
|
|
180
243
|
"max_features": [None, Interval(Integral, 1, None, closed="left")],
|
|
181
244
|
"min_delta": [None, Interval(Real, None, None, closed="neither")],
|
|
182
245
|
"standardize": [None, StrOptions({"normalize"})],
|
|
246
|
+
"nn_strategy": [StrOptions({"grouping", "radius"})],
|
|
183
247
|
"random_state": ["random_state"],
|
|
184
248
|
}
|
|
185
249
|
|
|
186
250
|
def __init__(
|
|
187
|
-
self,
|
|
251
|
+
self,
|
|
252
|
+
max_features=None,
|
|
253
|
+
min_delta=0,
|
|
254
|
+
standardize="normalize",
|
|
255
|
+
nn_strategy="grouping",
|
|
256
|
+
random_state=None,
|
|
188
257
|
):
|
|
189
258
|
self.max_features = max_features
|
|
190
259
|
self.min_delta = min_delta
|
|
191
260
|
self.standardize = standardize
|
|
261
|
+
self.nn_strategy = nn_strategy
|
|
192
262
|
self.random_state = random_state
|
|
193
263
|
|
|
194
264
|
@_fit_context(prefer_skip_nested_validation=True)
|
|
@@ -249,7 +319,7 @@ class FOCISelector(SelectorMixin, BaseEstimator):
|
|
|
249
319
|
for j in remaining:
|
|
250
320
|
sel_candidate = selected + [j]
|
|
251
321
|
X_sub = X[:, sel_candidate]
|
|
252
|
-
Tn_val = _Tn(X_sub, y_rank, random_state)
|
|
322
|
+
Tn_val = _Tn(X_sub, y_rank, random_state, nn_strategy=self.nn_strategy)
|
|
253
323
|
if Tn_val > best_Tn:
|
|
254
324
|
best_Tn = Tn_val
|
|
255
325
|
best_j = j
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.
|
|
22
|
-
__version_tuple__ = version_tuple = (0,
|
|
21
|
+
__version__ = version = '0.3.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 3, 0)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g3d446d680'
|
|
@@ -167,3 +167,38 @@ def test_random_state_int_reproducible():
|
|
|
167
167
|
selector_1.Tn_path_,
|
|
168
168
|
selector_2.Tn_path_,
|
|
169
169
|
)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def test_nn_strategy_grouping_and_radius_are_accepted_and_reproducible():
|
|
173
|
+
X_df, y = make_demo_data(n=200, p=10, seed=0)
|
|
174
|
+
|
|
175
|
+
for strategy in ("grouping", "radius"):
|
|
176
|
+
selector_1 = FOCISelector(
|
|
177
|
+
random_state=0, nn_strategy=strategy, min_delta=None, max_features=3
|
|
178
|
+
).fit(X_df, y)
|
|
179
|
+
selector_2 = FOCISelector(
|
|
180
|
+
random_state=0, nn_strategy=strategy, min_delta=None, max_features=3
|
|
181
|
+
).fit(X_df, y)
|
|
182
|
+
|
|
183
|
+
# Non-trivial selection (avoid early stopping selecting none)
|
|
184
|
+
assert selector_1.support_mask_.sum() > 2
|
|
185
|
+
|
|
186
|
+
np.testing.assert_array_equal(
|
|
187
|
+
selector_1.selected_indices_,
|
|
188
|
+
selector_2.selected_indices_,
|
|
189
|
+
)
|
|
190
|
+
assert_allclose(
|
|
191
|
+
selector_1.Tn_path_,
|
|
192
|
+
selector_2.Tn_path_,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def test_nn_strategy_invalid_raises():
|
|
197
|
+
random_state = np.random.RandomState(0)
|
|
198
|
+
X = random_state.normal(size=(20, 3))
|
|
199
|
+
y = random_state.normal(size=20)
|
|
200
|
+
|
|
201
|
+
sel = FOCISelector(nn_strategy="invalid")
|
|
202
|
+
expected = "The 'nn_strategy' parameter of FOCISelector must be"
|
|
203
|
+
with pytest.raises(InvalidParameterError, match=re.escape(expected)):
|
|
204
|
+
sel.fit(X, y)
|
|
@@ -41,6 +41,8 @@ pyFOCI.egg-info/PKG-INFO
|
|
|
41
41
|
pyFOCI.egg-info/SOURCES.txt
|
|
42
42
|
pyFOCI.egg-info/dependency_links.txt
|
|
43
43
|
pyFOCI.egg-info/requires.txt
|
|
44
|
+
pyFOCI.egg-info/scm_file_list.json
|
|
45
|
+
pyFOCI.egg-info/scm_version.json
|
|
44
46
|
pyFOCI.egg-info/top_level.txt
|
|
45
47
|
pyFOCI/tests/__init__.py
|
|
46
48
|
pyFOCI/tests/test_common.py
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"files": [
|
|
3
|
+
".coveragerc",
|
|
4
|
+
"CITATION.cff",
|
|
5
|
+
".pre-commit-config.yaml",
|
|
6
|
+
"README.md",
|
|
7
|
+
"LICENSE",
|
|
8
|
+
".codecov.yml",
|
|
9
|
+
"pyproject.toml",
|
|
10
|
+
"CHANGELOG.md",
|
|
11
|
+
"dev-readme.txt",
|
|
12
|
+
"pixi.lock",
|
|
13
|
+
".gitignore",
|
|
14
|
+
"doc/Makefile",
|
|
15
|
+
"doc/quick_start.rst",
|
|
16
|
+
"doc/index.rst",
|
|
17
|
+
"doc/api.rst",
|
|
18
|
+
"doc/make.bat",
|
|
19
|
+
"doc/user_guide.rst",
|
|
20
|
+
"doc/conf.py",
|
|
21
|
+
"doc/_static/img/logo.png",
|
|
22
|
+
"doc/_static/img/index_getting_started.svg",
|
|
23
|
+
"doc/_static/img/index_examples.svg",
|
|
24
|
+
"doc/_static/img/index_user_guide.svg",
|
|
25
|
+
"doc/_static/img/index_api.svg",
|
|
26
|
+
"doc/_static/css/project-template.css",
|
|
27
|
+
"doc/_static/js/copybutton.js",
|
|
28
|
+
"doc/_templates/numpydoc_docstring.py",
|
|
29
|
+
"doc/_templates/function.rst",
|
|
30
|
+
"doc/_templates/sidebar-search-bs.html",
|
|
31
|
+
"doc/_templates/class.rst",
|
|
32
|
+
"pyFOCI/__init__.py",
|
|
33
|
+
"pyFOCI/_foci.py",
|
|
34
|
+
"pyFOCI/utils/__init__.py",
|
|
35
|
+
"pyFOCI/utils/discovery.py",
|
|
36
|
+
"pyFOCI/utils/tests/__init__.py",
|
|
37
|
+
"pyFOCI/utils/tests/test_discovery.py",
|
|
38
|
+
"pyFOCI/tests/__init__.py",
|
|
39
|
+
"pyFOCI/tests/test_foci.py",
|
|
40
|
+
"pyFOCI/tests/test_common.py",
|
|
41
|
+
"examples/plot_FOCISelector.py",
|
|
42
|
+
"examples/README.txt",
|
|
43
|
+
".github/dependabot.yml",
|
|
44
|
+
".github/workflows/release.yml",
|
|
45
|
+
".github/workflows/python-app.yml",
|
|
46
|
+
".github/workflows/lint.yml",
|
|
47
|
+
".github/workflows/deploy-gh-pages.yml"
|
|
48
|
+
]
|
|
49
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|