From 23dc1dbb6720c8f8d421534db744c0b83131a910 Mon Sep 17 00:00:00 2001 From: JT Date: Mon, 24 Feb 2025 23:54:05 +0000 Subject: [PATCH 1/6] py3 compatibility fixes, and removed session.close() from orm middleware to prevent shutting down transactions --- .../management/commands/collectstatic.py | 2 -- baph/core/management/commands/dumpsettings.py | 2 +- baph/core/management/commands/killcache.py | 24 +++++++++---------- baph/core/management/commands/nsincr.py | 16 ++++++------- baph/core/management/commands/tables.py | 2 +- baph/core/management/commands/validate.py | 4 ++-- baph/core/serializers/python.py | 4 ++-- baph/middleware/orm.py | 1 - 8 files changed, 26 insertions(+), 29 deletions(-) diff --git a/baph/contrib/staticfiles/management/commands/collectstatic.py b/baph/contrib/staticfiles/management/commands/collectstatic.py index 3375819..97ca5de 100644 --- a/baph/contrib/staticfiles/management/commands/collectstatic.py +++ b/baph/contrib/staticfiles/management/commands/collectstatic.py @@ -3,8 +3,6 @@ from django.contrib.staticfiles.finders import get_finders from django.contrib.staticfiles.storage import staticfiles_storage -print 'storage:', staticfiles_storage - from django.core.files.storage import FileSystemStorage from django.core.management.color import no_style from django.utils.functional import cached_property diff --git a/baph/core/management/commands/dumpsettings.py b/baph/core/management/commands/dumpsettings.py index 8516054..9fd38b0 100644 --- a/baph/core/management/commands/dumpsettings.py +++ b/baph/core/management/commands/dumpsettings.py @@ -59,4 +59,4 @@ def handle(self, *keys, **options): if pretty: pprint.pprint(output) else: - print output + print(output) diff --git a/baph/core/management/commands/killcache.py b/baph/core/management/commands/killcache.py index 9d01c03..b4b9ab1 100644 --- a/baph/core/management/commands/killcache.py +++ b/baph/core/management/commands/killcache.py @@ -40,11 +40,11 @@ def lookup_model(): if k.startswith('_'): continue if name == 'l': - print '\t%s' % k, v._meta.cache_detail_keys + print('\t%s' % k, v._meta.cache_detail_keys) if name == k.lower(): return v if name != 'l': - print 'Invalid choice: %s' % name + print('Invalid choice: %s' % name) def prompt_for_model_name(): while True: @@ -54,12 +54,12 @@ def prompt_for_model_name(): return None if not cmd: for name in get_cacheable_models(): - print ' %s' % name + print(' %s' % name) continue return cmd def prompt_for_pk(model): - print 'Enter the primary key components:' + print('Enter the primary key components:') pk = [] for col in class_mapper(model).primary_key: v = raw_input(' %s: ' % col.name) @@ -82,7 +82,7 @@ def handle(self, *args, **options): else: pks = None - print '' + print('') while True: if not model_name: model_name = prompt_for_model_name() @@ -90,7 +90,7 @@ def handle(self, *args, **options): # quit break if not model_name in Base._decl_class_registry: - print error_msg('Invalid model name: %s' % model_name) + print(error_msg('Invalid model name: %s' % model_name)) model_name = None continue model = Base._decl_class_registry[model_name] @@ -101,13 +101,13 @@ def handle(self, *args, **options): session = orm.sessionmaker() for pk in pks: - print info_msg('\nLooking up %r with pk=%s' % (model_name, pk)) + print(info_msg('\nLooking up %r with pk=%s' % (model_name, pk))) obj = session.query(model).get(pk) if not obj: - print error_msg(' No %s found with PK %s' % (model_name, pk)) + print(error_msg(' No %s found with PK %s' % (model_name, pk))) continue - print success_msg(' Found object: %r' % obj) + print(success_msg(' Found object: %r' % obj)) caches = defaultdict(lambda: { 'cache_keys': set(), @@ -125,13 +125,13 @@ def handle(self, *args, **options): caches[alias]['version_keys'].add(version_key) for alias, keys in caches.items(): - print info_msg('Processing keys on cache %r' % alias) + print(info_msg('Processing keys on cache %r' % alias)) cache = get_cache(alias) for key in keys['cache_keys']: - print ' Killing cache key: %r' % key + print(' Killing cache key: %r' % key) cache.delete_many(keys['cache_keys']) for key in keys['version_keys']: - print ' Incrementing version key: %r' % key + print(' Incrementing version key: %r' % key) cache.incr(key) model_name = None diff --git a/baph/core/management/commands/nsincr.py b/baph/core/management/commands/nsincr.py index 7db9c42..3d55e7a 100644 --- a/baph/core/management/commands/nsincr.py +++ b/baph/core/management/commands/nsincr.py @@ -15,11 +15,11 @@ def build_options_list(namespaces): return options def print_options(options): - print '\n%s %s %s' % ('id', 'name'.ljust(16), 'attrs') + print('\n%s %s %s' % ('id', 'name'.ljust(16), 'attrs')) for i, (ns, name, attr, type, models) in enumerate(options): names = sorted([model.__name__ for model in models]) - print '%s %s %s' % (i, name.ljust(16), attr) - print ' invalidates: %s' % names + print('%s %s %s' % (i, name.ljust(16), attr)) + print(' invalidates: %s' % names) def get_value_for_attr(attr): msg = 'Enter the value for %r (ENTER to cancel): ' % attr @@ -49,22 +49,22 @@ def get_option(options): # string reference index = name_map[value] else: - print 'Invalid option: %r' % value + print('Invalid option: %r' % value) continue if index >= len(options): - print 'Invalid index: %r' % index + print('Invalid index: %r' % index) continue return options[index] def increment_version_key(cache, key): version = cache.get(key) - print ' current value of %s: %s' % (key, version) + print(' current value of %s: %s' % (key, version)) version = version + 1 if version else 1 cache.set(key, version) version = cache.get(key) - print ' new value of %s: %s' % (key, version) + print(' new value of %s: %s' % (key, version)) class Command(NoArgsCommand): @@ -115,7 +115,7 @@ def handle_noargs(self, **options): try: result = self.main() except KeyboardInterrupt: - print '' + print('') break if result is None: break diff --git a/baph/core/management/commands/tables.py b/baph/core/management/commands/tables.py index 495df41..439fc18 100644 --- a/baph/core/management/commands/tables.py +++ b/baph/core/management/commands/tables.py @@ -13,5 +13,5 @@ def handle(self, *args, **options): tables = [(table.schema or default_schema, table.name) for table in Base.metadata.tables.values()] for table in sorted(tables): - print '.'.join(table) + print('.'.join(table)) diff --git a/baph/core/management/commands/validate.py b/baph/core/management/commands/validate.py index d34b064..4876cce 100644 --- a/baph/core/management/commands/validate.py +++ b/baph/core/management/commands/validate.py @@ -15,9 +15,9 @@ def handle_noargs(self, **options): self.validate(display_num_errors=True) #configure_mappers() - print '\nPost-Validation Tables:' + print('\nPost-Validation Tables:') for table in Base.metadata.tables: - print '\t', table + print('\t', table) """ print '\nPost-Validation Class Registry:' for k,v in sorted(Base._decl_class_registry.items()): diff --git a/baph/core/serializers/python.py b/baph/core/serializers/python.py index eb9d1c0..516e64b 100644 --- a/baph/core/serializers/python.py +++ b/baph/core/serializers/python.py @@ -1,5 +1,5 @@ from django.conf import settings -from django.utils.encoding import smart_unicode, is_protected_type +from django.utils.encoding import smart_text, is_protected_type from sqlalchemy.orm.util import identity_key from baph.core.serializers import base @@ -57,7 +57,7 @@ def Deserializer(object_list, **options): # Handle each field for (field_name, field_value) in d.iteritems(): if isinstance(field_value, bytes): - field_value = smart_unicode(field_value, + field_value = smart_text(field_value, options.get("encoding", settings.DEFAULT_CHARSET), strings_only=True) data[field_name] = field_value diff --git a/baph/middleware/orm.py b/baph/middleware/orm.py index 2e8f727..3926479 100755 --- a/baph/middleware/orm.py +++ b/baph/middleware/orm.py @@ -19,7 +19,6 @@ def process_response(self, request, response): if response.status_code >= 400: session.expunge_all() session.commit() - session.close() return response def process_exception(self, request, exception): From 21e23b9ad897cf4b6c625d40fc928c4139743a3f Mon Sep 17 00:00:00 2001 From: JT Date: Fri, 6 Jun 2025 16:59:41 +0000 Subject: [PATCH 2/6] reduce MAX_KEY_LEN to 32 to prevent exceeding index length 1000 with utf charset --- baph/auth/models/oauth_/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/baph/auth/models/oauth_/__init__.py b/baph/auth/models/oauth_/__init__.py index b39a657..07f4da7 100644 --- a/baph/auth/models/oauth_/__init__.py +++ b/baph/auth/models/oauth_/__init__.py @@ -11,7 +11,7 @@ orm = ORM.get() Base = orm.Base -MAX_KEY_LEN = 255 +MAX_KEY_LEN = 32 MAX_SECRET_LEN = 255 KEY_LEN = 32 SECRET_LEN = 32 From e381ef616b6cb92440eeb2067d7c2dd634f86d0e Mon Sep 17 00:00:00 2001 From: JT Date: Fri, 13 Jun 2025 16:32:24 +0000 Subject: [PATCH 3/6] reduced oauth nonce length to prevent index length errors with utf8mb4 charset in mysql --- baph/auth/models/oauth_/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/baph/auth/models/oauth_/__init__.py b/baph/auth/models/oauth_/__init__.py index 07f4da7..06d06b6 100644 --- a/baph/auth/models/oauth_/__init__.py +++ b/baph/auth/models/oauth_/__init__.py @@ -13,8 +13,7 @@ MAX_KEY_LEN = 32 MAX_SECRET_LEN = 255 -KEY_LEN = 32 -SECRET_LEN = 32 +MAX_NONCE_LEN = 33 UNIQUE_KEY = getattr(settings, 'BAPH_UNIQUE_OAUTH_KEYS', True) @@ -43,4 +42,4 @@ class OAuthNonce(Base): timestamp = Column(DateTime, nullable=False, index=True) token_key = Column(String(32)) consumer_key = Column(String(MAX_KEY_LEN), nullable=False) - key = Column(String(255), nullable=False) + key = Column(String(MAX_NONCE_LEN), nullable=False) From f8d1f55a9de70583ea9c62f6cf90026470ad8005 Mon Sep 17 00:00:00 2001 From: JT Date: Fri, 20 Jun 2025 21:25:44 +0000 Subject: [PATCH 4/6] added ListVarchar and DictVarchar to db.types, to allow usage of varchar fields instead of text --- baph/db/types.py | 18 ++++++++++++++++-- baph/forms/forms.py | 4 +++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/baph/db/types.py b/baph/db/types.py index e797a27..5d8288b 100644 --- a/baph/db/types.py +++ b/baph/db/types.py @@ -25,6 +25,7 @@ class Email(types.TypeDecorator): impl = types.Unicode + class UUID(types.TypeDecorator): '''Generic UUID column type for SQLAlchemy. Includes native support for PostgreSQL and a MySQL-specific implementation, in addition to the @@ -75,13 +76,13 @@ def process_result_value(self, value, dialect=None): def is_mutable(self): return False + class Json(types.TypeDecorator): impl = types.Unicode def process_bind_param(self, value, dialect): if value is None: return None - #return json.dumps(value) return json.dumps(value) def process_result_value(self, value, dialect): @@ -89,17 +90,24 @@ def process_result_value(self, value, dialect): return None return json.loads(value) + JsonType = Json + class JsonText(JsonType): impl = types.UnicodeText -class List(JsonText): +class List(JsonText): @property def python_type(self): return list + +class ListVarchar(List): + impl = types.Unicode + + # http://docs.sqlalchemy.org/en/latest/orm/extensions/mutable.html class MutableDict(Mutable, dict): @@ -128,6 +136,7 @@ def __delitem__(self, key): dict.__delitem__(self, key) self.changed() + class MutableList(Mutable, list): @classmethod def coerce(cls, key, value): @@ -181,6 +190,11 @@ class Dict(JsonText): def python_type(self): return dict + +class DictVarchar(Dict): + impl = types.Unicode + + class TZAwareDateTime(types.TypeDecorator): impl = types.DateTime diff --git a/baph/forms/forms.py b/baph/forms/forms.py index ea661f3..d5dd723 100644 --- a/baph/forms/forms.py +++ b/baph/forms/forms.py @@ -31,11 +31,13 @@ Boolean: forms.BooleanField, types.Json: fields.JsonField, types.List: fields.ListField, + types.ListVarchar: fields.ListField, types.Dict: fields.DictField, + types.DictVarchar: fields.DictField, types.Email: forms.EmailField, 'collection': fields.MultiObjectField, 'object': fields.ObjectField, - } +} ALL_FIELDS = '__all__' orm = ORM.get() From 0749a9a11044e6d787dd35d6129d172d184df066 Mon Sep 17 00:00:00 2001 From: JT Date: Fri, 1 Aug 2025 16:25:15 +0000 Subject: [PATCH 5/6] fix for extra spaces in memcached response --- baph/core/cache/backends/memcached.py | 1 + 1 file changed, 1 insertion(+) diff --git a/baph/core/cache/backends/memcached.py b/baph/core/cache/backends/memcached.py index b1b76ed..109a76d 100644 --- a/baph/core/cache/backends/memcached.py +++ b/baph/core/cache/backends/memcached.py @@ -97,6 +97,7 @@ def send_command(self, cmd, row_len=0, expect=None): while line: # readline splits on '\r\n', we still need to split on '\n' item, sep, line = line.partition('\n') + item = item.strip() if item == 'END': return lines else: From 38c1c211b0a0376ae08e8bd5af8ed9c27566240c Mon Sep 17 00:00:00 2001 From: JT Date: Fri, 1 Aug 2025 16:28:21 +0000 Subject: [PATCH 6/6] fix for parse errors caused by trailing spaces in memcached response --- baph/core/cache/backends/memcached.py | 1 + 1 file changed, 1 insertion(+) diff --git a/baph/core/cache/backends/memcached.py b/baph/core/cache/backends/memcached.py index b1b76ed..109a76d 100644 --- a/baph/core/cache/backends/memcached.py +++ b/baph/core/cache/backends/memcached.py @@ -97,6 +97,7 @@ def send_command(self, cmd, row_len=0, expect=None): while line: # readline splits on '\r\n', we still need to split on '\n' item, sep, line = line.partition('\n') + item = item.strip() if item == 'END': return lines else: