labdata 0.1.23__tar.gz → 0.1.25__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.
Files changed (87) hide show
  1. {labdata-0.1.23 → labdata-0.1.25}/PKG-INFO +1 -1
  2. {labdata-0.1.23 → labdata-0.1.25}/labdata/__init__.py +2 -1
  3. {labdata-0.1.23 → labdata-0.1.25}/labdata/accounts.py +57 -3
  4. {labdata-0.1.23 → labdata-0.1.25}/labdata/cli.py +619 -20
  5. {labdata-0.1.23 → labdata-0.1.25}/labdata/compute/__init__.py +2 -0
  6. {labdata-0.1.23 → labdata-0.1.25}/labdata/compute/ec2.py +4 -4
  7. {labdata-0.1.23 → labdata-0.1.25}/labdata/compute/ephys.py +276 -131
  8. {labdata-0.1.23 → labdata-0.1.25}/labdata/compute/pcluster.py +8 -0
  9. labdata-0.1.25/labdata/compute/schedulers.py +1029 -0
  10. labdata-0.1.25/labdata/compute/spikeinterface.py +937 -0
  11. {labdata-0.1.23 → labdata-0.1.25}/labdata/compute/utils.py +37 -19
  12. {labdata-0.1.23 → labdata-0.1.25}/labdata/copy.py +29 -0
  13. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/activity.py +1 -1
  14. labdata-0.1.25/labdata/dashboard/ephys/__init__.py +1 -0
  15. {labdata-0.1.23/labdata/dashboard → labdata-0.1.25/labdata/dashboard/ephys}/drift.py +12 -16
  16. {labdata-0.1.23/labdata/dashboard → labdata-0.1.25/labdata/dashboard/ephys}/sorting.py +125 -56
  17. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/index.py +2 -2
  18. labdata-0.1.25/labdata/export/__init__.py +15 -0
  19. labdata-0.1.25/labdata/export/database.py +198 -0
  20. labdata-0.1.25/labdata/export/docker/Dockerfile.in +37 -0
  21. labdata-0.1.25/labdata/export/docker/entrypoint.sh +75 -0
  22. labdata-0.1.25/labdata/export/docker/load_database.sh +25 -0
  23. labdata-0.1.25/labdata/export/docker/mysql.cnf +4 -0
  24. labdata-0.1.25/labdata/export/docker.py +319 -0
  25. labdata-0.1.25/labdata/export/selection.py +1034 -0
  26. labdata-0.1.25/labdata/export/share.py +197 -0
  27. labdata-0.1.25/labdata/export/users.py +160 -0
  28. {labdata-0.1.23 → labdata-0.1.25}/labdata/rules/ephys.py +270 -15
  29. {labdata-0.1.23 → labdata-0.1.25}/labdata/s3.py +89 -15
  30. {labdata-0.1.23 → labdata-0.1.25}/labdata/schema/ephys.py +255 -147
  31. {labdata-0.1.23 → labdata-0.1.25}/labdata/schema/general.py +4 -3
  32. {labdata-0.1.23 → labdata-0.1.25}/labdata/utils.py +69 -8
  33. {labdata-0.1.23 → labdata-0.1.25}/labdata/widgets.py +3 -1
  34. {labdata-0.1.23 → labdata-0.1.25}/labdata.egg-info/PKG-INFO +1 -1
  35. {labdata-0.1.23 → labdata-0.1.25}/labdata.egg-info/SOURCES.txt +16 -5
  36. {labdata-0.1.23 → labdata-0.1.25}/pyproject.toml +4 -1
  37. labdata-0.1.23/labdata/compute/schedulers.py +0 -545
  38. labdata-0.1.23/labdata/export.py +0 -381
  39. {labdata-0.1.23 → labdata-0.1.25}/LICENSE +0 -0
  40. {labdata-0.1.23 → labdata-0.1.25}/README.md +0 -0
  41. {labdata-0.1.23 → labdata-0.1.25}/labdata/compute/caiman.py +0 -0
  42. {labdata-0.1.23 → labdata-0.1.25}/labdata/compute/pose.py +0 -0
  43. {labdata-0.1.23 → labdata-0.1.25}/labdata/compute/singularity.py +0 -0
  44. {labdata-0.1.23 → labdata-0.1.25}/labdata/compute/submission.py +0 -0
  45. {labdata-0.1.23 → labdata-0.1.25}/labdata/compute/suite2p.py +0 -0
  46. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/__init__.py +0 -0
  47. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/admin.py +0 -0
  48. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/ai_utils.py +0 -0
  49. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/compute.py +0 -0
  50. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/console.py +0 -0
  51. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/decisiontask.py +0 -0
  52. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/docstrings.py +0 -0
  53. {labdata-0.1.23/labdata/dashboard → labdata-0.1.25/labdata/dashboard/ephys}/raster.py +0 -0
  54. /labdata-0.1.23/labdata/dashboard/ephys.py → /labdata-0.1.25/labdata/dashboard/ephys/recordings.py +0 -0
  55. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/events.py +0 -0
  56. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/imaging.py +0 -0
  57. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/launch.py +0 -0
  58. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/local_files.py +0 -0
  59. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/notes.py +0 -0
  60. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/procedures.py +0 -0
  61. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/reads.py +0 -0
  62. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/schema_graph.py +0 -0
  63. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/segmentation.py +0 -0
  64. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/sync.py +0 -0
  65. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/upload.py +0 -0
  66. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/upload_worker.py +0 -0
  67. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/video.py +0 -0
  68. {labdata-0.1.23 → labdata-0.1.25}/labdata/dashboard/writes.py +0 -0
  69. {labdata-0.1.23 → labdata-0.1.25}/labdata/ephys_io.py +0 -0
  70. {labdata-0.1.23 → labdata-0.1.25}/labdata/ephys_signal.py +0 -0
  71. {labdata-0.1.23 → labdata-0.1.25}/labdata/rules/__init__.py +0 -0
  72. {labdata-0.1.23 → labdata-0.1.25}/labdata/rules/imaging.py +0 -0
  73. {labdata-0.1.23 → labdata-0.1.25}/labdata/rules/utils.py +0 -0
  74. {labdata-0.1.23 → labdata-0.1.25}/labdata/schema/__init__.py +0 -0
  75. {labdata-0.1.23 → labdata-0.1.25}/labdata/schema/histology.py +0 -0
  76. {labdata-0.1.23 → labdata-0.1.25}/labdata/schema/onephoton.py +0 -0
  77. {labdata-0.1.23 → labdata-0.1.25}/labdata/schema/procedures.py +0 -0
  78. {labdata-0.1.23 → labdata-0.1.25}/labdata/schema/tasks.py +0 -0
  79. {labdata-0.1.23 → labdata-0.1.25}/labdata/schema/twophoton.py +0 -0
  80. {labdata-0.1.23 → labdata-0.1.25}/labdata/schema/utils.py +0 -0
  81. {labdata-0.1.23 → labdata-0.1.25}/labdata/schema/video.py +0 -0
  82. {labdata-0.1.23 → labdata-0.1.25}/labdata/stacks.py +0 -0
  83. {labdata-0.1.23 → labdata-0.1.25}/labdata.egg-info/dependency_links.txt +0 -0
  84. {labdata-0.1.23 → labdata-0.1.25}/labdata.egg-info/entry_points.txt +0 -0
  85. {labdata-0.1.23 → labdata-0.1.25}/labdata.egg-info/requires.txt +0 -0
  86. {labdata-0.1.23 → labdata-0.1.25}/labdata.egg-info/top_level.txt +0 -0
  87. {labdata-0.1.23 → labdata-0.1.25}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: labdata
3
- Version: 0.1.23
3
+ Version: 0.1.25
4
4
  Summary: Package to manage data in experimental neuroscience labs
5
5
  Author-email: Joao Couto <jpcouto@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/jcouto/labdata
@@ -1,4 +1,5 @@
1
- VERSION = "0.1.23"
1
+ VERSION = "0.1.25"
2
+ __version__ = VERSION
2
3
 
3
4
  from .utils import *
4
5
  from .copy import copy_to_upload_server
@@ -78,13 +78,22 @@ def database_grants(name, projects, database_name='lab_data', sandbox=False):
78
78
  return [g.replace('%', '%%') for g in grants]
79
79
 
80
80
 
81
+ def split_host(host, port=3306):
82
+ '''Return ``(address, port)`` of a database host written ``address`` or ``address:port``;
83
+ ``port`` is used when the host has none.'''
84
+ address, _, number = str(host).strip().rpartition(':')
85
+ if address and number.isdigit():
86
+ return address, int(number)
87
+ return str(host).strip(), int(port)
88
+
89
+
81
90
  def ask_database_admin(host, default_user=None):
82
91
  '''Ask for the database admin login and return a pymysql connection.
83
92
 
84
93
  Parameters
85
94
  ----------
86
95
  host : str
87
- Database address.
96
+ Database address, ``address`` or ``address:port``.
88
97
  default_user : str, optional
89
98
  User offered as default.
90
99
 
@@ -96,7 +105,8 @@ def ask_database_admin(host, default_user=None):
96
105
  print(f'Database admin login for {host} (used for this command only, not saved).')
97
106
  user = input(f' Admin user [{default_user or ""}]: ').strip() or default_user
98
107
  password = getpass(' Admin password: ')
99
- return pymysql.connect(host=host, user=user, password=password, autocommit=True)
108
+ address, port = split_host(host)
109
+ return pymysql.connect(host=address, port=port, user=user, password=password, autocommit=True)
100
110
 
101
111
 
102
112
  def database_user_exists(conn, name):
@@ -147,6 +157,49 @@ def database_user_grants(conn, name):
147
157
  return [r[0] for r in _rows(conn, f"SHOW GRANTS FOR '{name}'@'%%'", ())]
148
158
 
149
159
 
160
+ def _grant_pattern(schema):
161
+ '''Return the regular expression of a schema name of a GRANT, where ``_`` and ``%`` are
162
+ wildcards unless escaped with ``\\``.'''
163
+ out, i = '', 0
164
+ while i < len(schema):
165
+ c = schema[i]
166
+ if c == '\\' and i + 1 < len(schema):
167
+ out += re.escape(schema[i + 1])
168
+ i += 2
169
+ continue
170
+ out += '.*' if c == '%' else '.' if c == '_' else re.escape(c)
171
+ i += 1
172
+ return re.compile(out)
173
+
174
+
175
+ def database_access(conn, databases):
176
+ '''Return ``{user: [databases]}`` for the database users with privileges other than
177
+ REFERENCES on ``databases``; ``'*'`` stands for a grant on every database. Users whose
178
+ grants can not be read are left out.'''
179
+ access = dict()
180
+ for user in list_database_users(conn):
181
+ try:
182
+ grants = database_user_grants(conn, user)
183
+ except Exception:
184
+ continue
185
+ for grant in grants:
186
+ m = re.match(r'GRANT (.+?) ON (\S+?)\.\S+ TO ', grant)
187
+ if not m:
188
+ continue
189
+ privileges = set(p.strip().upper() for p in m.group(1).split(','))
190
+ if privileges <= {'USAGE', 'REFERENCES'}:
191
+ continue
192
+ schema = m.group(2).strip('`')
193
+ if schema == '*':
194
+ access.setdefault(user, set()).add('*')
195
+ continue
196
+ pattern = _grant_pattern(schema)
197
+ for database in databases:
198
+ if pattern.fullmatch(database):
199
+ access.setdefault(user, set()).add(database)
200
+ return {user: sorted(names) for user, names in sorted(access.items())}
201
+
202
+
150
203
  def create_s3_user(session, name, groups=(), policies=(), like=None):
151
204
  '''Create the IAM user ``name`` with one access key, and the permissions of ``groups``, ``policies`` or user ``like``.
152
205
 
@@ -836,7 +889,8 @@ def grant_database_project(conn, name, project, database_name='lab_data'):
836
889
  def connect_database_admin(host, user, password):
837
890
  '''Return a pymysql connection for ``user``, after checking it may create users and grant permissions.'''
838
891
  import pymysql
839
- conn = pymysql.connect(host=host, user=user, password=password, autocommit=True)
892
+ address, port = split_host(host)
893
+ conn = pymysql.connect(host=address, port=port, user=user, password=password, autocommit=True)
840
894
  grants = ' '.join(r[0] for r in _rows(conn, 'SHOW GRANTS', ())).upper()
841
895
  if 'CREATE USER' not in grants and 'ALL PRIVILEGES ON *.*' not in grants:
842
896
  conn.close()