Merge branch 'encukou-markdown-identifiers'
[zzz-pokedex.git] / pokedex / db / __init__.py
1 # encoding: utf-8
2 import re
3
4 from sqlalchemy import engine_from_config, orm
5
6 from ..defaults import get_default_db_uri
7 from .tables import Language, metadata
8 from .multilang import MultilangSession, MultilangScopedSession
9
10 ENGLISH_ID = 9
11
12
13 def connect(uri=None, session_args={}, engine_args={}, engine_prefix=''):
14 """Connects to the requested URI. Returns a session object.
15
16 With the URI omitted, attempts to connect to a default SQLite database
17 contained within the package directory.
18
19 Calling this function also binds the metadata object to the created engine.
20 """
21
22 # If we didn't get a uri, fall back to the default
23 if uri is None:
24 uri = engine_args.get(engine_prefix + 'url', None)
25 if uri is None:
26 uri = get_default_db_uri()
27
28 ### Do some fixery for MySQL
29 if uri.startswith('mysql:'):
30 # MySQL uses latin1 for connections by default even if the server is
31 # otherwise oozing with utf8; charset fixes this
32 if 'charset' not in uri:
33 uri += '?charset=utf8'
34
35 # Tables should be InnoDB, in the event that we're creating them, and
36 # use UTF-8 goddammit!
37 for table in metadata.tables.values():
38 table.kwargs['mysql_engine'] = 'InnoDB'
39 table.kwargs['mysql_charset'] = 'utf8'
40
41 ### Connect
42 engine_args[engine_prefix + 'url'] = uri
43 engine = engine_from_config(engine_args, prefix=engine_prefix)
44 conn = engine.connect()
45 metadata.bind = engine
46
47 all_session_args = dict(autoflush=True, autocommit=False, bind=engine)
48 all_session_args.update(session_args)
49 sm = orm.sessionmaker(class_=MultilangSession,
50 default_language_id=ENGLISH_ID, **all_session_args)
51 session = MultilangScopedSession(sm)
52
53 return session
54
55 def identifier_from_name(name):
56 """Make a string safe to use as an identifier.
57
58 Valid characters are lowercase alphanumerics and "-". This function may
59 raise ValueError if it can't come up with a suitable identifier.
60
61 This function is useful for scripts which add things with names.
62 """
63 if isinstance(name, str):
64 identifier = name.decode('utf-8')
65 else:
66 identifier = name
67 identifier = identifier.lower()
68 identifier = identifier.replace(u'+', u' plus ')
69 identifier = re.sub(u'[ _–]+', u'-', identifier)
70 identifier = re.sub(u"['./;’(),:]", u'', identifier)
71 identifier = identifier.replace(u'é', u'e')
72 identifier = identifier.replace(u'♀', u'-f')
73 identifier = identifier.replace(u'♂', u'-m')
74 if identifier in (u'???', u'????'):
75 identifier = u'unknown'
76 elif identifier == u'!':
77 identifier = u'exclamation'
78 elif identifier == u'?':
79 identifier = u'question'
80
81 if not identifier.replace(u"-", u"").isalnum():
82 raise ValueError(identifier)
83 return identifier