1
1
import warnings
2
- import pymysql
3
2
import logging
4
3
import inspect
5
4
import re
8
7
from .connection import conn
9
8
from .diagram import Diagram , _get_tier
10
9
from .settings import config
11
- from .errors import DataJointError
10
+ from .errors import DataJointError , AccessError
12
11
from .jobs import JobTable
13
12
from .external import ExternalMapping
14
13
from .heading import Heading
@@ -45,9 +44,11 @@ class Schema:
45
44
def __init__ (self , schema_name = None , context = None , * , connection = None , create_schema = True ,
46
45
create_tables = True , add_objects = None ):
47
46
"""
48
- Associate database schema `schema_name`. If the schema does not exist, attempt to create it on the server.
47
+ Associate database schema `schema_name`. If the schema does not exist, attempt to
48
+ create it on the server.
49
49
50
- If the schema_name is omitted, then schema.activate(..) must be called later to associate with the database.
50
+ If the schema_name is omitted, then schema.activate(..) must be called later
51
+ to associate with the database.
51
52
52
53
:param schema_name: the database schema to associate.
53
54
:param context: dictionary for looking up foreign key references, leave None to use local context.
@@ -70,25 +71,32 @@ def __init__(self, schema_name=None, context=None, *, connection=None, create_sc
70
71
if schema_name :
71
72
self .activate (schema_name )
72
73
73
- def activate (self , schema_name , * , connection = None , create_schema = True ,
74
+ def is_activated (self ):
75
+ return self .database is not None
76
+
77
+ def activate (self , schema_name = None , * , connection = None , create_schema = None ,
74
78
create_tables = None , add_objects = None ):
75
79
"""
76
- Associate database schema `schema_name`. If the schema does not exist, attempt to create it on the server.
80
+ Associate database schema `schema_name`. If the schema does not exist, attempt to
81
+ create it on the server.
77
82
:param schema_name: the database schema to associate.
83
+ schema_name=None is used to assert that the schema has already been activated.
78
84
:param connection: Connection object. Defaults to datajoint.conn().
79
- :param create_schema: When False, do not create the schema and raise an error if missing.
80
- :param create_tables: When False, do not create tables and raise errors when accessing missing tables.
81
- :param add_objects: a mapping with additional objects to make available to the context in which table classes
82
- are declared.
85
+ :param create_schema: If False, do not create the schema and raise an error if missing.
86
+ :param create_tables: If False, do not create tables and raise errors when attempting
87
+ to access missing tables.
88
+ :param add_objects: a mapping with additional objects to make available to the context
89
+ in which table classes are declared.
83
90
"""
84
91
if schema_name is None :
85
- if self .is_activated :
92
+ if self .exists :
86
93
return
87
94
raise DataJointError ("Please provide a schema_name to activate the schema." )
88
- if self .is_activated :
95
+ if self .database is not None and self . exists :
89
96
if self .database == schema_name : # already activated
90
97
return
91
- raise DataJointError ("The schema is already activated for schema {db}." .format (db = self .database ))
98
+ raise DataJointError (
99
+ "The schema is already activated for schema {db}." .format (db = self .database ))
92
100
if connection is not None :
93
101
self .connection = connection
94
102
if self .connection is None :
@@ -101,37 +109,32 @@ def activate(self, schema_name, *, connection=None, create_schema=True,
101
109
if add_objects :
102
110
self .add_objects = add_objects
103
111
if not self .exists :
104
- if not create_schema or not self .database :
112
+ if not self . create_schema or not self .database :
105
113
raise DataJointError (
106
- "Database named `{name}` was not defined . "
114
+ "Database `{name}` has not yet been declared . "
107
115
"Set argument create_schema=True to create it." .format (name = schema_name ))
116
+ # create database
117
+ logger .info ("Creating schema `{name}`." .format (name = schema_name ))
118
+ try :
119
+ self .connection .query ("CREATE DATABASE `{name}`" .format (name = schema_name ))
120
+ except AccessError :
121
+ raise DataJointError (
122
+ "Schema `{name}` does not exist and could not be created. "
123
+ "Check permissions." .format (name = schema_name ))
108
124
else :
109
- # create database
110
- logger .info ("Creating schema `{name}`." .format (name = schema_name ))
111
- try :
112
- self .connection .query ("CREATE DATABASE `{name}`" .format (name = schema_name ))
113
- except pymysql .OperationalError :
114
- raise DataJointError (
115
- "Schema `{name}` does not exist and could not be created. "
116
- "Check permissions." .format (name = schema_name ))
117
- else :
118
- self .log ('created' )
119
- self .log ('connect' )
125
+ self .log ('created' )
120
126
self .connection .register (self )
121
127
122
- # decorate all tables
128
+ # decorate all tables already decorated
123
129
for cls , context in self .declare_list :
124
130
if self .add_objects :
125
131
context = dict (context , ** self .add_objects )
126
132
self ._decorate_master (cls , context )
127
133
128
- @property
129
- def is_activated (self ):
130
- return self .database is not None
131
-
132
- def _assert_activation (self , message = "The schema must be activated first." ):
133
- if not self .is_activated :
134
- raise DataJointError (message )
134
+ def _assert_exists (self , message = None ):
135
+ if not self .exists :
136
+ raise DataJointError (
137
+ message or "Schema `{db}` has not been created." .format (db = self .database ))
135
138
136
139
def __call__ (self , cls , * , context = None ):
137
140
"""
@@ -142,7 +145,7 @@ def __call__(self, cls, *, context=None):
142
145
context = context or self .context or inspect .currentframe ().f_back .f_locals
143
146
if issubclass (cls , Part ):
144
147
raise DataJointError ('The schema decorator should not be applied to Part relations' )
145
- if self .is_activated :
148
+ if self .is_activated () :
146
149
self ._decorate_master (cls , context )
147
150
else :
148
151
self .declare_list .append ((cls , context ))
@@ -204,7 +207,7 @@ def _decorate_table(self, table_class, context, assert_declared=False):
204
207
205
208
@property
206
209
def log (self ):
207
- self ._assert_activation ()
210
+ self ._assert_exists ()
208
211
if self ._log is None :
209
212
self ._log = Log (self .connection , self .database )
210
213
return self ._log
@@ -217,7 +220,7 @@ def size_on_disk(self):
217
220
"""
218
221
:return: size of the entire schema in bytes
219
222
"""
220
- self ._assert_activation ()
223
+ self ._assert_exists ()
221
224
return int (self .connection .query (
222
225
"""
223
226
SELECT SUM(data_length + index_length)
@@ -230,7 +233,7 @@ def spawn_missing_classes(self, context=None):
230
233
in the context.
231
234
:param context: alternative context to place the missing classes into, e.g. locals()
232
235
"""
233
- self ._assert_activation ()
236
+ self ._assert_exists ()
234
237
if context is None :
235
238
if self .context is not None :
236
239
context = self .context
@@ -273,43 +276,49 @@ def drop(self, force=False):
273
276
"""
274
277
Drop the associated schema if it exists
275
278
"""
276
- self ._assert_activation ()
277
279
if not self .exists :
278
- logger .info ("Schema named `{database}` does not exist. Doing nothing." .format (database = self .database ))
280
+ logger .info ("Schema named `{database}` does not exist. Doing nothing." .format (
281
+ database = self .database ))
279
282
elif (not config ['safemode' ] or
280
283
force or
281
284
user_choice ("Proceed to delete entire schema `%s`?" % self .database , default = 'no' ) == 'yes' ):
282
285
logger .info ("Dropping `{database}`." .format (database = self .database ))
283
286
try :
284
287
self .connection .query ("DROP DATABASE `{database}`" .format (database = self .database ))
285
288
logger .info ("Schema `{database}` was dropped successfully." .format (database = self .database ))
286
- except pymysql .OperationalError :
287
- raise DataJointError ("An attempt to drop schema `{database}` "
288
- "has failed. Check permissions." .format (database = self .database ))
289
+ except AccessError :
290
+ raise AccessError (
291
+ "An attempt to drop schema `{database}` "
292
+ "has failed. Check permissions." .format (database = self .database ))
289
293
290
294
@property
291
295
def exists (self ):
292
296
"""
293
297
:return: true if the associated schema exists on the server
294
298
"""
295
- self ._assert_activation ()
296
- cur = self .connection .query ("SHOW DATABASES LIKE '{database}'" .format (database = self .database ))
297
- return cur .rowcount > 0
299
+ if self .database is None :
300
+ raise DataJointError ("Schema must be activated first." )
301
+ return self .database is not None and (
302
+ self .connection .query (
303
+ "SELECT schema_name "
304
+ "FROM information_schema.schemata "
305
+ "WHERE schema_name = '{database}'" .format (
306
+ database = self .database )).rowcount > 0 )
298
307
299
308
@property
300
309
def jobs (self ):
301
310
"""
302
311
schema.jobs provides a view of the job reservation table for the schema
303
312
:return: jobs table
304
313
"""
305
- self ._assert_activation ()
314
+ self ._assert_exists ()
306
315
if self ._jobs is None :
307
316
self ._jobs = JobTable (self .connection , self .database )
308
317
return self ._jobs
309
318
310
319
@property
311
320
def code (self ):
312
- self ._assert_activation ()
321
+ self ._assert_exists ()
313
322
return self .save ()
314
323
315
324
def save (self , python_filename = None ):
@@ -318,7 +327,7 @@ def save(self, python_filename=None):
318
327
This method is in preparation for a future release and is not officially supported.
319
328
:return: a string containing the body of a complete Python module defining this schema.
320
329
"""
321
- self ._assert_activation ()
330
+ self ._assert_exists ()
322
331
module_count = itertools .count ()
323
332
# add virtual modules for referenced modules with names vmod0, vmod1, ...
324
333
module_lookup = collections .defaultdict (lambda : 'vmod' + str (next (module_count )))
@@ -358,20 +367,18 @@ def replace(s):
358
367
for k , v in module_lookup .items ()), body ))
359
368
if python_filename is None :
360
369
return python_code
361
- else :
362
- with open (python_filename , 'wt' ) as f :
363
- f .write (python_code )
370
+ with open (python_filename , 'wt' ) as f :
371
+ f .write (python_code )
364
372
365
373
def list_tables (self ):
366
374
"""
367
375
Return a list of all tables in the schema except tables with ~ in first character such
368
376
as ~logs and ~job
369
- :return: A list of table names in their raw datajoint naming convection form
377
+ :return: A list of table names from the database schema.
370
378
"""
371
-
372
379
return [table_name for (table_name ,) in self .connection .query ("""
373
380
SELECT table_name FROM information_schema.tables
374
- WHERE table_schema = %s and table_name NOT LIKE '~%%'""" , args = (self .database ))]
381
+ WHERE table_schema = %s and table_name NOT LIKE '~%%'""" , args = (self .database , ))]
375
382
376
383
377
384
class VirtualModule (types .ModuleType ):
@@ -393,8 +400,8 @@ def __init__(self, module_name, schema_name, *, create_schema=False,
393
400
:return: the python module containing classes from the schema object and the table classes
394
401
"""
395
402
super (VirtualModule , self ).__init__ (name = module_name )
396
- _schema = Schema (schema_name , create_schema = create_schema , create_tables = create_tables ,
397
- connection = connection )
403
+ _schema = Schema (schema_name , create_schema = create_schema ,
404
+ create_tables = create_tables , connection = connection )
398
405
if add_objects :
399
406
self .__dict__ .update (add_objects )
400
407
self .__dict__ ['schema' ] = _schema
@@ -406,4 +413,7 @@ def list_schemas(connection=None):
406
413
:param connection: a dj.Connection object
407
414
:return: list of all accessible schemas on the server
408
415
"""
409
- return [r [0 ] for r in (connection or conn ()).query ('SHOW SCHEMAS' ) if r [0 ] not in {'information_schema' }]
416
+ return [r [0 ] for r in (connection or conn ()).query (
417
+ 'SELECT schema_name '
418
+ 'FROM information_schema.schemata '
419
+ 'WHERE schema_name <> "information_schema"' )]
0 commit comments