def read_x2go_info_file(rename=False, use_defaults=True): pytis_x2go_file = pytis_x2go_info_file() if os.path.exists(pytis_x2go_file): for i in range(3): try: access_data = parse_x2go_info_file(pytis_x2go_file) except X2GoInfoSoftException as e: log(OPERATIONAL, *e.args) time.sleep(1) continue except X2GoInfoHardException as e: log(OPERATIONAL, *e.args) return None if rename: try: os.rename(pytis_x2go_file, pytis_x2go_info_file(x2go_session_id(fake=True))) except Exception as e: return else: os.remove(pytis_x2go_file) break elif use_defaults: access_data = dict(port=config.rpc_local_port, password=None) else: access_data = None return access_data
def _pytis_help_nodes(self): def clone(node, id): return self.ContentNode( id=id, title=node.title(), descr=node.descr(), content=node.content(), hidden=node.hidden(), children=[clone(n, 'help:pytis/' + n.id()) for n in node.children()], resource_provider=self._resource_provider, foldable=True, ) directory = os.path.join(pytis.config.help_dir, 'src') reader = lcg.reader(directory, 'pytis', ext='txt', resource_provider=self._resource_provider) try: node = reader.build() except IOError as e: log(OPERATIONAL, "Unable to read Pytis help files from '%s':" % directory, e) node = self.ContentNode('help:pytis', title=_("Pytis User Guide"), content=lcg.p(_("Help files not found!")), hidden=True, resource_provider=self._resource_provider) else: node = clone(node, 'help:pytis') return node
def __init__(self, message, exception=None, *args): """Inicializuj výjimku a zaloguj informace o ní. Argumenty: message -- lidsky čitelné oznámení o chybě, string; může být též 'None', v kterémžto případě se doplní standardní zpráva o databázové chybě, to je však vhodné používat pouze v případě, kdy nemá smysl uživateli sdělovat bližší popis chyby exception -- výjimka, která tuto výjimku způsobila, instance třídy 'Exception'; nebo 'None' (neznamená nutně, že chyba nebyla způsobena výjimkou, tato výjimka pouze nemusí být podstatná) args -- libovolné další argumenty, které mají být spolu s 'message' a 'exception' předány konstruktoru nadtřídy """ if message is None: message = _(u"Database error") super_(DBException).__init__(self, message, exception, *args) log(OPERATIONAL, 'Database exception', (message, ) + args) if exception: log(OPERATIONAL, 'Wrapped database exception', (exception, ) + exception.args) self._message = message self._exception = exception
def _get_default_select(spec): import pytis.form def init_select(view, data): sorting = view.sorting() if sorting is None: sorting = tuple([(k.id(), pd.DESCENDANT) for k in data.key() if view.field(k.id()) is not None]) success, select_count = pytis.form.db_operation(data.select, sort=sorting, reuse=False) if not success: log(EVENT, 'Selhání databázové operace') return None return select_count resolver = pytis.config.resolver try: view = resolver.get(spec, 'view_spec') except Exception: log(OPERATIONAL, "Nepodařilo se vytvořit view_spec") return None try: data = pytis.util.data_object(spec) except Exception: log(OPERATIONAL, "Nepodařilo se vytvořit datový objekt") return None data = pytis.util.data_object(spec) select_count = init_select(view, data) if select_count: print("Default select pro specifikaci %s vrací %s řádků" % ( spec, select_count, )) data.fetchone()
def _retrieve_row(self, row): def fetch(row): attempt = 1 while True: try: return self._data.fetch(row) except pytis.data.DBRetryException: if attempt <= 10: attempt += 1 continue else: raise current = self._current_row if not current or current.row != row: success, data_row = db_operation(fetch, row) if not success: self._panic() if data_row: self._presented_row.set_row(data_row) current = self._current_row = self._CurrentRow( row, copy.copy(self._presented_row)) else: if 0 <= row < self.number_of_rows(min_value=(row + 1)): log(DEBUG, "Missing grid row:", row) return None return current.the_row
def _pytis_help(self, resource_dirs): image_dir = os.path.join(config.help_dir, 'img') resource_provider = lcg.ResourceProvider(dirs=[image_dir] + resource_dirs) def clone(node, node_id): # Clone the content node, but force `id' to help URI and `foldable' to True. return lcg.ContentNode(node_id, title=node.title(), descr=node.descr(), content=node.content(), hidden=node.hidden(), children=[clone(n, 'help:pytis/'+n.id()) for n in node.children()], resource_provider=resource_provider, foldable=True) try: node = self._pytis_help_root_node except AttributeError: directory = os.path.join(config.help_dir, 'src') reader = lcg.reader(directory, 'pytis', ext='txt', resource_provider=resource_provider) try: node = self._pytis_help_root_node = reader.build() except IOError as e: log(OPERATIONAL, "Unable to read Pytis help files from '%s':" % directory, e) node = lcg.ContentNode('pytis:', title=_("Pytis User Guide"), content=lcg.p(_("Help files not found!")), hidden=True, resource_provider=resource_provider) # We need to clone on every request because set_parent() is called on # the result when added to the help tree and set_parent may not be # called multiple times. return clone(node, 'help:pytis')
def top_level_exception(einfo=None): """Zpracuj aktuálně vyvolanou výjimku aplikace.""" global _in_top_level_exception if not _in_top_level_exception: _in_top_level_exception = True try: if not einfo: einfo = sys.exc_info() if issubclass(einfo[0], SystemExit): sys.exit() tbstring = format_traceback() import cgitb try: tbstring = cgitb.text(einfo) except Exception: import traceback tbstring = "\n".join(traceback.format_exception(*einfo)) log(OPERATIONAL, 'Top-level exception caught', tbstring) if pytis.form.run_dialog(pytis.form.BugReport, einfo): sys.exit() if pytis.config.debug_on_error: import pdb pdb.post_mortem(sys.exc_info()[2]) finally: _in_top_level_exception = False
def __init__(self, connection_creator, connection_closer): if __debug__: log(DEBUG, 'Creating a new pool') self._lock = thread.allocate_lock() self._pool = {} self._connection_creator = connection_creator self._connection_closer = connection_closer self._allocated_connections = {}
def __init__(self, connection_creator, connection_closer): if __debug__: log(DEBUG, 'Creating a new pool') self._lock = _thread.allocate_lock() self._pool = {} self._connection_creator = connection_creator self._connection_closer = connection_closer self._allocated_connections = {}
def client_available(): """Return true, iff remote client is available.""" if not config.rpc_communication_enabled or client_ip() is None: level = OPERATIONAL if config.rpc_communication_enabled else DEBUG log(level, "RPC unavailable") return False try: return _request('echo', 'hello') == 'hello' except Exception, e: log(OPERATIONAL, "RPC exception:", e) return False
def value(self): # Temporary hack: Automatically upgrade the legacy values 'plain' and 'md5' # to the new UniversalPasswordStorage instance. This instance is compatible # with existing passwords when upgrade.72.sql was applied. value = super(CMSConfiguration._Option_password_storage, self).value() if value in ('plain', 'md5'): from pytis.util import OPERATIONAL, log log(OPERATIONAL, ("Value '%s' of configuration option 'password_storage' is not valid anymore. " "Using 'wiking.UniversalPasswordStorage() instead.") % value) value = wiking.UniversalPasswordStorage() return value
def init_select(view, data): sorting = view.sorting() if sorting is None: sorting = tuple([(k.id(), pd.DESCENDANT) for k in data.key() if view.field(k.id()) is not None]) success, select_count = pytis.form.db_operation(data.select, sort=sorting, reuse=False) if not success: log(EVENT, 'Selhání databázové operace') return None return select_count
def put_back(self, connection_spec, connection): pool = self._pool spec_id = self._connection_spec_id(connection_spec) with Locked(self._lock): try: connections = pool[spec_id] except KeyError: pool[spec_id] = connections = [] if ((pytis.config.max_pool_connections is None or len(connections) < pytis.config.max_pool_connections)): connections.append(connection) if __debug__: log(DEBUG, 'Connection returned to pool:', connection)
def value(self): # Temporary hack: Automatically upgrade the legacy values 'plain' and 'md5' # to the new UniversalPasswordStorage instance. This instance is compatible # with existing passwords when upgrade.72.sql was applied. value = super(CMSConfiguration._Option_password_storage, self).value() if value in ('plain', 'md5'): from pytis.util import OPERATIONAL, log log(OPERATIONAL, ( "Value '%s' of configuration option 'password_storage' is not valid anymore. " "Using 'wiking.UniversalPasswordStorage() instead.") % value) value = wiking.UniversalPasswordStorage() return value
def put_back(self, connection_spec, connection): pool = self._pool spec_id = self._connection_spec_id(connection_spec) def lfunction(): try: connections = pool[spec_id] except KeyError: pool[spec_id] = connections = [] import config if ((config.max_pool_connections is None or len(connections) < config.max_pool_connections)): connections.append(connection) with_lock(self._lock, lfunction) if __debug__: log(DEBUG, 'Connection returned to pool:', connection)
def __init__(self): try: data = pytis.data.dbtable('ev_pytis_user_help', ('help_id', 'fullname', 'spec_name', 'page_id', 'position', 'title', 'description', 'menu_help', 'content',)) except pd.DBException: log(OPERATIONAL, "Not using DMP help: DMP help tables not found in database.") raise self.NotAvailable() count = data.select(condition=pd.NE('help_id', pd.sval('menu/'))) data.close() if count == 0: log(OPERATIONAL, "Not using DMP help: DMP help tables are empty.") raise self.NotAvailable() self._data = data self._cached_descriptions = {} super(DmpHelpGenerator, self).__init__()
def __init__(self, permission, table=None, column=None): """ Arguments: permission -- the missing permission, one of the 'Permission' class constants table -- name of the table which couldn't be accessed, string or 'None' column -- name of the column which couldn't be accessed, string or 'None' """ log(EVENT, 'Access violation attempt', (pytis.config.dbconnection.user(), permission, table, column)) Exception.__init__(self, _(u"Access denied"), permission, table, column)
def __init__(self, permission, table=None, column=None): """ Arguments: permission -- the missing permission, one of the 'Permission' class constants table -- name of the table which couldn't be accessed, string or 'None' column -- name of the column which couldn't be accessed, string or 'None' """ import config log(EVENT, 'Access violation attempt', (config.dbconnection.user(), permission, table, column)) Exception.__init__(self, _(u"Access denied"), permission, table, column)
def _notif_listen_loop(self): while True: while self._pgnotif_connection is None: time.sleep(10) try: self._notif_init_connection() for notification in self._registered_notifications: self._notif_do_registration(notification) except Exception as e: self._pgnotif_connection = None connection_ = self._pgnotif_connection connection = connection_.connection() if __debug__: log(DEBUG, 'Listening for notifications:', connection) def lfunction(): cursor = connection.cursor() try: fileno = connection.fileno() except AttributeError: # older psycogp2 versions fileno = cursor.fileno() return cursor, fileno cursor, fileno = with_lock(self._pg_query_lock, lfunction) try: select.select([fileno], [], [], None) except Exception as e: if __debug__: log(DEBUG, 'Socket error', e.args) break if __debug__: log(DEBUG, 'Input received') def lfunction(): notifications = [] try: connection.poll() ready = True except AttributeError: # older psycopg2 versions try: ready = cursor.isready() except dbapi.OperationalError: self._pg_notif_connection = None return notifications if ready: notifies = connection.notifies if notifies: if __debug__: log(DEBUG, 'Data change registered') notifications = [] while notifies: notifications.append(notifies.pop()[1]) return notifications notifications = with_locks((self._notif_connection_lock, self._pg_query_lock,), lfunction) if __debug__: log(DEBUG, 'Notifications received:', notifications) self._notif_invoke_callbacks(notifications)
def SetValue(self, row, col, value): # Tato metoda neodpovídá specifikaci gridu, ale to nevadí, protože # políčka editujeme výhradně přes naše editory. assert isinstance(value, pytis.data.Value), ('Value not a value', value) edited = self._edited_row if edited is None: # K této situaci dochází, když se kliknutím myši opouští # rozeditované políčko řádku, jemuž ještě nebyla změněna žádná # hodnota. V takovém případě naše metody editaci nakrásno # ukončí a wxWindows po provedené změně řádku vesele zavolá # SetValue ... return # Nastav hodnotu editovanému sloupci cid = self._columns[col].id edited.update(cid, value) log(EVENT, 'Nastavena hodnota editovaného políčka:', (row, col, value))
def get(self, connection_spec): pool = self._pool spec_id = self._connection_spec_id(connection_spec) with Locked(self._lock): try: connections = pool[spec_id] except KeyError: pool[spec_id] = connections = [] try: allocated_connections = self._allocated_connections[spec_id] except KeyError: allocated_connections = self._allocated_connections[spec_id] \ = weakref.WeakKeyDictionary() c = None broken_connections_present = False while connections: c_candidate = connections.pop() if c_candidate.connection_info('broken'): broken_connections_present = True else: c = c_candidate if __debug__: log(DEBUG, 'Available connections:', connections) break if c is None or broken_connections_present: gc.collect() if c is None: if ((pytis.config.connection_limit is not None and len(allocated_connections) >= pytis.config.connection_limit)): if __debug__: log(EVENT, "Connections summary:") for c in allocated_connections.keys(): log(EVENT, "Connection:", c.connection_info('last_access')) raise DBSystemException( _(u"Too many database connections")) else: c = self._connection_creator(connection_spec) if __debug__: log(DEBUG, 'New connection created:', c) allocated_connections[c] = True if __debug__: log(DEBUG, 'Passing connection:', c) return c
def get(self, connection_spec): import config pool = self._pool spec_id = self._connection_spec_id(connection_spec) def lfunction(): try: connections = pool[spec_id] except KeyError: pool[spec_id] = connections = [] try: allocated_connections = self._allocated_connections[spec_id] except KeyError: allocated_connections = self._allocated_connections[spec_id] \ = weakref.WeakKeyDictionary() c = None broken_connections_present = False while connections: c_candidate = connections.pop() if c_candidate.connection_info('broken'): broken_connections_present = True else: c = c_candidate if __debug__: log(DEBUG, 'Available connections:', connections) break if c is None or broken_connections_present: gc.collect() if c is None: if ((config.connection_limit is not None and len(allocated_connections) >= config.connection_limit)): if __debug__: log(EVENT, "Connections summary:") for c in allocated_connections.keys(): log(EVENT, "Connection:", c.connection_info('last_access')) raise DBSystemException(_(u"Too many database connections")) else: c = self._connection_creator(connection_spec) if __debug__: log(DEBUG, 'New connection created:', c) allocated_connections[c] = True return c c = with_lock(self._lock, lfunction) if __debug__: log(DEBUG, 'Passing connection:', c) return c
def sleep(self): """Uvolni systémové zdroje využívané instancí a umožni její zrušení. Pokud instance využívá některé nedostatkové systémové zdroje jako například spojení do databáze nebo procesy, tato metoda by je měla uvolnit. Druhou funkcí metody je uvolnit prostředky (například hlídací procesy), které znemožňují zrušení instance. Tato metoda by měla být volána vždy, když je trvale nebo na delší dobu ukončeno používání instance. Zavoláním této metody se neznemožňuje další použití instance, lze nadále využívat všechny její veřejné metody. Je-li pak ovšem třeba opět uvolnit zdroje, je nutno tuto metodu zavolat znovu. """ if __debug__: log(DEBUG, 'Sleep') self.close()
def _notif_listen_loop(self): while True: while self._pgnotif_connection is None: time.sleep(10) try: self._notif_init_connection() for notification in self._registered_notifications: self._notif_do_registration(notification) except Exception as e: self._pgnotif_connection = None connection_ = self._pgnotif_connection connection = connection_.connection() if __debug__: log(DEBUG, 'Listening for notifications:', connection) with Locked(self._pg_query_lock): fileno = connection.fileno() try: select.select([fileno], [], [], None) except Exception as e: if __debug__: log(DEBUG, 'Socket error', e.args) break if __debug__: log(DEBUG, 'Input received') with Locked(self._notif_connection_lock), Locked( self._pg_query_lock): notifications = [] try: connection.poll() ready = True except dbapi.OperationalError: self._pg_notif_connection = None ready = False if ready: notifies = connection.notifies if notifies: if __debug__: log(DEBUG, 'Data change registered') while notifies: notifications.append(notifies.pop()[1]) if __debug__: log(DEBUG, 'Notifications received:', notifications) self._notif_invoke_callbacks(notifications)
def fetch(row, direction=pytis.data.FORWARD): result = self._data.fetchone(direction=direction) if result is None: # In theory this shouldn't happen but it actually happens so we # have to attempt some workaround here. data.rewind() if row > 0: data.skip(row - 1, direction=pytis.data.FORWARD) result = data.fetchone(direction=pytis.data.FORWARD) if result is None: # This shouldn't happen at all but it still happens. log(DEBUG, "Missing grid row") if require: raise Exception('Missing row', row) return None else: log(DEBUG, "Grid data synchronization error") self._presented_row.set_row(result) the_row = copy.copy(self._presented_row) self._current_row = self._CurrentRow(row, the_row)
def lfunction(): notifications = [] try: connection.poll() ready = True except AttributeError: # older psycopg2 versions try: ready = cursor.isready() except dbapi.OperationalError: self._pg_notif_connection = None return notifications if ready: notifies = connection.notifies if notifies: if __debug__: log(DEBUG, 'Data change registered') notifications = [] while notifies: notifications.append(notifies.pop()[1]) return notifications
def _reverse_forward_tunnel(self, transport): forward_host = self._forward_host forward_port = self._forward_port port = self._ssh_forward_port if not port: port = self._DEFAULT_SSH_FORWARD_PORT n_attempts = 1 if self._strict_forward_port else self._MAX_SSH_FORWARD_ATTEMPTS port_limit = port + n_attempts for p in range(port, port_limit): try: transport.request_port_forward('', p) break except paramiko.SSHException as e: log(EVENT, "Couldn't connect to port %s: %s" % (p, e,)) else: message = "No free port found in the range %s-%s" % (port, port_limit - 1,) log(OPERATIONAL, message) raise paramiko.SSHException(message) if self._actual_ssh_forward_port is not None: self._actual_ssh_forward_port.set(p) log(EVENT, 'Remote port %d forwarded to %s:%d' % (p, forward_host, forward_port,)) while True: chan = transport.accept(1000) if chan is None: continue gevent.spawn(self._handler, chan, forward_host, forward_port)
def _handler(self, chan, host, port): sock = socket.socket() try: sock.connect((host, port)) except Exception as e: log(OPERATIONAL, 'Forwarding request to %s:%d failed: %r' % (host, port, e)) return log( EVENT, 'Tunnel open %r -> %r -> %r' % (chan.origin_addr, chan.getpeername(), (host, port))) while True: r, w, x = select.select([sock, chan], [], []) if sock in r: data = sock.recv(1024) if len(data) == 0: break chan.send(data) if chan in r: data = chan.recv(1024) if len(data) == 0: break sock.send(data) chan.close() sock.close() log(EVENT, 'Tunnel closed from %r' % (chan.origin_addr, ))
def run(self): self._actual_ssh_port = None # Get parameters ssh_host = self._ssh_host ssh_port = self._ssh_port forward_host = self._forward_host forward_port = self._forward_port user = self._ssh_user or getpass.getuser() password = self._ssh_password key_filename = self._key_filename if key_filename is None and not os.getenv('SSH_AGENT_PID'): key_filename = os.path.expanduser('~/.ssh/id_rsa') if not os.path.exists(key_filename): key_filename = None # Create client client = paramiko.SSHClient() client.load_system_host_keys() client.set_missing_host_key_policy(paramiko.WarningPolicy()) # Connect to the ssh host log(EVENT, 'Connecting to ssh host %s:%d' % (ssh_host, ssh_port,)) try: client.connect(hostname=ssh_host, port=ssh_port, username=user, key_filename=key_filename, password=password, gss_auth=self._gss_auth) except Exception as e: log(OPERATIONAL, 'Failed to connect to %s@%s:%d: %r' % (user, ssh_host, ssh_port, e,)) return # Forward log(EVENT, 'Forwarding remote port %d+ to %s:%d' % (self._ssh_forward_port or self._DEFAULT_SSH_FORWARD_PORT, forward_host, forward_port,)) self._reverse_forward_tunnel(client.get_transport())
def __init__(self, message, exception=None, *args): """Inicializuj výjimku a zaloguj informace o ní. Argumenty: message -- lidsky čitelné oznámení o chybě, string; může být též 'None', v kterémžto případě se doplní standardní zpráva o databázové chybě, to je však vhodné používat pouze v případě, kdy nemá smysl uživateli sdělovat bližší popis chyby exception -- výjimka, která tuto výjimku způsobila, instance třídy 'Exception'; nebo 'None' (neznamená nutně, že chyba nebyla způsobena výjimkou, tato výjimka pouze nemusí být podstatná) args -- libovolné další argumenty, které mají být spolu s 'message' a 'exception' předány konstruktoru nadtřídy """ if message is None: message = _(u"Database error") super_(DBException).__init__(self, message, exception, *args) log(OPERATIONAL, 'Database exception', (message,) + args) if exception: log(OPERATIONAL, 'Wrapped database exception', (exception,) + exception.args) self._message = message self._exception = exception
def parse_x2go_info_file(filename): try: f = open(filename) except Exception as e: log(OPERATIONAL, "Can't read pytis X2Go file", e) return None data = '' while True: d = f.read() if not d: break data += d items = data.split(':') if len(items) != 4: raise X2GoInfoSoftException("Incomplete or invalid X2Go file") if items[0] != '0': raise X2GoInfoHardException("Unknown pytis X2Go format") access_data = {} try: access_data['port'] = int(items[1]) except ValueError: raise X2GoInfoHardException("Invalid port number in X2Go file", items[1]) access_data['password'] = items[2] return access_data
def run(self): self._actual_ssh_port = None # Get parameters ssh_host = self._ssh_host ssh_port = self._ssh_port forward_host = self._forward_host forward_port = self._forward_port user = self._ssh_user or getpass.getuser() password = self._ssh_password key_filename = self._key_filename if key_filename is None and not os.getenv('SSH_AGENT_PID'): key_filename = os.path.expanduser('~/.ssh/id_rsa') if not os.path.exists(key_filename): key_filename = None # Create client client = paramiko.SSHClient() client.load_system_host_keys() client.set_missing_host_key_policy(paramiko.WarningPolicy()) # Connect to the ssh host log(EVENT, 'Connecting to ssh host %s:%d' % ( ssh_host, ssh_port, )) try: client.connect(hostname=ssh_host, port=ssh_port, username=user, key_filename=key_filename, password=password, gss_auth=self._gss_auth) except Exception as e: log( OPERATIONAL, 'Failed to connect to %s@%s:%d: %r' % ( user, ssh_host, ssh_port, e, )) return # Forward log( EVENT, 'Forwarding remote port %d+ to %s:%d' % ( self._ssh_forward_port or self._DEFAULT_SSH_FORWARD_PORT, forward_host, forward_port, )) self._reverse_forward_tunnel(client.get_transport())
def _reverse_forward_tunnel(self, transport): forward_host = self._forward_host forward_port = self._forward_port port = self._ssh_forward_port if not port: port = self._DEFAULT_SSH_FORWARD_PORT n_attempts = 1 if self._strict_forward_port else self._MAX_SSH_FORWARD_ATTEMPTS port_limit = port + n_attempts for p in range(port, port_limit): try: transport.request_port_forward('', p) break except paramiko.SSHException as e: log(EVENT, "Couldn't connect to port %s: %s" % ( p, e, )) else: message = "No free port found in the range %s-%s" % ( port, port_limit - 1, ) log(OPERATIONAL, message) raise paramiko.SSHException(message) if self._actual_ssh_forward_port is not None: self._actual_ssh_forward_port.set(p) log( EVENT, 'Remote port %d forwarded to %s:%d' % ( p, forward_host, forward_port, )) while True: chan = transport.accept(1000) if chan is None: continue gevent.spawn(self._handler, chan, forward_host, forward_port)
def _handler(self, chan, host, port): sock = socket.socket() try: sock.connect((host, port)) except Exception as e: log(OPERATIONAL, 'Forwarding request to %s:%d failed: %r' % (host, port, e)) return log(EVENT, 'Tunnel open %r -> %r -> %r' % (chan.origin_addr, chan.getpeername(), (host, port))) while True: r, w, x = select.select([sock, chan], [], []) if sock in r: data = sock.recv(1024) if len(data) == 0: break chan.send(data) if chan in r: data = chan.recv(1024) if len(data) == 0: break sock.send(data) chan.close() sock.close() log(EVENT, 'Tunnel closed from %r' % (chan.origin_addr,))
def __init__(self, req): """Initialize the global wiking handler instance. The argument 'req' is the initial request which triggered the Handler creation, however the handler will normally exist much longer than for this single request and its method 'handle()' will be called to handle also other requests (including this one). The constructor only needs the request instance to gather some global information to be able to initialize the configuration etc. """ # Initialize the global configuration stored in 'wiking.cfg'. config_file = req.option("config_file") if config_file: # Read the configuration file first, so that the request options have a higher priority. wiking.cfg.user_config_file = config_file for option in wiking.cfg.options(): name = option.name() value = req.option(name) if value and name != "config_file": if name in ("translation_path", "resource_path", "modules"): separator = value.find(":") != -1 and ":" or "," value = tuple([d.strip() for d in value.split(separator)]) if name == "translation_path": value = tuple(wiking.cfg.translation_path) + value elif name == "resource_path": value += tuple(wiking.cfg.resource_path) elif isinstance(option, wiking.cfg.NumericOption): if value.isdigit(): value = int(value) else: log(OPERATIONAL, "Invalid numeric value for '%s':" % name, value) continue elif isinstance(option, wiking.cfg.BooleanOption): if value.lower() in ("yes", "true", "on"): value = True elif value.lower() in ("no", "false", "off"): value = False else: log(OPERATIONAL, "Invalid boolean value for '%s':" % name, value) continue elif not isinstance(option, wiking.cfg.StringOption): log(OPERATIONAL, "Unable to set '%s' through request options." % name) continue setattr(wiking.cfg, name, value) # Apply default values which depend on the request. server_hostname = wiking.cfg.server_hostname if server_hostname is None: # TODO: The name returned by req.server_hostname() works for simple # cases where there are no server aliases, but we can not guarantee # that it is really unique. Thus might be safer to raise an error # when req.primary_server_hostname() returns None and require # configuring server_hostname explicitly. server_hostname = req.primary_server_hostname() or req.server_hostname() wiking.cfg.server_hostname = server_hostname domain = server_hostname if domain.startswith("www."): domain = domain[4:] if wiking.cfg.webmaster_address is None: wiking.cfg.webmaster_address = "webmaster@" + domain if wiking.cfg.default_sender_address is None: wiking.cfg.default_sender_address = "wiking@" + domain if wiking.cfg.dbname is None: wiking.cfg.dbname = server_hostname if wiking.cfg.resolver is None: wiking.cfg.resolver = wiking.WikingResolver(wiking.cfg.modules) # Modify pytis configuration. import pytis.util import config config.dblisten = False config.log_exclude = [pytis.util.ACTION, pytis.util.EVENT, pytis.util.DEBUG] for option in ("dbname", "dbhost", "dbport", "dbuser", "dbpass", "dbsslm", "dbschemas"): setattr(config, option, getattr(wiking.cfg, option)) config.dbconnections = wiking.cfg.connections config.dbconnection = config.option("dbconnection").default() config.resolver = wiking.cfg.resolver del config self._application = application = wiking.module.Application self._exporter = wiking.cfg.exporter(translations=wiking.cfg.translation_path) application.initialize(req) # Save the current handler instance for profiling purposes. Handler._instance = self
def top_level_exception(message=None): """Zpracuj aktuálně vyvolanou výjimku aplikace.""" global _in_top_level_exception if _in_top_level_exception: return _in_top_level_exception = True einfo = sys.exc_info() if issubclass(einfo[0], SystemExit): sys.exit() tbstring = format_traceback() import cgitb try: tbstring = cgitb.text(einfo) except: import traceback tbstring = "\n".join(traceback.format_exception(*einfo)) log(OPERATIONAL, 'Top-level exception caught', tbstring) text = pytis.form.run_dialog(pytis.form.BugReport, einfo, message=message) if text is None: sys.exit() elif text: to = config.bug_report_address if not to: pytis.form.run_dialog( pytis.form.Message, _("Destination address not known. The configuration option " "`bug_report_address' must be set.")) else: tb = einfo[2] while tb.tb_next is not None: tb = tb.tb_next filename = os.path.split(tb.tb_frame.f_code.co_filename)[-1] buginfo = "%s at %s line %d" % (einfo[0].__name__, filename, tb.tb_lineno) address = config.sender_address if not address: import commands status, domain = commands.getstatusoutput('hostname -f') username = config.dbconnection.user() if status: address = username else: address = '%s@%s' % (username, domain) while True: address = pytis.form.run_dialog( pytis.form.InputDialog, prompt=_("Your e-mail address") + ': ', value=address, input_width=30, message=(_('Set your address in form "%s" ' 'to avoid being ' 'asked next time.') % (_("User interface settings"), ))) if address is None or address and address.strip() != '': break if address: import email.Header import email.Message import email.Utils import smtplib def header(value): if isinstance(value, basestring): try: unicode(value, 'us-ascii') except: pass else: return value return email.Header.Header(value, 'utf-8') msg = email.Message.Message() msg['From'] = header(address) msg['To'] = header(to) msg['Subject'] = header('%s: %s' % (config.bug_report_subject, buginfo)) msg['Date'] = email.Utils.formatdate() msg.set_payload(text) try: try: server = smtplib.SMTP(config.smtp_server) server.sendmail(address, to, msg.as_string()) finally: try: server.quit() except: pass except Exception as e: pytis.form.run_dialog( pytis.form.Error, _("Failed sending error report:") + "\n" + unicode(e)) else: pytis.form.run_dialog(pytis.form.Message, _("Error report sent.")) if config.debug_on_error: import pdb pdb.post_mortem(sys.exc_info()[2]) _in_top_level_exception = False
def __init__(self, bindings, ordering=None, distinct_on=(), arguments=None, crypto_names=(), **kwargs): """Inicializuj tabulku s napojením do databáze. Argumenty: bindings -- sekvence instancí třídy 'DBBinding' ordering -- stejné jako v předkovi distinct_on -- sequence of column names to add as a DISTINCT TO part to SELECT commands arguments -- sequence of 'DBBinding' instances defining table arguments, when the table is actually a row returning function. Otherwise it must be 'None'. crypto_names -- sequence of additional crypto names (strings) required by the object but not defined in bindings kwargs -- k předání předkovi Sloupce datové tabulky se určí automaticky na základě 'bindings'. Jejich typy jsou určeny typy odpovídajících dat v databázi(přesné mapování závisí na potomcích třídy a není zde specifikováno). Klíčovým sloupcem tabulky je první sloupec z 'bindings', který je klíčovým sloupcem v databázi. Žádné dva prvky 'bindings' by neměly mít shodné id, s výjimkou skrytých bindings, která mají jako id prázdný řetězec. """ assert is_sequence(bindings), ('Invalid binding type', bindings) self._bindings = tuple(bindings) assert not filter(lambda b: not isinstance(b, DBBinding), bindings), \ ('Invalid binding type', bindings) assert arguments is None or is_sequence(arguments), ('Invalid binding type', arguments) if arguments is None: self._arguments = None else: self._arguments = tuple(arguments) assert not filter(lambda b: not isinstance(b, DBBinding), arguments), \ ('Invalid "argument" type', arguments) if __debug__: log(DEBUG, 'Database instance bindings:', self._bindings) columns, key = self._db_bindings_to_column_spec(self._bindings) if __debug__: log(DEBUG, 'Database instance columns:', columns) if __debug__: log(DEBUG, 'Database instance key:', key) self._distinct_on = distinct_on assert is_sequence(crypto_names), crypto_names if __debug__: assert all([isinstance(n, basestring) for n in crypto_names]), crypto_names crypto_names = list(crypto_names) for b in bindings: if isinstance(b, DBColumnBinding): n = b.crypto_name() if n is not None and n not in crypto_names: crypto_names.append(n) self._crypto_names = crypto_names try: del kwargs['key'] except: pass super(DBData, self).__init__(columns=columns, key=key, ordering=ordering, **kwargs)
def _postgresql_query(self, connection, query, outside_transaction, _retry=True): result = None def transform_arg(arg): if isinstance(arg, Range.Range): lower = arg.lower() upper = arg.upper() test_value = upper if lower is None else lower if isinstance(test_value, (int, long, float,)): c = psycopg2.extras.NumericRange elif isinstance(test_value, datetime.datetime): if test_value.tzinfo is None: c = psycopg2.extras.DateTimeRange else: c = psycopg2.extras.DateTimeTZRange elif isinstance(test_value, datetime.date): c = psycopg2.extras.DateRange else: raise Exception("Unsupported range type", arg) bounds = ('[' if arg.lower_inc() else '(') + (']' if arg.upper_inc() else ')') arg = c(lower, upper, bounds=bounds) return arg if isinstance(query, basestring): query_args = {} else: query, args = query.query() query_args = dict([(k, transform_arg(v)) for k, v in args.items()]) def do_query(connection, query): raw_connection = connection.connection() standard_strings = connection.connection_info('standard_strings') if not standard_strings: query = query.replace('\\', '\\\\') cursor = raw_connection.cursor() callback = self._query_callback[0] # The hasattr test is a hack enforced by the fact that constructor # calls of pytis.data classes are in very strange state now. if hasattr(self, '_sql_logger') and self._sql_logger is not None: if query_args: def escape(arg): if isinstance(arg, basestring): result = "'%s'" % (arg.replace('\x00', '\\0').replace("'", "''"),) if not standard_strings: result = result.replace('\\', '\\\\') elif isinstance(arg, buffer): result = '<binary_data>' else: result = arg return result escaped_args = dict([(k, escape(v)) for k, v in query_args.items()]) query_string = query % escaped_args else: query_string = query self._sql_logger.write(query_string + '\n') if callback is not None: start_time = time.time() # query_args shouldn't be used when empty to prevent mistaken # '%' processing in `query' try: if query_args: cursor.execute(query, query_args) else: cursor.execute(query) connection.connection_info('transaction_commands').append(query) finally: if outside_transaction: raw_connection.commit() self._postgresql_reset_connection_info(connection, ['commit']) if callback is not None: callback(query, start_time, time.time()) return cursor def retry(message, exception): connection.set_connection_info('broken', True) if _retry: if not outside_transaction: raise DBRetryException(message, exception, exception.args, query) cdata = connection.connection_data() search_path = connection.connection_info('search_path') new_connection = self._postgresql_new_connection(cdata) try: if search_path: do_query(new_connection, 'set search_path to ' + search_path) result = do_query(new_connection, query) except Exception as e: raise DBSystemException(message, e, e.args, query) else: raise DBSystemException(message, exception, exception.args, query) return result, new_connection try: result = do_query(connection, query) if query == 'commit': self._postgresql_commit_transaction(connection) elif query == 'rollback': self._postgresql_rollback_transaction(connection) except dbapi.InterfaceError as e: if e.args and e.args[0].find('connection already closed') != -1: # We believe this shouldn't happen as a program error and it # may occur as a result of database engine connection crash. log(OPERATIONAL, "Access to closed database connection") result, connection = retry(_(u"Database interface error"), e) else: raise DBUserException(None, e, e.args, query) except dbapi.NotSupportedError as e: if e.args and e.args[0].find('cannot perform INSERT RETURNING') != -1: # This is handled once again below since older dbapi versions report it as # ProgrammingError and newer versions as NotSupportedError. raise DBInsertException() raise DBUserException(None, e, e.args, query) except dbapi.ProgrammingError as e: if e.args: position = e.args[0].find if position('could not obtain lock') != -1: raise DBLockException() elif position('cannot perform INSERT RETURNING') != -1: raise DBInsertException() elif (position('error: Connection timed out') != -1 or position('timeout expired') != -1): raise DBSystemException(_(u"Database connection timeout"), e, e.args, query) elif position('server closed the connection unexpectedly') != -1: result, connection = retry(_(u"Database connection error"), e) else: log(OPERATIONAL, "Transaction commands:", connection.connection_info('transaction_commands')) data = '%s [search_path=%s]' % (query, connection.connection_info('search_path'),) raise DBUserException(None, e, e.args, data) else: raise DBUserException(None, e, e.args, query) except dbapi.DataError as e: raise DBUserException(None, e, e.args, query) except dbapi.OperationalError as e: if e.args and e.args[0].find('could not obtain lock') != -1: raise DBLockException() result, connection = retry(_(u"Database operational error"), e) except dbapi.InternalError as e: raise DBException(None, e, query) except dbapi.IntegrityError as e: raise DBUserException(_(u"Database integrity violation"), e, e.args, query) now = time.time() connection.set_connection_info('last_query_time', now) connection.set_connection_info('last_activity', now) if connection.connection_info('transaction_start_time') is None: connection.set_connection_info('transaction_start_time', now) if __debug__: if query not in ('commit', 'rollback',): connection.set_connection_info('transaction_start_stack', inspect.currentframe()) if __debug__: if query.startswith('fetch') or query.startswith('skip'): extra_info = (query,) else: self._last_informative_query = query extra_info = () info = (time.ctime(now), self._last_informative_query,) + extra_info connection.set_connection_info('last_access', info) return self._postgresql_Result(result), connection
def select_row(self, *args, **kwargs): if hasattr(self._main_form, 'select_row'): return self._main_form.select_row(*args, **kwargs) else: log(EVENT, "Main form doesn't support `select_row()'!")
def _panic(self): if __debug__: log(DEBUG, 'Zpanikaření gridové tabulky')
def process_event(event, callback=callback): def system_callback(): # Při zamykání atd. se využívá toho, že v existují jen dvě vlákna # zpracovávající události a že v rámci jednoho vlákna dochází pouze # k sekvenčnímu nebo cibulovitému řazení událostí. STATE_CURRENT = 'STATE_CURRENT' STATE_FREE = 'STATE_FREE' STATE_BLOCKED = 'STATE_BLOCKED' global _system_callback_thread_ident, _system_callback_lock _system_callback_access_lock.acquire() try: ident = _thread.get_ident() if _system_callback_thread_ident == ident: # Jsme uvnitř vlastní slupky, jsme v pohodě state = STATE_CURRENT elif (_system_callback_thread_ident is None and _system_callback_lock is None): # Nikdo jiný nemá zájem, uzmeme to _system_callback_thread_ident = ident state = STATE_FREE else: # Máme konkurenci -- vytvoříme si synchronizační zámek pro # oznámení uvolnění cesty _system_callback_lock = lock = _thread.allocate_lock() _system_callback_lock.acquire() state = STATE_BLOCKED finally: _system_callback_access_lock.release() if state == STATE_BLOCKED: # Čekáme na uvolnění cesty lock.acquire() lock.release() _system_callback_access_lock.acquire() try: # Ještě stále je to náš synchronizační zámek? Uvolni jej! if _system_callback_lock is lock: _system_callback_lock = None # Teď jsme na koni my _system_callback_thread_ident = ident state = STATE_FREE finally: _system_callback_access_lock.release() try: # To hlavní... result = callback(event) finally: _system_callback_access_lock.acquire() try: # Jako první usurpátoři musíme uvolnit informace o své # cibuli ... if state == STATE_FREE: _system_callback_thread_ident = None if _system_callback_lock is not None: while True: try: # ... a poslat signál případnému čekateli _system_callback_lock.release() break except _thread.error: # To je případ, kdy čekatel ještě nestačil # na svůj zámek zavolat acquire pass finally: _system_callback_access_lock.release() return result if isinstance(event, wx.IdleEvent) and idle_blocked(): return global _current_event, _interrupted, _last_user_event, _last_user_event_time is_user = _is_user_event(event) if is_user: pytis.form.message('') if not isinstance(event, (wx.IdleEvent, wx.UpdateUIEvent)): if __debug__: log(DEBUG, 'Processing event:', (event, event.__class__)) try: if _thread.get_ident() == _watcher_thread_ident or _current_event: # Událost během události if _wx_key and _wx_key.is_event_of_key(event, 'Ctrl-g'): # TODO: ne natvr. _interrupted = True result = True elif is_user: result = True else: result = system_callback() elif is_user and pytis.form.modal(pytis.form.top_window()): # Událost vyvolaná uživatelským příkazem v modálním okně result = callback(event) elif is_user: # Událost vyvolaná uživatelským příkazem _interrupted = False _current_event = event try: result = callback(event) finally: _interrupted = False # událost končí -> nebude co přerušit _current_event = None _last_user_event = event else: # Standardní "systémová" událost result = system_callback() except SystemExit: raise except Exception: top_level_exception() return finally: if is_user: _last_user_event_time = time.time() return result
def __init__(self, bindings, ordering=None, distinct_on=(), arguments=None, crypto_names=(), **kwargs): """Inicializuj tabulku s napojením do databáze. Argumenty: bindings -- sekvence instancí třídy 'DBBinding' ordering -- stejné jako v předkovi distinct_on -- sequence of column names to add as a DISTINCT TO part to SELECT commands arguments -- sequence of 'DBBinding' instances defining table arguments, when the table is actually a row returning function. Otherwise it must be 'None'. crypto_names -- sequence of additional crypto names (strings) required by the object but not defined in bindings kwargs -- k předání předkovi Sloupce datové tabulky se určí automaticky na základě 'bindings'. Jejich typy jsou určeny typy odpovídajících dat v databázi(přesné mapování závisí na potomcích třídy a není zde specifikováno). Klíčovým sloupcem tabulky je první sloupec z 'bindings', který je klíčovým sloupcem v databázi. Žádné dva prvky 'bindings' by neměly mít shodné id, s výjimkou skrytých bindings, která mají jako id prázdný řetězec. """ assert all(isinstance(b, DBBinding) for b in bindings), bindings assert arguments is None or all( isinstance(b, DBBinding) for b in arguments), arguments assert all([isinstance(n, basestring) for n in crypto_names]), crypto_names self._bindings = tuple(bindings) if arguments is None: self._arguments = None else: self._arguments = tuple(arguments) if __debug__: log(DEBUG, 'Database instance bindings:', self._bindings) columns, key = self._db_bindings_to_column_spec(self._bindings) if __debug__: log(DEBUG, 'Database instance columns:', columns) if __debug__: log(DEBUG, 'Database instance key:', key) self._distinct_on = distinct_on self._crypto_names = list( set(crypto_names).union(b.crypto_name() for b in bindings if isinstance(b, DBColumnBinding) and b.crypto_name() is not None)) try: del kwargs['key'] except Exception: pass super(DBData, self).__init__(columns=columns, key=key, ordering=ordering, **kwargs)
def __init__(self, req): """Initialize the global wiking handler instance. The argument 'req' is the initial request which triggered the Handler creation, however the handler will normally exist much longer than for this single request and its method 'handle()' will be called to handle also other requests (including this one). The constructor only needs the request instance to gather some global information to be able to initialize the configuration etc. """ # Initialize the global configuration stored in 'wiking.cfg'. config_file = req.option('config_file') if config_file: # Read the configuration file first, so that the request options have a higher priority. wiking.cfg.user_config_file = config_file for option in wiking.cfg.options(): name = option.name() value = req.option(name) if value and name != 'config_file': if name in ('translation_path', 'resource_path', 'modules'): separator = value.find(':') != -1 and ':' or ',' value = tuple([d.strip() for d in value.split(separator)]) if name == 'translation_path': value = tuple(wiking.cfg.translation_path) + value elif name == 'resource_path': value += tuple(wiking.cfg.resource_path) elif isinstance(option, wiking.cfg.NumericOption): if value.isdigit(): value = int(value) else: log(OPERATIONAL, "Invalid numeric value for '%s':" % name, value) continue elif isinstance(option, wiking.cfg.BooleanOption): if value.lower() in ('yes', 'true', 'on'): value = True elif value.lower() in ('no', 'false', 'off'): value = False else: log(OPERATIONAL, "Invalid boolean value for '%s':" % name, value) continue elif not isinstance(option, wiking.cfg.StringOption): log(OPERATIONAL, "Unable to set '%s' through request options." % name) continue setattr(wiking.cfg, name, value) # Apply default values which depend on the request. server_hostname = wiking.cfg.server_hostname if server_hostname is None: # TODO: The name returned by req.server_hostname() works for simple # cases where there are no server aliases, but we can not guarantee # that it is really unique. Thus might be safer to raise an error # when req.primary_server_hostname() returns None and require # configuring server_hostname explicitly. server_hostname = req.primary_server_hostname() or req.server_hostname() wiking.cfg.server_hostname = server_hostname domain = server_hostname if domain.startswith('www.'): domain = domain[4:] if wiking.cfg.webmaster_address is None: wiking.cfg.webmaster_address = 'webmaster@' + domain if wiking.cfg.default_sender_address is None: wiking.cfg.default_sender_address = 'wiking@' + domain if wiking.cfg.dbname is None: wiking.cfg.dbname = server_hostname if wiking.cfg.resolver is None: wiking.cfg.resolver = wiking.WikingResolver(wiking.cfg.modules) # Modify pytis configuration. pytis.config.dblisten = False pytis.config.log_exclude = [pytis.util.ACTION, pytis.util.EVENT, pytis.util.DEBUG] for option in ('dbname', 'dbhost', 'dbport', 'dbuser', 'dbpass', 'dbsslm', 'dbschemas',): setattr(pytis.config, option, getattr(wiking.cfg, option)) pytis.config.dbconnections = wiking.cfg.dbconnections pytis.config.dbconnection = pytis.config.option('dbconnection').default() pytis.config.resolver = wiking.cfg.resolver self._application = application = wiking.module.Application self._exporter = wiking.cfg.exporter(translations=wiking.cfg.translation_path) application.initialize(req) # Save the current handler instance for profiling purposes. Handler._instance = self
def _postgresql_query(self, connection, query, outside_transaction, _retry=True): result = None def transform_arg(arg): if isinstance(arg, Range.Range): lower = arg.lower() upper = arg.upper() test_value = upper if lower is None else lower if isinstance(test_value, ( int, long, float, )): c = psycopg2.extras.NumericRange elif isinstance(test_value, datetime.datetime): if test_value.tzinfo is None: c = psycopg2.extras.DateTimeRange else: c = psycopg2.extras.DateTimeTZRange elif isinstance(test_value, datetime.date): c = psycopg2.extras.DateRange else: raise Exception("Unsupported range type", arg) bounds = ('[' if arg.lower_inc() else '(') + (']' if arg.upper_inc() else ')') arg = c(lower, upper, bounds=bounds) return arg if isinstance(query, basestring): query_args = {} else: query, args = query.query() query_args = dict([(k, transform_arg(v)) for k, v in args.items()]) def do_query(connection, query): raw_connection = connection.connection() standard_strings = connection.connection_info('standard_strings') if not standard_strings: query = query.replace('\\', '\\\\') cursor = raw_connection.cursor() callback = self._query_callback[0] # The hasattr test is a hack enforced by the fact that constructor # calls of pytis.data classes are in very strange state now. if hasattr(self, '_sql_logger') and self._sql_logger is not None: if query_args: def escape(arg): if isinstance(arg, basestring): result = "'%s'" % (arg.replace( '\x00', '\\0').replace("'", "''"), ) if not standard_strings: result = result.replace('\\', '\\\\') elif isinstance(arg, buffer): result = '<binary_data>' else: result = arg return result escaped_args = dict([(k, escape(v)) for k, v in query_args.items()]) query_string = query % escaped_args else: query_string = query self._sql_logger.write(query_string + '\n') if callback is not None: start_time = time.time() # query_args shouldn't be used when empty to prevent mistaken # '%' processing in `query' try: if query_args: cursor.execute(query, query_args) else: cursor.execute(query) connection.connection_info('transaction_commands').append( query) finally: if outside_transaction: raw_connection.commit() self._postgresql_reset_connection_info( connection, ['commit']) if callback is not None: callback(query, start_time, time.time()) return cursor def retry(message, exception): connection.set_connection_info('broken', True) if _retry: if not outside_transaction: raise DBRetryException(message, exception, exception.args, query) cdata = connection.connection_data() search_path = connection.connection_info('search_path') new_connection = self._postgresql_new_connection(cdata) try: if search_path: do_query(new_connection, 'set search_path to ' + search_path) result = do_query(new_connection, query) except Exception as e: raise DBSystemException(message, e, e.args, query) else: raise DBSystemException(message, exception, exception.args, query) return result, new_connection try: result = do_query(connection, query) if query == 'commit': self._postgresql_commit_transaction(connection) elif query == 'rollback': self._postgresql_rollback_transaction(connection) except dbapi.InterfaceError as e: if e.args and e.args[0].find('connection already closed') != -1: # We believe this shouldn't happen as a program error and it # may occur as a result of database engine connection crash. log(OPERATIONAL, "Access to closed database connection") result, connection = retry(_(u"Database interface error"), e) else: raise DBUserException(None, e, e.args, query) except dbapi.NotSupportedError as e: if e.args and e.args[0].find( 'cannot perform INSERT RETURNING') != -1: # This is handled once again below since older dbapi versions report it as # ProgrammingError and newer versions as NotSupportedError. raise DBInsertException() raise DBUserException(None, e, e.args, query) except dbapi.ProgrammingError as e: if e.args: position = e.args[0].find if position('could not obtain lock') != -1: raise DBLockException() elif position('cannot perform INSERT RETURNING') != -1: raise DBInsertException() elif (position('error: Connection timed out') != -1 or position('timeout expired') != -1): raise DBSystemException(_(u"Database connection timeout"), e, e.args, query) elif position( 'server closed the connection unexpectedly') != -1: result, connection = retry(_(u"Database connection error"), e) else: log(OPERATIONAL, "Transaction commands:", connection.connection_info('transaction_commands')) data = '%s [search_path=%s]' % ( query, connection.connection_info('search_path'), ) raise DBUserException(None, e, e.args, data) else: raise DBUserException(None, e, e.args, query) except dbapi.DataError as e: raise DBUserException(None, e, e.args, query) except dbapi.OperationalError as e: if e.args and e.args[0].find('could not obtain lock') != -1: raise DBLockException() result, connection = retry(_(u"Database operational error"), e) except dbapi.InternalError as e: raise DBException(None, e, query) except dbapi.IntegrityError as e: raise DBUserException(_(u"Database integrity violation"), e, e.args, query) now = time.time() connection.set_connection_info('last_query_time', now) connection.set_connection_info('last_activity', now) if connection.connection_info('transaction_start_time') is None: connection.set_connection_info('transaction_start_time', now) if __debug__: if query not in ( 'commit', 'rollback', ): connection.set_connection_info('transaction_start_stack', inspect.currentframe()) if __debug__: if query.startswith('fetch') or query.startswith('skip'): extra_info = (query, ) else: self._last_informative_query = query extra_info = () info = ( time.ctime(now), self._last_informative_query, ) + extra_info connection.set_connection_info('last_access', info) return self._postgresql_Result(result), connection
def _notif_listen_loop(self): while True: while self._pgnotif_connection is None: time.sleep(10) try: self._notif_init_connection() for notification in self._registered_notifications: self._notif_do_registration(notification) except Exception as e: self._pgnotif_connection = None connection_ = self._pgnotif_connection connection = connection_.connection() if __debug__: log(DEBUG, 'Listening for notifications:', connection) def lfunction(): cursor = connection.cursor() try: fileno = connection.fileno() except AttributeError: # older psycogp2 versions fileno = cursor.fileno() return cursor, fileno cursor, fileno = with_lock(self._pg_query_lock, lfunction) try: select.select([fileno], [], [], None) except Exception as e: if __debug__: log(DEBUG, 'Socket error', e.args) break if __debug__: log(DEBUG, 'Input received') def lfunction(): notifications = [] try: connection.poll() ready = True except AttributeError: # older psycopg2 versions try: ready = cursor.isready() except dbapi.OperationalError: self._pg_notif_connection = None return notifications if ready: notifies = connection.notifies if notifies: if __debug__: log(DEBUG, 'Data change registered') notifications = [] while notifies: notifications.append(notifies.pop()[1]) return notifications notifications = with_locks(( self._notif_connection_lock, self._pg_query_lock, ), lfunction) if __debug__: log(DEBUG, 'Notifications received:', notifications) self._notif_invoke_callbacks(notifications)
def IsAcceptedKey(self, event): # TODO/wx: Z neznámých důvodů není voláno. if __debug__: log(DEBUG, 'Neuvěřitelné -- voláno IsAcceptedKey') return False
def apply_profile(self, *args, **kwargs): if hasattr(self._main_form, 'apply_profile'): return self._main_form.apply_profile(*args, **kwargs) else: log(EVENT, "Main form doesn't support `apply_profile()'!")