Mercurial > libervia-backend
comparison sat_frontends/quick_frontend/quick_contact_list.py @ 3028:ab2696e34d29
Python 3 port:
/!\ this is a huge commit
/!\ starting from this commit, SàT is needs Python 3.6+
/!\ SàT maybe be instable or some feature may not work anymore, this will improve with time
This patch port backend, bridge and frontends to Python 3.
Roughly this has been done this way:
- 2to3 tools has been applied (with python 3.7)
- all references to python2 have been replaced with python3 (notably shebangs)
- fixed files not handled by 2to3 (notably the shell script)
- several manual fixes
- fixed issues reported by Python 3 that where not handled in Python 2
- replaced "async" with "async_" when needed (it's a reserved word from Python 3.7)
- replaced zope's "implements" with @implementer decorator
- temporary hack to handle data pickled in database, as str or bytes may be returned,
to be checked later
- fixed hash comparison for password
- removed some code which is not needed anymore with Python 3
- deactivated some code which needs to be checked (notably certificate validation)
- tested with jp, fixed reported issues until some basic commands worked
- ported Primitivus (after porting dependencies like urwid satext)
- more manual fixes
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 13 Aug 2019 19:08:41 +0200 |
parents | 8990ed9aad31 |
children | f8e3789912d0 |
comparison
equal
deleted
inserted
replaced
3027:ff5bcb12ae60 | 3028:ab2696e34d29 |
---|---|
30 | 30 |
31 log = getLogger(__name__) | 31 log = getLogger(__name__) |
32 | 32 |
33 try: | 33 try: |
34 # FIXME: to be removed when an acceptable solution is here | 34 # FIXME: to be removed when an acceptable solution is here |
35 unicode("") # XXX: unicode doesn't exist in pyjamas | 35 str("") # XXX: unicode doesn't exist in pyjamas |
36 except (TypeError, AttributeError): # Error raised is not the same depending on | 36 except (TypeError, AttributeError): # Error raised is not the same depending on |
37 # pyjsbuild options | 37 # pyjsbuild options |
38 # XXX: pyjamas' max doesn't support key argument, so we implement it ourself | 38 # XXX: pyjamas' max doesn't support key argument, so we implement it ourself |
39 pyjamas_max = max | 39 pyjamas_max = max |
40 | 40 |
44 return pyjamas_max(iter_cpy) | 44 return pyjamas_max(iter_cpy) |
45 | 45 |
46 # next doesn't exist in pyjamas | 46 # next doesn't exist in pyjamas |
47 def next(iterable, *args): | 47 def next(iterable, *args): |
48 try: | 48 try: |
49 return iterable.next() | 49 return iterable.__next__() |
50 except StopIteration as e: | 50 except StopIteration as e: |
51 if args: | 51 if args: |
52 return args[0] | 52 return args[0] |
53 raise e | 53 raise e |
54 | 54 |
182 """Return a dictionary binding the entities bare JIDs to their roster groups | 182 """Return a dictionary binding the entities bare JIDs to their roster groups |
183 | 183 |
184 @return (dict[jid.JID, set(unicode)]) | 184 @return (dict[jid.JID, set(unicode)]) |
185 """ | 185 """ |
186 result = {} | 186 result = {} |
187 for group, data in self._groups.iteritems(): | 187 for group, data in self._groups.items(): |
188 for entity in data["jids"]: | 188 for entity in data["jids"]: |
189 result.setdefault(entity, set()).add(group) | 189 result.setdefault(entity, set()).add(group) |
190 return result | 190 return result |
191 | 191 |
192 @property | 192 @property |
201 def all_iter(self): | 201 def all_iter(self): |
202 """return all know entities in cache as an iterator of tuples | 202 """return all know entities in cache as an iterator of tuples |
203 | 203 |
204 entities are not sorted | 204 entities are not sorted |
205 """ | 205 """ |
206 return self._cache.iteritems() | 206 return iter(self._cache.items()) |
207 | 207 |
208 @property | 208 @property |
209 def items(self): | 209 def items(self): |
210 """Return item representation for all visible entities in cache | 210 """Return item representation for all visible entities in cache |
211 | 211 |
212 entities are not sorted | 212 entities are not sorted |
213 key: bare jid, value: data | 213 key: bare jid, value: data |
214 """ | 214 """ |
215 return { | 215 return { |
216 jid_: cache | 216 jid_: cache |
217 for jid_, cache in self._cache.iteritems() | 217 for jid_, cache in self._cache.items() |
218 if self.entityVisible(jid_) | 218 if self.entityVisible(jid_) |
219 } | 219 } |
220 | 220 |
221 def getItem(self, entity): | 221 def getItem(self, entity): |
222 """Return item representation of requested entity | 222 """Return item representation of requested entity |
338 @param entity(jid.JID): must be a bare jid | 338 @param entity(jid.JID): must be a bare jid |
339 @return (jid.JID): bare jid + main resource | 339 @return (jid.JID): bare jid + main resource |
340 @raise ValueError: the entity is not bare | 340 @raise ValueError: the entity is not bare |
341 """ | 341 """ |
342 if entity.resource: | 342 if entity.resource: |
343 raise ValueError(u"getFullJid must be used with a bare jid") | 343 raise ValueError("getFullJid must be used with a bare jid") |
344 main_resource = self.getCache(entity, C.CONTACT_MAIN_RESOURCE) | 344 main_resource = self.getCache(entity, C.CONTACT_MAIN_RESOURCE) |
345 return jid.JID(u"{}/{}".format(entity, main_resource)) | 345 return jid.JID("{}/{}".format(entity, main_resource)) |
346 | 346 |
347 def setGroupData(self, group, name, value): | 347 def setGroupData(self, group, name, value): |
348 """Register a data for a group | 348 """Register a data for a group |
349 | 349 |
350 @param group: a valid (existing) group name | 350 @param group: a valid (existing) group name |
506 cache_attr = ( | 506 cache_attr = ( |
507 cache[C.CONTACT_RESOURCES].setdefault(entity.resource, {}) | 507 cache[C.CONTACT_RESOURCES].setdefault(entity.resource, {}) |
508 if entity.resource | 508 if entity.resource |
509 else cache | 509 else cache |
510 ) | 510 ) |
511 for attribute, value in attributes.iteritems(): | 511 for attribute, value in attributes.items(): |
512 if value is None: | 512 if value is None: |
513 # XXX: pyjamas hack: we need to use pop instead of del | 513 # XXX: pyjamas hack: we need to use pop instead of del |
514 try: | 514 try: |
515 cache_attr[attribute].pop(value) | 515 cache_attr[attribute].pop(value) |
516 except KeyError: | 516 except KeyError: |
594 entity_bare = entity.bare | 594 entity_bare = entity.bare |
595 was_visible = self.entityVisible(entity_bare) | 595 was_visible = self.entityVisible(entity_bare) |
596 try: | 596 try: |
597 groups = self._cache[entity_bare].get(C.CONTACT_GROUPS, set()) | 597 groups = self._cache[entity_bare].get(C.CONTACT_GROUPS, set()) |
598 except KeyError: | 598 except KeyError: |
599 log.error(_(u"Trying to delete an unknow entity [{}]").format(entity)) | 599 log.error(_("Trying to delete an unknow entity [{}]").format(entity)) |
600 try: | 600 try: |
601 self._roster.remove(entity_bare) | 601 self._roster.remove(entity_bare) |
602 except KeyError: | 602 except KeyError: |
603 pass | 603 pass |
604 del self._cache[entity_bare] | 604 del self._cache[entity_bare] |
637 else: | 637 else: |
638 try: | 638 try: |
639 del cache[C.CONTACT_RESOURCES][entity.resource] | 639 del cache[C.CONTACT_RESOURCES][entity.resource] |
640 except KeyError: | 640 except KeyError: |
641 log.error( | 641 log.error( |
642 u"Presence unavailable received " | 642 "Presence unavailable received " |
643 u"for an unknown resource [{}]".format(entity) | 643 "for an unknown resource [{}]".format(entity) |
644 ) | 644 ) |
645 if not cache[C.CONTACT_RESOURCES]: | 645 if not cache[C.CONTACT_RESOURCES]: |
646 cache[C.CONTACT_MAIN_RESOURCE] = None | 646 cache[C.CONTACT_MAIN_RESOURCE] = None |
647 else: | 647 else: |
648 if not entity.resource: | 648 if not entity.resource: |
649 log.warning( | 649 log.warning( |
650 _( | 650 _( |
651 u"received presence from entity " | 651 "received presence from entity " |
652 u"without resource: {}".format(entity) | 652 "without resource: {}".format(entity) |
653 ) | 653 ) |
654 ) | 654 ) |
655 resources_data = cache[C.CONTACT_RESOURCES] | 655 resources_data = cache[C.CONTACT_RESOURCES] |
656 resource_data = resources_data.setdefault(entity.resource, {}) | 656 resource_data = resources_data.setdefault(entity.resource, {}) |
657 resource_data[C.PRESENCE_SHOW] = show | 657 resource_data[C.PRESENCE_SHOW] = show |
701 @param entity(jid.JID): entity to unselect | 701 @param entity(jid.JID): entity to unselect |
702 """ | 702 """ |
703 try: | 703 try: |
704 cache = self._cache[entity.bare] | 704 cache = self._cache[entity.bare] |
705 except: | 705 except: |
706 log.error(u"Try to unselect an entity not in cache") | 706 log.error("Try to unselect an entity not in cache") |
707 else: | 707 else: |
708 try: | 708 try: |
709 cache[C.CONTACT_SELECTED].remove(entity.resource) | 709 cache[C.CONTACT_SELECTED].remove(entity.resource) |
710 except KeyError: | 710 except KeyError: |
711 log.error(u"Try to unselect a not selected entity") | 711 log.error("Try to unselect a not selected entity") |
712 else: | 712 else: |
713 self._selected.remove(entity) | 713 self._selected.remove(entity) |
714 self.update([entity], C.UPDATE_SELECTION) | 714 self.update([entity], C.UPDATE_SELECTION) |
715 | 715 |
716 def select(self, entity): | 716 def select(self, entity): |
719 @param entity(jid.JID, None): entity to select (resource is significant) | 719 @param entity(jid.JID, None): entity to select (resource is significant) |
720 None to unselect all entities | 720 None to unselect all entities |
721 """ | 721 """ |
722 if entity is None: | 722 if entity is None: |
723 self._selected.clear() | 723 self._selected.clear() |
724 for cache in self._cache.itervalues(): | 724 for cache in self._cache.values(): |
725 cache[C.CONTACT_SELECTED].clear() | 725 cache[C.CONTACT_SELECTED].clear() |
726 self.update(type_=C.UPDATE_SELECTION, profile=self.profile) | 726 self.update(type_=C.UPDATE_SELECTION, profile=self.profile) |
727 else: | 727 else: |
728 log.debug(u"select %s" % entity) | 728 log.debug("select %s" % entity) |
729 try: | 729 try: |
730 cache = self._cache[entity.bare] | 730 cache = self._cache[entity.bare] |
731 except: | 731 except: |
732 log.error(u"Try to select an entity not in cache") | 732 log.error("Try to select an entity not in cache") |
733 else: | 733 else: |
734 cache[C.CONTACT_SELECTED].add(entity.resource) | 734 cache[C.CONTACT_SELECTED].add(entity.resource) |
735 self._selected.add(entity) | 735 self._selected.add(entity) |
736 self.update([entity], C.UPDATE_SELECTION, profile=self.profile) | 736 self.update([entity], C.UPDATE_SELECTION, profile=self.profile) |
737 | 737 |
775 super(QuickContactListHandler, self).__init__() | 775 super(QuickContactListHandler, self).__init__() |
776 self.host = host | 776 self.host = host |
777 global handler | 777 global handler |
778 if handler is not None: | 778 if handler is not None: |
779 raise exceptions.InternalError( | 779 raise exceptions.InternalError( |
780 u"QuickContactListHandler must be instanciated only once" | 780 "QuickContactListHandler must be instanciated only once" |
781 ) | 781 ) |
782 handler = self | 782 handler = self |
783 self._clist = {} # key: profile, value: ProfileContactList | 783 self._clist = {} # key: profile, value: ProfileContactList |
784 self._widgets = set() | 784 self._widgets = set() |
785 self._update_locked = False # se to True to ignore updates | 785 self._update_locked = False # se to True to ignore updates |
792 """Check if entity is in contact list | 792 """Check if entity is in contact list |
793 | 793 |
794 @param entity (jid.JID): jid of the entity (resource is not ignored, | 794 @param entity (jid.JID): jid of the entity (resource is not ignored, |
795 use bare jid if needed) | 795 use bare jid if needed) |
796 """ | 796 """ |
797 for contact_list in self._clist.itervalues(): | 797 for contact_list in self._clist.values(): |
798 if entity in contact_list: | 798 if entity in contact_list: |
799 return True | 799 return True |
800 return False | 800 return False |
801 | 801 |
802 @property | 802 @property |
804 """Return all the bare JIDs of the roster entities. | 804 """Return all the bare JIDs of the roster entities. |
805 | 805 |
806 @return (set[jid.JID]) | 806 @return (set[jid.JID]) |
807 """ | 807 """ |
808 entities = set() | 808 entities = set() |
809 for contact_list in self._clist.itervalues(): | 809 for contact_list in self._clist.values(): |
810 entities.update(contact_list.roster) | 810 entities.update(contact_list.roster) |
811 return entities | 811 return entities |
812 | 812 |
813 @property | 813 @property |
814 def roster_connected(self): | 814 def roster_connected(self): |
815 """Return all the bare JIDs of the roster entities that are connected. | 815 """Return all the bare JIDs of the roster entities that are connected. |
816 | 816 |
817 @return (set[jid.JID]) | 817 @return (set[jid.JID]) |
818 """ | 818 """ |
819 entities = set() | 819 entities = set() |
820 for contact_list in self._clist.itervalues(): | 820 for contact_list in self._clist.values(): |
821 entities.update(contact_list.roster_connected) | 821 entities.update(contact_list.roster_connected) |
822 return entities | 822 return entities |
823 | 823 |
824 @property | 824 @property |
825 def roster_entities_by_group(self): | 825 def roster_entities_by_group(self): |
827 JIDs. This also includes the empty group (None key). | 827 JIDs. This also includes the empty group (None key). |
828 | 828 |
829 @return (dict[unicode,set(jid.JID)]) | 829 @return (dict[unicode,set(jid.JID)]) |
830 """ | 830 """ |
831 groups = {} | 831 groups = {} |
832 for contact_list in self._clist.itervalues(): | 832 for contact_list in self._clist.values(): |
833 groups.update(contact_list.roster_entities_by_group) | 833 groups.update(contact_list.roster_entities_by_group) |
834 return groups | 834 return groups |
835 | 835 |
836 @property | 836 @property |
837 def roster_groups_by_entities(self): | 837 def roster_groups_by_entities(self): |
839 groups. | 839 groups. |
840 | 840 |
841 @return (dict[jid.JID, set(unicode)]) | 841 @return (dict[jid.JID, set(unicode)]) |
842 """ | 842 """ |
843 entities = {} | 843 entities = {} |
844 for contact_list in self._clist.itervalues(): | 844 for contact_list in self._clist.values(): |
845 entities.update(contact_list.roster_groups_by_entities) | 845 entities.update(contact_list.roster_groups_by_entities) |
846 return entities | 846 return entities |
847 | 847 |
848 @property | 848 @property |
849 def selected(self): | 849 def selected(self): |
850 """Return contacts currently selected | 850 """Return contacts currently selected |
851 | 851 |
852 @return (set): set of selected entities | 852 @return (set): set of selected entities |
853 """ | 853 """ |
854 entities = set() | 854 entities = set() |
855 for contact_list in self._clist.itervalues(): | 855 for contact_list in self._clist.values(): |
856 entities.update(contact_list.selected) | 856 entities.update(contact_list.selected) |
857 return entities | 857 return entities |
858 | 858 |
859 @property | 859 @property |
860 def all_iter(self): | 860 def all_iter(self): |
861 """Return item representation for all entities in cache | 861 """Return item representation for all entities in cache |
862 | 862 |
863 items are unordered | 863 items are unordered |
864 """ | 864 """ |
865 for profile, contact_list in self._clist.iteritems(): | 865 for profile, contact_list in self._clist.items(): |
866 for bare_jid, cache in contact_list.all_iter: | 866 for bare_jid, cache in contact_list.all_iter: |
867 data = cache.copy() | 867 data = cache.copy() |
868 data[C.CONTACT_PROFILE] = profile | 868 data[C.CONTACT_PROFILE] = profile |
869 yield bare_jid, data | 869 yield bare_jid, data |
870 | 870 |
874 | 874 |
875 items are unordered | 875 items are unordered |
876 key: bare jid, value: data | 876 key: bare jid, value: data |
877 """ | 877 """ |
878 items = {} | 878 items = {} |
879 for profile, contact_list in self._clist.iteritems(): | 879 for profile, contact_list in self._clist.items(): |
880 for bare_jid, cache in contact_list.items.iteritems(): | 880 for bare_jid, cache in contact_list.items.items(): |
881 data = cache.copy() | 881 data = cache.copy() |
882 items[bare_jid] = data | 882 items[bare_jid] = data |
883 data[C.CONTACT_PROFILE] = profile | 883 data[C.CONTACT_PROFILE] = profile |
884 return items | 884 return items |
885 | 885 |
951 (e.g. C.CONTACT_SPECIAL_GROUP) | 951 (e.g. C.CONTACT_SPECIAL_GROUP) |
952 None to return all special extras. | 952 None to return all special extras. |
953 @return (set[jid.JID]) | 953 @return (set[jid.JID]) |
954 """ | 954 """ |
955 entities = set() | 955 entities = set() |
956 for contact_list in self._clist.itervalues(): | 956 for contact_list in self._clist.values(): |
957 entities.update(contact_list.getSpecialExtras(special_type)) | 957 entities.update(contact_list.getSpecialExtras(special_type)) |
958 return entities | 958 return entities |
959 | 959 |
960 def _contactsFilled(self, profile): | 960 def _contactsFilled(self, profile): |
961 self._to_fill.remove(profile) | 961 self._to_fill.remove(profile) |
982 | 982 |
983 if profile is not None: | 983 if profile is not None: |
984 assert profile in self._clist | 984 assert profile in self._clist |
985 to_fill.add(profile) | 985 to_fill.add(profile) |
986 else: | 986 else: |
987 to_fill.update(self._clist.keys()) | 987 to_fill.update(list(self._clist.keys())) |
988 | 988 |
989 remaining = to_fill.difference(filled) | 989 remaining = to_fill.difference(filled) |
990 if remaining != to_fill: | 990 if remaining != to_fill: |
991 log.debug( | 991 log.debug( |
992 u"Not re-filling already filled contact list(s) for {}".format( | 992 "Not re-filling already filled contact list(s) for {}".format( |
993 u", ".join(to_fill.intersection(filled)) | 993 ", ".join(to_fill.intersection(filled)) |
994 ) | 994 ) |
995 ) | 995 ) |
996 for profile in remaining: | 996 for profile in remaining: |
997 self._clist[profile]._fill() | 997 self._clist[profile]._fill() |
998 | 998 |
999 def clearContacts(self, keep_cache=False): | 999 def clearContacts(self, keep_cache=False): |
1000 """Clear all the contact list | 1000 """Clear all the contact list |
1001 | 1001 |
1002 @param keep_cache: if True, don't reset the cache | 1002 @param keep_cache: if True, don't reset the cache |
1003 """ | 1003 """ |
1004 for contact_list in self._clist.itervalues(): | 1004 for contact_list in self._clist.values(): |
1005 contact_list.clearContacts(keep_cache) | 1005 contact_list.clearContacts(keep_cache) |
1006 # we need a full update | 1006 # we need a full update |
1007 self.update() | 1007 self.update() |
1008 | 1008 |
1009 def select(self, entity): | 1009 def select(self, entity): |
1010 for contact_list in self._clist.itervalues(): | 1010 for contact_list in self._clist.values(): |
1011 contact_list.select(entity) | 1011 contact_list.select(entity) |
1012 | 1012 |
1013 def unselect(self, entity): | 1013 def unselect(self, entity): |
1014 for contact_list in self._clist.itervalues(): | 1014 for contact_list in self._clist.values(): |
1015 contact_list.select(entity) | 1015 contact_list.select(entity) |
1016 | 1016 |
1017 def lockUpdate(self, locked=True, do_update=True): | 1017 def lockUpdate(self, locked=True, do_update=True): |
1018 """Forbid contact list updates | 1018 """Forbid contact list updates |
1019 | 1019 |
1023 @param do_update(bool): if True, a full update is done after unlocking | 1023 @param do_update(bool): if True, a full update is done after unlocking |
1024 if set to False, widget state can be inconsistent, be sure to know | 1024 if set to False, widget state can be inconsistent, be sure to know |
1025 what youa re doing! | 1025 what youa re doing! |
1026 """ | 1026 """ |
1027 log.debug( | 1027 log.debug( |
1028 u"Contact lists updates are now {}".format( | 1028 "Contact lists updates are now {}".format( |
1029 u"LOCKED" if locked else u"UNLOCKED" | 1029 "LOCKED" if locked else "UNLOCKED" |
1030 ) | 1030 ) |
1031 ) | 1031 ) |
1032 self._update_locked = locked | 1032 self._update_locked = locked |
1033 if not locked and do_update: | 1033 if not locked and do_update: |
1034 self.update() | 1034 self.update() |