brainstem-python-api-tools 0.2.0__py3-none-any.whl → 2.0.0__py3-none-any.whl

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.
@@ -0,0 +1,180 @@
1
+ """Command-line interface for BrainSTEM API tools.
2
+
3
+ Usage examples
4
+ --------------
5
+ brainstem login
6
+ brainstem login --headless
7
+ brainstem login --url http://127.0.0.1:8000/
8
+ brainstem logout
9
+ brainstem load session
10
+ brainstem load session --portal public --filters name.icontains=rat --sort -name
11
+ brainstem load session --id <uuid>
12
+ brainstem load session --limit 20 --offset 40
13
+ brainstem save session --data '{"name":"New","projects":["<uuid>"]}'
14
+ brainstem save session --id <uuid> --data '{"description":"updated"}'
15
+ brainstem delete session --id <uuid>
16
+ """
17
+
18
+ import argparse
19
+ import json
20
+ import os
21
+ import sys
22
+
23
+ from .brainstem_api_client import BrainstemClient, _MODEL_TO_APP, _TOKEN_FILE
24
+
25
+
26
+ def _build_parser() -> argparse.ArgumentParser:
27
+ # Shared flags available on every subcommand
28
+ common = argparse.ArgumentParser(add_help=False)
29
+ common.add_argument(
30
+ "--token",
31
+ default=os.environ.get("BRAINSTEM_API_TOKEN"),
32
+ help="API token. Defaults to $BRAINSTEM_API_TOKEN or the cached token.",
33
+ )
34
+ common.add_argument(
35
+ "--headless",
36
+ action="store_true",
37
+ help="Print verification URL + code instead of opening a browser.",
38
+ )
39
+ common.add_argument(
40
+ "--url",
41
+ default=None,
42
+ help="Base URL of the BrainSTEM server (default: https://www.brainstem.org/).",
43
+ )
44
+
45
+ parser = argparse.ArgumentParser(
46
+ prog="brainstem",
47
+ description="BrainSTEM command-line API client.",
48
+ parents=[common],
49
+ )
50
+
51
+ sub = parser.add_subparsers(dest="command", required=True)
52
+
53
+ # ---- login ------------------------------------------------------
54
+ sub.add_parser(
55
+ "login",
56
+ parents=[common],
57
+ help="Authenticate and cache your API token.",
58
+ )
59
+
60
+ # ---- logout -----------------------------------------------------
61
+ sub.add_parser(
62
+ "logout",
63
+ parents=[common],
64
+ help="Remove the cached API token.",
65
+ )
66
+
67
+ # ---- load -------------------------------------------------------
68
+ p_load = sub.add_parser("load", parents=[common], help="Load records from BrainSTEM.")
69
+ p_load.add_argument("model", choices=sorted(_MODEL_TO_APP), help="Model name.")
70
+ p_load.add_argument("--portal", default="private", help="'private' or 'public'.")
71
+ p_load.add_argument("--id", help="UUID of a specific record.")
72
+ p_load.add_argument(
73
+ "--filters",
74
+ nargs="+",
75
+ metavar="FIELD=VALUE",
76
+ help="Filter expressions, e.g. name.icontains=rat",
77
+ )
78
+ p_load.add_argument(
79
+ "--sort",
80
+ nargs="+",
81
+ metavar="FIELD",
82
+ help="Sort fields. Prefix with '-' for descending.",
83
+ )
84
+ p_load.add_argument(
85
+ "--include",
86
+ nargs="+",
87
+ metavar="RELATION",
88
+ help="Related models to embed.",
89
+ )
90
+ p_load.add_argument("--limit", type=int, help="Max records (API max: 100).")
91
+ p_load.add_argument("--offset", type=int, help="Records to skip (pagination).")
92
+
93
+ # ---- save -------------------------------------------------------
94
+ p_save = sub.add_parser("save", parents=[common], help="Create or update a record.")
95
+ p_save.add_argument("model", choices=sorted(_MODEL_TO_APP), help="Model name.")
96
+ p_save.add_argument("--portal", default="private")
97
+ p_save.add_argument("--id", help="UUID of the record to update (omit to create).")
98
+ p_save.add_argument(
99
+ "--data",
100
+ required=True,
101
+ help="JSON string of fields to submit, e.g. '{\"name\":\"x\"}'.",
102
+ )
103
+
104
+ # ---- delete -----------------------------------------------------
105
+ p_delete = sub.add_parser("delete", parents=[common], help="Delete a record by ID.")
106
+ p_delete.add_argument("model", choices=sorted(_MODEL_TO_APP), help="Model name.")
107
+ p_delete.add_argument("--portal", default="private")
108
+ p_delete.add_argument("--id", required=True, help="UUID of the record to delete.")
109
+
110
+ return parser
111
+
112
+
113
+ def main():
114
+ parser = _build_parser()
115
+ args = parser.parse_args()
116
+
117
+ if args.command == "logout":
118
+ if _TOKEN_FILE.exists():
119
+ _TOKEN_FILE.unlink()
120
+ print(f"Logged out. Token removed from {_TOKEN_FILE}")
121
+ else:
122
+ print("No cached token found.")
123
+ return
124
+
125
+ client = BrainstemClient(
126
+ token=args.token,
127
+ headless=getattr(args, "headless", False),
128
+ url=getattr(args, "url", None),
129
+ )
130
+
131
+ if args.command == "login":
132
+ print(f"Token: {client._token}")
133
+ print(f"Cached at: {_TOKEN_FILE}")
134
+ return
135
+
136
+ if args.command == "load":
137
+ filters = {}
138
+ for expr in (args.filters or []):
139
+ if "=" not in expr:
140
+ parser.error(f"Invalid filter '{expr}': expected FIELD=VALUE")
141
+ k, v = expr.split("=", 1)
142
+ filters[k] = v
143
+
144
+ resp = client.load(
145
+ args.model,
146
+ portal=args.portal,
147
+ id=args.id,
148
+ filters=filters or None,
149
+ sort=args.sort,
150
+ include=args.include,
151
+ limit=args.limit,
152
+ offset=args.offset,
153
+ )
154
+
155
+ elif args.command == "save":
156
+ try:
157
+ data = json.loads(args.data)
158
+ except json.JSONDecodeError as exc:
159
+ parser.error(f"Invalid JSON for --data: {exc}")
160
+
161
+ resp = client.save(args.model, portal=args.portal, id=args.id, data=data)
162
+
163
+ elif args.command == "delete":
164
+ resp = client.delete(args.model, portal=args.portal, id=args.id)
165
+
166
+ # Output
167
+ if resp.status_code == 204:
168
+ print("Deleted successfully.")
169
+ else:
170
+ try:
171
+ print(json.dumps(resp.json(), indent=2))
172
+ except Exception:
173
+ print(resp.text)
174
+
175
+ if not resp.ok:
176
+ sys.exit(1)
177
+
178
+
179
+ if __name__ == "__main__":
180
+ main()
@@ -0,0 +1,179 @@
1
+ Metadata-Version: 2.4
2
+ Name: brainstem_python_api_tools
3
+ Version: 2.0.0
4
+ Summary: A Python toolset for interacting with the BrainSTEM API.
5
+ Author-email: BrainSTEM Team <petersen.peter@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/brainstem-org/brainstem_python_api_tools
8
+ Requires-Python: >=3.8
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: requests>=2.28
12
+ Provides-Extra: dev
13
+ Requires-Dist: pytest; extra == "dev"
14
+ Requires-Dist: pytest-mock; extra == "dev"
15
+ Dynamic: license-file
16
+
17
+ # BrainSTEM Python API Tools
18
+
19
+ The `brainstem_python_api_tools` is a Python toolset for interacting with the [BrainSTEM](https://www.brainstem.org/) API, designed for researchers and developers working with neuroscience data.
20
+
21
+ ## Installation
22
+ You can install the package using `pip`:
23
+ ```bash
24
+ pip install brainstem_python_api_tools
25
+ ```
26
+
27
+ ## Authentication
28
+
29
+ Authentication uses a **browser-based device authorization flow** that supports two-factor authentication (2FA). No credentials are entered into the tool itself.
30
+
31
+ ```python
32
+ from brainstem_api_tools import BrainstemClient
33
+
34
+ # First run: opens a browser window for secure login.
35
+ # The token is cached at ~/.config/brainstem/token and reused automatically.
36
+ client = BrainstemClient()
37
+ ```
38
+
39
+ To skip the browser flow, pass a token directly:
40
+ ```python
41
+ client = BrainstemClient(token="YOUR_TOKEN")
42
+ ```
43
+
44
+ For headless environments (no browser available):
45
+ ```python
46
+ client = BrainstemClient(headless=True) # prints a URL + code to enter manually
47
+ ```
48
+
49
+ To connect to a different server (e.g. a local development instance):
50
+ ```python
51
+ client = BrainstemClient(url="http://127.0.0.1:8000/")
52
+ ```
53
+
54
+ > **Security note:** The cached token file is stored with owner-read-only permissions (`0600`). Treat it like a password and do not commit it to version control.
55
+
56
+ ## Getting Started
57
+ To get started with the BrainSTEM API tools, please refer to the tutorial script provided:
58
+
59
+ - **Tutorial:** `brainstem_api_tutorial.py`
60
+
61
+ The tutorial demonstrates how to:
62
+
63
+ - **Authenticate:** Load the client and authenticate via your browser.
64
+ - **Load Data:** Load sessions and filter data using flexible options.
65
+ - **Paginate:** Retrieve large datasets using `limit` / `offset` or `load_all=True`.
66
+ - **Convenience Loaders:** Use `load_session()`, `load_subject()`, etc. for common queries.
67
+ - **Update Entries:** Modify existing records and update them in the database.
68
+ - **Create Entries:** Submit new data entries with required fields.
69
+ - **Delete Entries:** Remove records by ID.
70
+ - **Load Public Data:** Access public projects and data using the public portal.
71
+
72
+ ## Example Usage
73
+ ```python
74
+ from brainstem_api_tools import BrainstemClient
75
+
76
+ client = BrainstemClient()
77
+
78
+ # Load sessions sorted by name
79
+ response = client.load('session', sort=['name'])
80
+ print(response.json())
81
+
82
+ # Filter and include related data
83
+ response = client.load(
84
+ 'session',
85
+ filters={'name.icontains': 'Rat'},
86
+ sort=['-name'],
87
+ include=['projects'],
88
+ )
89
+
90
+ # Paginate results (manual)
91
+ page2 = client.load('session', limit=20, offset=20).json()
92
+
93
+ # Auto-paginate — fetches every page and returns a merged dict
94
+ all_sessions = client.load('session', load_all=True)
95
+
96
+ # Convenience loaders — sensible defaults with named filter kwargs
97
+ # load_session embeds dataacquisition, behaviors, manipulations, epochs
98
+ sessions = client.load_session(name='Rat', load_all=True)
99
+
100
+ # load_subject embeds procedures and subjectlogs
101
+ subjects = client.load_subject(sex='M', projects='<project-uuid>', load_all=True)
102
+
103
+ # load_project embeds sessions, subjects, collections, cohorts
104
+ projects = client.load_project(name='MyProject')
105
+
106
+ # load_behavior / load_dataacquisition / load_manipulation scope by session UUID
107
+ behaviors = client.load_behavior(session='<session-uuid>', load_all=True)
108
+
109
+ # load_procedure scopes by subject UUID
110
+ procedures = client.load_procedure(subject='<subject-uuid>', load_all=True)
111
+
112
+ # Create a record
113
+ client.save('session', data={'name': 'New session', 'projects': ['<project-uuid>']})
114
+
115
+ # Update a record
116
+ client.save('session', id='<session-uuid>', data={'description': 'updated'})
117
+
118
+ # Delete a record
119
+ client.delete('session', id='<session-uuid>')
120
+ ```
121
+
122
+ ## Command-line Interface
123
+
124
+ After installation a `brainstem` command is available in your shell.
125
+
126
+ ### Authentication
127
+ ```bash
128
+ # Authenticate (opens browser) and cache token
129
+ brainstem login
130
+
131
+ # Headless — prints URL + code instead of opening browser
132
+ brainstem login --headless
133
+
134
+ # Connect to a local dev server
135
+ brainstem login --url http://127.0.0.1:8000/
136
+
137
+ # Remove cached token
138
+ brainstem logout
139
+ ```
140
+
141
+ ### Loading data
142
+ ```bash
143
+ # Load all sessions (private portal)
144
+ brainstem load session
145
+
146
+ # Filter, sort and embed related data
147
+ brainstem load session --filters name.icontains=Rat --sort -name --include projects
148
+
149
+ # Load a single record by UUID
150
+ brainstem load session --id <uuid>
151
+
152
+ # Manual pagination
153
+ brainstem load session --limit 20 --offset 20
154
+
155
+ # Public portal
156
+ brainstem load project --portal public
157
+ ```
158
+
159
+ ### Creating and updating records
160
+ ```bash
161
+ # Create a new session
162
+ brainstem save session --data '{"name":"New session","projects":["<uuid>"]}'
163
+
164
+ # Update an existing record
165
+ brainstem save session --id <uuid> --data '{"description":"updated"}'
166
+ ```
167
+
168
+ ### Deleting records
169
+ ```bash
170
+ brainstem delete session --id <uuid>
171
+ ```
172
+
173
+ All subcommands accept `--token`, `--headless`, and `--url` to override defaults.
174
+
175
+ ## Contributing
176
+ Contributions are welcome! Feel free to open issues or submit pull requests on GitHub.
177
+
178
+ ## License
179
+ This project is licensed under the MIT License. See the `LICENSE` file for more details.
@@ -0,0 +1,9 @@
1
+ brainstem_api_tools/__init__.py,sha256=fjUyImRQc7gB_6D_a6q-55sMwMPo41famC4lzUqRrRc,117
2
+ brainstem_api_tools/brainstem_api_client.py,sha256=_lkS32E2kOdjF2e0SsENflATLD_S-1zLsX4G4OoQYU0,35267
3
+ brainstem_api_tools/cli.py,sha256=UB5QHFMcUK8Se79lqyEEUU2fIavuz757SHXzqeF_x1Y,5760
4
+ brainstem_python_api_tools-2.0.0.dist-info/licenses/LICENSE,sha256=I4iwel7RmYcQggAinCAw6Gxcup59frUNXxFKf9hXCoc,1092
5
+ brainstem_python_api_tools-2.0.0.dist-info/METADATA,sha256=MpWNZyTQq-q685jXNPj03C9GePOSdwAN4pesL9BrDcA,5575
6
+ brainstem_python_api_tools-2.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
7
+ brainstem_python_api_tools-2.0.0.dist-info/entry_points.txt,sha256=o78cX6aY5foCZ6xskNVWc_Stjxi3dfYn_8l_kszjfZ4,59
8
+ brainstem_python_api_tools-2.0.0.dist-info/top_level.txt,sha256=66OUGJs8UdzQdEqtx32kt84z2x-IpYEHmI1lLGlEwPA,20
9
+ brainstem_python_api_tools-2.0.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.7.0)
2
+ Generator: setuptools (82.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ brainstem = brainstem_api_tools.cli:main
@@ -1,54 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: brainstem_python_api_tools
3
- Version: 0.2.0
4
- Summary: A Python toolset for interacting with API of BrainSTEM.
5
- Home-page: https://github.com/brainstem-org/brainstem_python_api_tools
6
- Author: BrainSTEM Team
7
- Author-email: petersen.peter@gmail.com
8
- License: MIT
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: License :: OSI Approved :: MIT License
11
- Classifier: Operating System :: OS Independent
12
- Requires-Python: >=3.7
13
- Description-Content-Type: text/markdown
14
- License-File: LICENSE
15
- Requires-Dist: requests
16
- Requires-Dist: jupyter
17
-
18
- # BrainSTEM Python API Tools
19
-
20
- The `brainstem_python_api_tools` is a Python toolset for interacting with the [BrainSTEM](https://www.brainstem.org/) API, designed for researchers and developers working with neuroscience data.
21
-
22
- ## Installation
23
- You can install the package using `pip`:
24
- ```bash
25
- pip install brainstem_python_api_tools
26
- ```
27
-
28
- ## Getting Started
29
- To get started with the BrainSTEM API tools, please refer to the tutorial script provided:
30
-
31
- - **Tutorial:** `brainstem_api_tutorial.py`
32
-
33
- The tutorial demonstrates how to:
34
-
35
- - **Authenticate:** Load the client and authenticate using your credentials.
36
- - **Loading Data:** Load sessions and filter data using flexible options.
37
- - **Updating Entries:** Modify existing models and update them in the database.
38
- - **Creating Entries:** Submit new data entries with required fields.
39
- - **Loading Public Data:** Access public projects and data using the public portal.
40
-
41
- ## Example Usage
42
- ```python
43
- from brainstem_api_tools import BrainstemClient
44
-
45
- client = BrainstemClient()
46
- response = client.load_model('session', sort=['name'])
47
- print(response.json())
48
- ```
49
-
50
- ## Contributing
51
- Contributions are welcome! Feel free to open issues or submit pull requests on [GitHub](https://github.com/brainstem-org/brainstem_python_api_tools).
52
-
53
- ## License
54
- This project is licensed under the MIT License. See the `LICENSE` file for more details.
@@ -1,7 +0,0 @@
1
- brainstem_api_tools/__init__.py,sha256=mADe7kLRh26hHSsFeqH60SVsJgzDb6PpoSRsmx0bKyU,73
2
- brainstem_api_tools/brainstem_api_client.py,sha256=TCruvRkMG4RpioxA-IrZZAOAnj8IXvzYK0Z7qEr_8ns,7787
3
- brainstem_python_api_tools-0.2.0.dist-info/LICENSE,sha256=I4iwel7RmYcQggAinCAw6Gxcup59frUNXxFKf9hXCoc,1092
4
- brainstem_python_api_tools-0.2.0.dist-info/METADATA,sha256=NzJQpgIBJq3EG_V0gw9Fl4Q55ffY_gO9Uk3WLp9BYDE,1925
5
- brainstem_python_api_tools-0.2.0.dist-info/WHEEL,sha256=A3WOREP4zgxI0fKrHUG8DC8013e3dK3n7a6HDbcEIwE,91
6
- brainstem_python_api_tools-0.2.0.dist-info/top_level.txt,sha256=66OUGJs8UdzQdEqtx32kt84z2x-IpYEHmI1lLGlEwPA,20
7
- brainstem_python_api_tools-0.2.0.dist-info/RECORD,,