def obj_docstring(obj): ''' Return a docstring for `obj` which has been passed through `stripped_dedent`. This function uses `obj.__doc__` if it is not `None`, otherwise `getcomments(obj)` if that is not `None`, otherwise `''`. The chosen string is passed through `stripped_dedent` before return. ''' docstring = getattr(obj, '__doc__', None) if docstring is None: docstring = '\n'.join( map(lambda line: cutprefix(line, '# '), (getcomments(obj) or '').rstrip().split('\n'))) return stripped_dedent(docstring)
def subcommand_usage_text( cls, subcmd, usage_format_mapping=None, short=False ): ''' Return the usage text for a subcommand. Parameters: * `subcmd`: the subcommand name * `short`: just include the first line of the usage message, intented for when there are many subcommands ''' method = cls.subcommands()[subcmd].method subusage = None # support (method, get_suboptions) try: classy = issubclass(method, BaseCommand) except TypeError: classy = False if classy: # first paragraph of the class usage text doc = method.usage_text(cmd=subcmd) subusage_format, *_ = cutprefix(doc, 'Usage:').lstrip().split("\n\n", 1) else: # extract the usage from the object docstring doc = obj_docstring(method) if doc: if 'Usage:' in doc: # extract the Usage: paragraph pre_usage, post_usage = doc.split('Usage:', 1) pre_usage = pre_usage.strip() post_usage_format, *_ = post_usage.split('\n\n', 1) subusage_format = stripped_dedent(post_usage_format) else: # extract the first paragraph subusage_format, *_ = doc.split('\n\n', 1) else: # default usage text - include the docstring below a header subusage_format = "\n ".join( ['{cmd} ...'] + [doc.split('\n\n', 1)[0]] ) if subusage_format: if short: subusage_format, *_ = subusage_format.split('\n', 1) mapping = dict(sys.modules[method.__module__].__dict__) if usage_format_mapping: mapping.update(usage_format_mapping) mapping.update(cmd=subcmd) subusage = subusage_format.format_map(mapping) return subusage or None
def __getattr__(self, attr): field_name = cutprefix(attr, 'by_') if field_name is not attr: with Pfx("%s.%s", type(self).__name__, attr): pk_name = self.IndexedSetMixin__pk assert pk_name, "empty .IndexedSetMixin__pk" by_pk = 'by_' + pk_name indexed = self.__indexed with self._lock: if field_name in indexed: return self.__dict__[attr] by_map = {} if field_name == pk_name: records = self.scan() else: records = getattr(self, by_pk).values() # load the ##warned = set() i = 0 for i, record in enumerate(records, 1): try: field_value = record[field_name] except KeyError: if field_name == pk_name: warning("no primary key %r: %r", field_name, record) continue ##if field_value in by_map: ## if field_value not in warned: ## warning("multiple records for %r", field_value) ## warned.add(field_value) by_map[field_value] = record setattr(self, attr, by_map) indexed.add(field_name) if field_name == pk_name: self.__scan_length = i return by_map if attr == '_IndexedSetMixin__indexed': # .__indexed indexed = self.__indexed = set() return indexed try: supergetattr = super().__getattr__ except AttributeError: return getattr(type(self), attr) else: return supergetattr(attr)
def __init__(self, parent, *a, key=None, fixed_size=None, **kw): for attr in dir(self): K = cutprefix(attr, 'WIDGET_') if K is not attr: v = getattr(self, attr) if v is not None: kw.setdefault(K.lower(), v) if fixed_size is None: fixed_size = (None, None) self.__parent = parent self.fixed_size = fixed_size if self.fixed_width is not None: kw.update(width=self.fixed_width) if self.fixed_height is not None: kw.update(height=self.fixed_height) super().__init__(parent, *a, **kw) if key is None: key = uuid4() self.key = key
def add(self, bookpath): ''' Add a book file via the `calibredb add` command. Return the database id. ''' cp = self.calibredb('add', '--duplicates', bookpath, subp_options=dict(stdin=DEVNULL, capture_output=True, text=True)) # Extract the database id from the "calibredb add" output. dbids = [] for line in cp.stdout.split('\n'): line_sfx = cutprefix(line, 'Added book ids:') if line_sfx is not line: dbids.extend(map(lambda s: int(s.strip()), line_sfx.split(','))) dbid, = dbids # pylint: disable=unbalanced-tuple-unpacking return dbid
def from_class(command_cls): ''' Return a mapping of subcommand names to subcommand specifications for class attributes which commence with `command_cls.SUBCOMMAND_METHOD_PREFIX`, by default `'cmd_'`. ''' prefix = command_cls.SUBCOMMAND_METHOD_PREFIX subcommands_map = {} for attr in dir(command_cls): if attr.startswith(prefix): subcmd = cutprefix(attr, prefix) method = getattr(command_cls, attr) subcommands_map[subcmd] = ( _ClassSubCommand( subcmd, method, usage_mapping=dict(getattr(method, 'USAGE_KEYWORDS', ())) ) if isclass(method) else _MethodSubCommand( subcmd, method, usage_mapping=dict(getattr(command_cls, 'USAGE_KEYWORDS', ())) ) ) return subcommands_map
def unprefixify_key(key, prefix): ''' Return the internal subkey (unprefixed) from the external `key`. ''' assert key.startswith(prefix), \ "key:%r does not start with prefix:%r" % (key, prefix) return cutprefix(key, prefix)
def from_spec(cls, spec): ''' Construct an instance from a connection spec string of the form [`tcp:`|`ssl:`][*user*`@`]*[tcp_host!]server_hostname*[`:`*port*]. The optional prefixes `tcp:` and `ssl:` indicate that the connection should be cleartext or SSL/TLS respectively. The default is SSL/TLS. ''' spec2 = cutprefix(spec, 'tcp:') if spec2 is not spec: spec = spec2 use_ssl = False else: spec = cutprefix(spec, 'ssl:') use_ssl = True # see if what's left after the mode matches a netrc account name account_entry = NetrcEntry.by_account(spec) if account_entry.machine is None: account_entry = None else: # a match, use the machine name as the spec spec = account_entry.machine try: user, hostpart = spec.split('@', 1) except ValueError: # no user specified, use a default hostpart = spec current_user = getpwuid(geteuid()).pw_name if account_entry: if account_entry.login: user = account_entry.login else: # see if the account name has a user part try: user, _ = account_entry.account.split('@', 1) except ValueError: user = current_user else: user = current_user try: host, port = hostpart.split(':') except ValueError: host = hostpart port = 995 if use_ssl else 110 else: port = int(port) try: tcp_host, sni_host = host.split('!', 1) except ValueError: # get the SNI name from the account name if account_entry: tcp_host = host try: _, sni_host = account_entry.account.split('@', 1) except ValueError: sni_host = account_entry.account else: tcp_host, sni_host = host, host conn_spec = cls( user=user, host=tcp_host, sni_host=sni_host, port=port, ssl=use_ssl ) ##print("conn_spec =", conn_spec) return conn_spec
def __init__(self, db_url, serial_sessions=None): ''' Initialise the ORM. If `serial_sessions` is true (default `False`) then allocate a lock to serialise session allocation. This might be chosen with SQL backends which do not support concurrent sessions such as SQLite. In the case of SQLite there's a small inbuilt timeout in an attempt to serialise transactions but it is possible to exceed it easily and recovery is usually infeasible. Instead we use the `serial_sessions` option to obtain a mutex before allocating a session. ''' db_fspath = cutprefix(db_url, 'sqlite:///') if db_fspath is db_url: # unchanged - no leading "sqlite:///" if db_url.startswith(('/', './', '../')) or '://' not in db_url: # turn filesystenm pathnames into SQLite db URLs db_fspath = abspath(db_url) db_url = 'sqlite:///' + db_url else: # no fs path db_fspath = None else: # starts with sqlite:///, we have the db_fspath pass self.db_url = db_url self.db_fspath = db_fspath is_sqlite = db_url.startswith('sqlite://') if serial_sessions is None: # serial SQLite sessions serial_sessions = is_sqlite elif not serial_sessions: if is_sqlite: warning( "serial_sessions specified as %r, but is_sqlite=%s:" " this may cause trouble with multithreaded use", serial_sessions, is_sqlite, ) self.serial_sessions = serial_sessions or is_sqlite self._lockfilepath = None self.Base = declarative_base() self.sqla_state = SQLAState( orm=self, engine=None, sessionmaker=None, session=None ) if serial_sessions: self._serial_sessions_lock = Lock() else: self._engine = None self._sessionmaker_raw = None self.db_url = db_url self.engine_keywords = {} self.engine_keywords = dict( case_sensitive=True, echo=( bool(os.environ.get('DEBUG')) or 'echo' in os.environ.get('SQLTAGS_MODES', '').split(',') ), # 'debug' ) if is_sqlite: # do not pool these connects and disable the Thread check # because we self.engine_keywords.update( poolclass=NullPool, connect_args={'check_same_thread': False} ) self.declare_schema()
def usage_format(self): ''' Return the usage format string from the class. ''' doc = self.method.usage_text(cmd=self.cmd) subusage_format, *_ = cutprefix(doc, 'Usage:').lstrip().split("\n\n", 1) return subusage_format