163 flag telling if logging should be initialized. You usually don't want |
166 flag telling if logging should be initialized. You usually don't want |
164 logging initialization when establishing the connection from a process |
167 logging initialization when establishing the connection from a process |
165 where it's already initialized. |
168 where it's already initialized. |
166 |
169 |
167 :kwargs: |
170 :kwargs: |
168 there goes authentication tokens. You usually have to specify for |
171 there goes authentication tokens. You usually have to specify a password |
169 instance a password for the given user, using a named 'password' argument. |
172 for the given user, using a named 'password' argument. |
170 """ |
173 """ |
171 config = cwconfig.CubicWebNoAppConfiguration() |
|
172 if host: |
|
173 config.global_set_option('pyro-ns-host', host) |
|
174 if group: |
|
175 config.global_set_option('pyro-ns-group', group) |
|
176 cnxprops = cnxprops or ConnectionProperties() |
174 cnxprops = cnxprops or ConnectionProperties() |
177 method = cnxprops.cnxtype |
175 method = cnxprops.cnxtype |
|
176 if method == 'pyro': |
|
177 config = cwconfig.CubicWebNoAppConfiguration() |
|
178 if host: |
|
179 config.global_set_option('pyro-ns-host', host) |
|
180 if group: |
|
181 config.global_set_option('pyro-ns-group', group) |
|
182 else: |
|
183 assert database |
|
184 config = cwconfig.instance_configuration(database) |
178 repo = get_repository(method, database, config=config) |
185 repo = get_repository(method, database, config=config) |
179 if method == 'inmemory': |
186 if method == 'inmemory': |
180 vreg = repo.vreg |
187 vreg = repo.vreg |
181 elif setvreg: |
188 elif setvreg: |
182 if mulcnx: |
189 if mulcnx: |
192 vreg = None |
199 vreg = None |
193 cnx = repo_connect(repo, login, cnxprops=cnxprops, **kwargs) |
200 cnx = repo_connect(repo, login, cnxprops=cnxprops, **kwargs) |
194 cnx.vreg = vreg |
201 cnx.vreg = vreg |
195 return cnx |
202 return cnx |
196 |
203 |
197 def in_memory_cnx(config, login, **kwargs): |
204 def in_memory_repo(config): |
198 """usefull method for testing and scripting to get a dbapi.Connection |
205 """Return and in_memory Repository object from a config (or vreg)""" |
199 object connected to an in-memory repository instance |
|
200 """ |
|
201 if isinstance(config, cwvreg.CubicWebVRegistry): |
206 if isinstance(config, cwvreg.CubicWebVRegistry): |
202 vreg = config |
207 vreg = config |
203 config = None |
208 config = None |
204 else: |
209 else: |
205 vreg = None |
210 vreg = None |
206 # get local access to the repository |
211 # get local access to the repository |
207 repo = get_repository('inmemory', config=config, vreg=vreg) |
212 return get_repository('inmemory', config=config, vreg=vreg) |
|
213 |
|
214 def in_memory_cnx(repo, login, **kwargs): |
|
215 """Establish a In memory connection to a <repo> for the user with <login> |
|
216 |
|
217 additionel credential might be required""" |
|
218 cnxprops = ConnectionProperties('inmemory') |
|
219 return repo_connect(repo, login, cnxprops=cnxprops, **kwargs) |
|
220 |
|
221 def in_memory_repo_cnx(config, login, **kwargs): |
|
222 """usefull method for testing and scripting to get a dbapi.Connection |
|
223 object connected to an in-memory repository instance |
|
224 """ |
208 # connection to the CubicWeb repository |
225 # connection to the CubicWeb repository |
209 cnxprops = ConnectionProperties('inmemory') |
226 repo = in_memory_repo(config) |
210 cnx = repo_connect(repo, login, cnxprops=cnxprops, **kwargs) |
227 return repo, in_memory_cnx(repo, login, **kwargs) |
211 return repo, cnx |
|
212 |
228 |
213 class _NeedAuthAccessMock(object): |
229 class _NeedAuthAccessMock(object): |
214 def __getattribute__(self, attr): |
230 def __getattribute__(self, attr): |
215 raise AuthenticationError() |
231 raise AuthenticationError() |
216 def __nonzero__(self): |
232 def __nonzero__(self): |
311 else: |
327 else: |
312 del self._eid_cache[eid] |
328 del self._eid_cache[eid] |
313 |
329 |
314 # low level session data management ####################################### |
330 # low level session data management ####################################### |
315 |
331 |
316 def get_shared_data(self, key, default=None, pop=False): |
332 def get_shared_data(self, key, default=None, pop=False, txdata=False): |
317 """return value associated to `key` in shared data""" |
333 """see :meth:`Connection.get_shared_data`""" |
318 return self.cnx.get_shared_data(key, default, pop) |
334 return self.cnx.get_shared_data(key, default, pop, txdata) |
319 |
335 |
320 def set_shared_data(self, key, value, querydata=False): |
336 def set_shared_data(self, key, value, txdata=False, querydata=None): |
321 """set value associated to `key` in shared data |
337 """see :meth:`Connection.set_shared_data`""" |
322 |
338 if querydata is not None: |
323 if `querydata` is true, the value will be added to the repository |
339 txdata = querydata |
324 session's query data which are cleared on commit/rollback of the current |
340 warn('[3.10] querydata argument has been renamed to txdata', |
325 transaction, and won't be available through the connexion, only on the |
341 DeprecationWarning, stacklevel=2) |
326 repository side. |
342 return self.cnx.set_shared_data(key, value, txdata) |
327 """ |
|
328 return self.cnx.set_shared_data(key, value, querydata) |
|
329 |
343 |
330 # server session compat layer ############################################# |
344 # server session compat layer ############################################# |
331 |
345 |
332 def describe(self, eid): |
346 def describe(self, eid): |
333 """return a tuple (type, sourceuri, extid) for the entity with id <eid>""" |
347 """return a tuple (type, sourceuri, extid) for the entity with id <eid>""" |
480 def __init__(self, repo, cnxid, cnxprops=None): |
494 def __init__(self, repo, cnxid, cnxprops=None): |
481 self._repo = repo |
495 self._repo = repo |
482 self.sessionid = cnxid |
496 self.sessionid = cnxid |
483 self._close_on_del = getattr(cnxprops, 'close_on_del', True) |
497 self._close_on_del = getattr(cnxprops, 'close_on_del', True) |
484 self._cnxtype = getattr(cnxprops, 'cnxtype', 'pyro') |
498 self._cnxtype = getattr(cnxprops, 'cnxtype', 'pyro') |
|
499 self._web_request = False |
485 if cnxprops and cnxprops.log_queries: |
500 if cnxprops and cnxprops.log_queries: |
486 self.executed_queries = [] |
501 self.executed_queries = [] |
487 self.cursor_class = LogCursor |
502 self.cursor_class = LogCursor |
488 if self._cnxtype == 'pyro': |
503 if self._cnxtype == 'pyro': |
489 # check client/server compat |
504 # check client/server compat |
532 esubpath = subpath |
547 esubpath = subpath |
533 if 'views' in subpath: |
548 if 'views' in subpath: |
534 esubpath = list(subpath) |
549 esubpath = list(subpath) |
535 esubpath.remove('views') |
550 esubpath.remove('views') |
536 esubpath.append(join('web', 'views')) |
551 esubpath.append(join('web', 'views')) |
537 cubespath = [config.cube_dir(p) for p in cubes] |
552 config.init_cubes(cubes) |
538 config.load_site_cubicweb(cubespath) |
553 vpath = config.build_vregistry_path(reversed(config.cubes_path()), |
539 vpath = config.build_vregistry_path(reversed(cubespath), |
|
540 evobjpath=esubpath, |
554 evobjpath=esubpath, |
541 tvobjpath=subpath) |
555 tvobjpath=subpath) |
542 self.vreg.register_objects(vpath) |
556 self.vreg.register_objects(vpath) |
543 |
557 |
544 def use_web_compatible_requests(self, baseurl, sitetitle=None): |
558 def use_web_compatible_requests(self, baseurl, sitetitle=None): |
545 """monkey patch DBAPIRequest to fake a cw.web.request, so you should |
559 """monkey patch DBAPIRequest to fake a cw.web.request, so you should |
546 able to call html views using rset from a simple dbapi connection. |
560 able to call html views using rset from a simple dbapi connection. |
547 |
561 |
548 You should call `load_appobjects` at some point to register those views. |
562 You should call `load_appobjects` at some point to register those views. |
549 """ |
563 """ |
550 from cubicweb.web.request import CubicWebRequestBase as cwrb |
|
551 DBAPIRequest.build_ajax_replace_url = cwrb.build_ajax_replace_url.im_func |
|
552 DBAPIRequest.ajax_replace_url = cwrb.ajax_replace_url.im_func |
|
553 DBAPIRequest.list_form_param = cwrb.list_form_param.im_func |
|
554 DBAPIRequest.property_value = _fake_property_value |
564 DBAPIRequest.property_value = _fake_property_value |
555 DBAPIRequest.next_tabindex = count().next |
565 DBAPIRequest.next_tabindex = count().next |
556 DBAPIRequest.form = {} |
|
557 DBAPIRequest.data = {} |
|
558 fake = lambda *args, **kwargs: None |
|
559 DBAPIRequest.relative_path = fake |
566 DBAPIRequest.relative_path = fake |
560 DBAPIRequest.url = fake |
567 DBAPIRequest.url = fake |
561 DBAPIRequest.next_tabindex = fake |
|
562 DBAPIRequest.get_page_data = fake |
568 DBAPIRequest.get_page_data = fake |
563 DBAPIRequest.set_page_data = fake |
569 DBAPIRequest.set_page_data = fake |
564 DBAPIRequest.add_js = fake #cwrb.add_js.im_func |
|
565 DBAPIRequest.add_css = fake #cwrb.add_css.im_func |
|
566 # XXX could ask the repo for it's base-url configuration |
570 # XXX could ask the repo for it's base-url configuration |
567 self.vreg.config.set_option('base-url', baseurl) |
571 self.vreg.config.set_option('base-url', baseurl) |
|
572 self.vreg.config.uiprops = {} |
|
573 self.vreg.config.datadir_url = baseurl + '/data' |
568 # XXX why is this needed? if really needed, could be fetched by a query |
574 # XXX why is this needed? if really needed, could be fetched by a query |
569 if sitetitle is not None: |
575 if sitetitle is not None: |
570 self.vreg['propertydefs']['ui.site-title'] = {'default': sitetitle} |
576 self.vreg['propertydefs']['ui.site-title'] = {'default': sitetitle} |
571 |
577 self._web_request = True |
572 @check_not_closed |
578 |
573 def source_defs(self): |
579 def request(self): |
574 """Return the definition of sources used by the repository. |
580 if self._web_request: |
575 |
581 from cubicweb.web.request import CubicWebRequestBase |
576 This is NOT part of the DB-API. |
582 req = CubicWebRequestBase(self.vreg, False) |
577 """ |
583 req.get_header = lambda x, default=None: default |
578 return self._repo.source_defs() |
584 req.set_session = lambda session, user=None: DBAPIRequest.set_session( |
|
585 req, session, user) |
|
586 req.relative_path = lambda includeparams=True: '' |
|
587 else: |
|
588 req = DBAPIRequest(self.vreg) |
|
589 req.set_session(DBAPISession(self)) |
|
590 return req |
579 |
591 |
580 @check_not_closed |
592 @check_not_closed |
581 def user(self, req=None, props=None): |
593 def user(self, req=None, props=None): |
582 """return the User object associated to this connection""" |
594 """return the User object associated to this connection""" |
583 # cnx validity is checked by the call to .user_info |
595 # cnx validity is checked by the call to .user_info |
591 groups=groups, |
603 groups=groups, |
592 properties=properties) |
604 properties=properties) |
593 else: |
605 else: |
594 from cubicweb.entity import Entity |
606 from cubicweb.entity import Entity |
595 user = Entity(req, rset, row=0) |
607 user = Entity(req, rset, row=0) |
596 user['login'] = login # cache login |
608 user.cw_attr_cache['login'] = login # cache login |
597 return user |
609 return user |
598 |
610 |
599 @check_not_closed |
611 @check_not_closed |
600 def check(self): |
612 def check(self): |
601 """raise `BadConnectionId` if the connection is no more valid""" |
613 """raise `BadConnectionId` if the connection is no more valid, else |
602 self._repo.check_session(self.sessionid) |
614 return its latest activity timestamp. |
|
615 """ |
|
616 return self._repo.check_session(self.sessionid) |
603 |
617 |
604 def _txid(self, cursor=None): # XXX could now handle various isolation level! |
618 def _txid(self, cursor=None): # XXX could now handle various isolation level! |
605 # return a dict as bw compat trick |
619 # return a dict as bw compat trick |
606 return {'txid': currentThread().getName()} |
620 return {'txid': currentThread().getName()} |
607 |
621 |
608 def request(self): |
|
609 return DBAPIRequest(self.vreg, DBAPISession(self)) |
|
610 |
|
611 # session data methods ##################################################### |
622 # session data methods ##################################################### |
612 |
623 |
613 @check_not_closed |
624 @check_not_closed |
614 def set_session_props(self, **props): |
625 def set_session_props(self, **props): |
615 """raise `BadConnectionId` if the connection is no more valid""" |
626 """raise `BadConnectionId` if the connection is no more valid""" |
616 self._repo.set_session_props(self.sessionid, props) |
627 self._repo.set_session_props(self.sessionid, props) |
617 |
628 |
618 @check_not_closed |
629 @check_not_closed |
619 def get_shared_data(self, key, default=None, pop=False): |
630 def get_shared_data(self, key, default=None, pop=False, txdata=False): |
620 """return value associated to `key` in shared data""" |
631 """return value associated to key in the session's data dictionary or |
621 return self._repo.get_shared_data(self.sessionid, key, default, pop) |
632 session's transaction's data if `txdata` is true. |
622 |
633 |
623 @check_not_closed |
634 If pop is True, value will be removed from the dictionnary. |
624 def set_shared_data(self, key, value, querydata=False): |
635 |
|
636 If key isn't defined in the dictionnary, value specified by the |
|
637 `default` argument will be returned. |
|
638 """ |
|
639 return self._repo.get_shared_data(self.sessionid, key, default, pop, txdata) |
|
640 |
|
641 @check_not_closed |
|
642 def set_shared_data(self, key, value, txdata=False): |
625 """set value associated to `key` in shared data |
643 """set value associated to `key` in shared data |
626 |
644 |
627 if `querydata` is true, the value will be added to the repository |
645 if `txdata` is true, the value will be added to the repository |
628 session's query data which are cleared on commit/rollback of the current |
646 session's query data which are cleared on commit/rollback of the current |
629 transaction, and won't be available through the connexion, only on the |
647 transaction. |
630 repository side. |
648 """ |
631 """ |
649 return self._repo.set_shared_data(self.sessionid, key, value, txdata) |
632 return self._repo.set_shared_data(self.sessionid, key, value, querydata) |
|
633 |
650 |
634 # meta-data accessors ###################################################### |
651 # meta-data accessors ###################################################### |
|
652 |
|
653 @check_not_closed |
|
654 def source_defs(self): |
|
655 """Return the definition of sources used by the repository.""" |
|
656 return self._repo.source_defs() |
635 |
657 |
636 @check_not_closed |
658 @check_not_closed |
637 def get_schema(self): |
659 def get_schema(self): |
638 """Return the schema currently used by the repository.""" |
660 """Return the schema currently used by the repository.""" |
639 return self._repo.get_schema() |
661 return self._repo.get_schema() |