···4445 - uses: cachix/install-nix-action@526118121621777ccd86f79b04685a9319637641 # v314647+ - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v1648+ with:49+ # This cache is for the nixpkgs repo checks and should not be trusted or used elsewhere.50+ name: nixpkgs-ci51+ authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"52+53 - name: Build shell54 run: nix-build untrusted/ci -A shell
+6
.github/workflows/lib-tests.yml
···32 with:33 extra_nix_config: sandbox = true3400000035 - name: Building Nixpkgs lib-tests36 run: |37 nix-build untrusted/ci -A lib-tests
···32 with:33 extra_nix_config: sandbox = true3435+ - uses: cachix/cachix-action@0fc020193b5a1fa3ac4575aa3a7d3aa6a35435ad # v1636+ with:37+ # This cache is for the nixpkgs repo checks and should not be trusted or used elsewhere.38+ name: nixpkgs-ci39+ authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"40+41 - name: Building Nixpkgs lib-tests42 run: |43 nix-build untrusted/ci -A lib-tests
···28 - Applications linked against different Mesa versions than installed on the system should now work correctly going forward (however, applications against older Mesa, e.g. from Nixpkgs releases before 25.05, remain broken)29 - Packages that used to depend on Mesa for libgbm or libdri should use `libgbm` or `dri-pkgconfig-stub` as inputs, respectively30000031- OpenSSH has been updated from 9.9p2 to 10.0p2, dropping support for DSA keys and adding a new `ssh-auth` binary to handle user authentication in a different address space from unauthenticated sessions. See the [full changelog](https://www.openwall.com/lists/oss-security/2025/04/09/1) for more details.3233- Emacs has been updated to 30.1.
···28 - Applications linked against different Mesa versions than installed on the system should now work correctly going forward (however, applications against older Mesa, e.g. from Nixpkgs releases before 25.05, remain broken)29 - Packages that used to depend on Mesa for libgbm or libdri should use `libgbm` or `dri-pkgconfig-stub` as inputs, respectively3031+- GNU Taler has been updated to version 1.0.32+ This marks a significant milestone as the GNU Taler payment system is now available in Swiss Francs for individuals and businesses in Switzerland.33+ For more details, see the [upstream release notes](https://www.taler.net/en/news/2025-01.html).34+35- OpenSSH has been updated from 9.9p2 to 10.0p2, dropping support for DSA keys and adding a new `ssh-auth` binary to handle user authentication in a different address space from unauthenticated sessions. See the [full changelog](https://www.openwall.com/lists/oss-security/2025/04/09/1) for more details.3637- Emacs has been updated to 30.1.
···25 "secmod-eddsa"26 "secmod-rsa"27 ];0028in2930{···46 options = {47 # TODO: do we want this to be a sub-attribute or only define the exchange set of options here48 exchange = {49- AML_THRESHOLD = lib.mkOption {00000050 type = lib.types.str;51- default = "${cfgTaler.settings.taler.CURRENCY}:1000000";52- defaultText = "1000000 in {option}`CURRENCY`";53- description = "Monthly transaction volume until an account is considered suspicious and flagged for AML review.";0054 };55 DB = lib.mkOption {56 type = lib.types.enum [ "postgres" ];···141 after = [ "taler-exchange-httpd.service" ];142 };143144- # Taken from https://docs.taler.net/taler-exchange-manual.html#exchange-database-setup145- # TODO: Why does aggregator need DELETE?146- systemd.services."taler-${talerComponent}-dbinit".script =147- let148- deletePerm = name: lib.optionalString (name == "aggregator") ",DELETE";149- dbScript = pkgs.writers.writeText "taler-exchange-db-permissions.sql" (150- lib.pipe servicesDB [151- (map (name: ''152- GRANT SELECT,INSERT,UPDATE${deletePerm name} ON ALL TABLES IN SCHEMA exchange TO "taler-exchange-${name}";153- GRANT USAGE ON SCHEMA exchange TO "taler-exchange-${name}";154- ''))155- lib.concatStrings156- ]157- );158- in159- ''160- ${lib.getExe' cfg.package "taler-exchange-dbinit"}161- psql -U taler-exchange-httpd -f ${dbScript}162- '';163 };164}
···25 "secmod-eddsa"26 "secmod-rsa"27 ];28+29+ configFile = config.environment.etc."taler/taler.conf".source;30in3132{···44 options = {45 # TODO: do we want this to be a sub-attribute or only define the exchange set of options here46 exchange = {47+ CURRENCY = lib.mkOption {48+ type = lib.types.nonEmptyStr;49+ description = ''50+ The currency which the exchange will operate with. This cannot be changed later.51+ '';52+ };53+ CURRENCY_ROUND_UNIT = lib.mkOption {54 type = lib.types.str;55+ default = "${cfg.settings.exchange.CURRENCY}:0.01";56+ defaultText = "0.01 in {option}`CURRENCY`";57+ description = ''58+ Smallest amount in this currency that can be transferred using the underlying RTGS. For example: "EUR:0.01" or "JPY:1"59+ '';60 };61 DB = lib.mkOption {62 type = lib.types.enum [ "postgres" ];···131 after = [ "taler-exchange-httpd.service" ];132 };133134+ systemd.services."taler-${talerComponent}-dbinit".script = ''135+ ${lib.getExe' cfg.package "taler-exchange-dbinit"} -c ${configFile}136+ '';0000000000000000137 };138}
+6-17
nixos/modules/services/finance/taler/merchant.nix
···17 "webhook"18 "wirewatch"19 "depositcheck"20- "exchange"21 ];0022in23{24 imports = [···90 path = [ cfg.package ];91 };9293- systemd.services."taler-${talerComponent}-dbinit".script =94- let95- # NOTE: not documented, but is necessary96- dbScript = pkgs.writers.writeText "taler-merchant-db-permissions.sql" (97- lib.concatStrings (98- map (name: ''99- GRANT SELECT,INSERT,UPDATE,DELETE ON ALL TABLES IN SCHEMA merchant TO "taler-merchant-${name}";100- GRANT USAGE ON SCHEMA merchant TO "taler-merchant-${name}";101- '') servicesDB102- )103- );104- in105- ''106- ${lib.getExe' cfg.package "taler-merchant-dbinit"}107- psql -U taler-${talerComponent}-httpd -f ${dbScript}108- '';109 };110}
···21 postInstall = ''22 chmod -R u+w $out/share23 # Only include the files needed for runtime in the derivation24- mv $out/share/php/${finalAttrs.pname}/{migrations,public,src,config,bin,templates,tests,translations,vendor,symfony.lock,composer.json,composer.lock} $out25 # Save the upstream .env file for reference, but rename it so it is not loaded26- mv $out/share/php/${finalAttrs.pname}/.env $out/env-upstream27 rm -rf "$out/share"28 '';29
···21 postInstall = ''22 chmod -R u+w $out/share23 # Only include the files needed for runtime in the derivation24+ mv $out/share/php/davis/{migrations,public,src,config,bin,templates,tests,translations,vendor,symfony.lock,composer.json,composer.lock} $out25 # Save the upstream .env file for reference, but rename it so it is not loaded26+ mv $out/share/php/davis/.env $out/env-upstream27 rm -rf "$out/share"28 '';29
···49 # The package expect to find an `example-robot-data/robots` folder somewhere50 # either in install prefix or in the sources51 # where it can find the meshes for unit tests52- preCheck = "ln -s source ../../${finalAttrs.pname}";53 pythonImportsCheck = [ "example_robot_data" ];5455 meta = with lib; {
···49 # The package expect to find an `example-robot-data/robots` folder somewhere50 # either in install prefix or in the sources51 # where it can find the meshes for unit tests52+ preCheck = "ln -s source ../../example-robot-data";53 pythonImportsCheck = [ "example_robot_data" ];5455 meta = with lib; {
···19 runHook preInstall2021 # https://gitlab.archlinux.org/archlinux/packaging/packages/fcitx5-material-color/-/blob/main/PKGBUILD?ref_type=heads#L1622- install -Dm644 arrow.png radio.png -t $out/share/${finalAttrs.pname}/23 for _variant in black blue brown deepPurple indigo orange pink red sakuraPink teal; do24 _variant_name=Material-Color-$_variant25 install -dm755 $_variant_name $out/share/fcitx5/themes/$_variant_name
···19 runHook preInstall2021 # https://gitlab.archlinux.org/archlinux/packaging/packages/fcitx5-material-color/-/blob/main/PKGBUILD?ref_type=heads#L1622+ install -Dm644 arrow.png radio.png -t $out/share/fcitx5-material-color/23 for _variant in black blue brown deepPurple indigo orange pink red sakuraPink teal; do24 _variant_name=Material-Color-$_variant25 install -dm755 $_variant_name $out/share/fcitx5/themes/$_variant_name
+1-1
pkgs/by-name/fi/figma-linux/package.nix
···8283 postFixup = ''84 substituteInPlace $out/share/applications/figma-linux.desktop \85- --replace "Exec=/opt/figma-linux/figma-linux" "Exec=$out/bin/${finalAttrs.pname}"86 '';8788 meta = with lib; {
···8283 postFixup = ''84 substituteInPlace $out/share/applications/figma-linux.desktop \85+ --replace "Exec=/opt/figma-linux/figma-linux" "Exec=$out/bin/figma-linux"86 '';8788 meta = with lib; {
···1112stdenvNoCC.mkDerivation (finalAttrs: {13 pname = "markdownlint-cli2";14- version = "0.17.2";1516 # upstream is not interested in including package-lock.json in the source17 # https://github.com/DavidAnson/markdownlint-cli2/issues/198#issuecomment-1690529976···19 # so use the tarball from the archlinux mirror20 src = fetchurl {21 url = "https://us.mirrors.cicku.me/archlinux/extra/os/x86_64/markdownlint-cli2-${finalAttrs.version}-1-any.pkg.tar.zst";22- hash = "sha256-TuiLFP/XItJh5VQWdwCvXRQCVzmqst4Sxna0eLobEQ4=";23 };2425 nativeBuildInputs = [
···1112stdenvNoCC.mkDerivation (finalAttrs: {13 pname = "markdownlint-cli2";14+ version = "0.18.1";1516 # upstream is not interested in including package-lock.json in the source17 # https://github.com/DavidAnson/markdownlint-cli2/issues/198#issuecomment-1690529976···19 # so use the tarball from the archlinux mirror20 src = fetchurl {21 url = "https://us.mirrors.cicku.me/archlinux/extra/os/x86_64/markdownlint-cli2-${finalAttrs.version}-1-any.pkg.tar.zst";22+ hash = "sha256-M7qmhRDJGm2MhgS2oMfRrkLAst1Ye/rPCwP78UBbyyY=";23 };2425 nativeBuildInputs = [
···44 runHook preInstall4546 # Based on the upstream PKGBUILD47- mkdir -p $out/share/doc/${finalAttrs.pname}48 cp -a bin $out49- cp $cmakeDir/README.md $out/share/doc/${finalAttrs.pname}5051 runHook postInstall52 '';
···44 runHook preInstall4546 # Based on the upstream PKGBUILD47+ mkdir -p $out/share/doc/mya48 cp -a bin $out49+ cp $cmakeDir/README.md $out/share/doc/mya5051 runHook postInstall52 '';
···1+From 3161fec0b9ff9154dbd952c3481400118fabb744 Mon Sep 17 00:00:00 20012+From: Helmut Grohne <helmut.grohne@intenta.de>3+Date: Thu, 21 Apr 2022 10:07:53 +02004+Subject: [PATCH] Add rudimentary support for modules property5+6+In linux commit 6dd85ff178cd76851e2184b13e545f5a88d1be30, Linux Torvalds7+changed "option modules" to plain "modules" since it was the only option8+left. kconfiglib does not have much support for either besides parsing9+it and suppressing warnings when it is applied to the 'MODULES' symbol.10+Mirror this behaviour for the newer "modules" property.11+12+Fixes: #10613+---14+ kconfiglib.py | 14 ++++++++++++++15+ 1 file changed, 14 insertions(+)16+17+diff --git a/kconfiglib.py b/kconfiglib.py18+index c67895c..ccef123 10064419+--- a/kconfiglib.py20++++ b/kconfiglib.py21+@@ -3263,6 +3263,20 @@ def _parse_props(self, node):22+ else:23+ self._parse_error("unrecognized option")24+25++ elif t0 is _T_MODULES:26++ # 'modules' formerly was 'option modules'. See above for why27++ # and when it is ignored. It was changed in28++ # linux commit 6dd85ff178cd76851e2184b13e545f5a88d1be30.29++ if node.item is not self.modules:30++ self._warn("the 'modules' property is not supported. Let "31++ "me know if this is a problem for you, as it "32++ "wouldn't be that hard to implement. Note that "33++ "modules are supported -- Kconfiglib just "34++ "assumes the symbol name MODULES, like older "35++ "versions of the C implementation did when "36++ "'modules' wasn't used.",37++ self.filename, self.linenr)38++39+ elif t0 is _T_OPTIONAL:40+ if node.item.__class__ is not Choice:41+ self._parse_error('"optional" is only valid for choices')
···14 sha256 = "0g690bk789hsry34y4ahvly5c8w8imca90ss4njfqf7m2qicrlmy";15 };160000017 # doesnt work out of the box but might be possible18 doCheck = false;19
···14 sha256 = "0g690bk789hsry34y4ahvly5c8w8imca90ss4njfqf7m2qicrlmy";15 };1617+ patches = [18+ # see https://github.com/ulfalizer/Kconfiglib/pull/11919+ ./0001-Add-rudimentary-support-for-modules-property.patch20+ ];21+22 # doesnt work out of the box but might be possible23 doCheck = false;24
···1+From 6b3ab4a94e4d498cdabd5aac6b749031abd785c8 Mon Sep 17 00:00:00 20012+From: Ralph Meijer <ralphm@ik.nu>3+Date: Thu, 18 Jul 2024 19:04:47 +02004+Subject: [PATCH] Remove py2 compat5+6+Co-authored-by: OPNA2608 <opna2608@protonmail.com>7+---8+ setup.py | 11 ++-9+ wokkel/component.py | 13 ++-10+ wokkel/data_form.py | 70 ++++++----------11+ wokkel/delay.py | 2 +-12+ wokkel/disco.py | 51 ++++++------13+ wokkel/formats.py | 20 ++---14+ wokkel/generic.py | 19 +----15+ wokkel/iwokkel.py | 150 +++++++++++++++++-----------------16+ wokkel/muc.py | 67 ++++++++-------17+ wokkel/pubsub.py | 55 ++++++-------18+ wokkel/server.py | 17 ++--19+ wokkel/shim.py | 5 +-20+ wokkel/subprotocols.py | 13 ++-21+ wokkel/test/helpers.py | 5 +-22+ wokkel/test/test_client.py | 3 +-23+ wokkel/test/test_data_form.py | 89 +++++---------------24+ wokkel/test/test_generic.py | 75 +----------------25+ wokkel/test/test_muc.py | 13 ++-26+ wokkel/test/test_server.py | 6 +-27+ wokkel/test/test_shim.py | 5 +-28+ wokkel/test/test_xmppim.py | 19 ++---29+ wokkel/xmppim.py | 89 ++++++++++----------30+ 22 files changed, 318 insertions(+), 479 deletions(-)31+32+diff --git a/setup.py b/setup.py33+index 8804fd9..f7f1e33 10075534+--- a/setup.py35++++ b/setup.py36+@@ -40,11 +40,11 @@ setup(name='wokkel',37+ license='MIT',38+ platforms='any',39+ classifiers=[40+- 'Programming Language :: Python :: 2.7',41+ 'Programming Language :: Python :: 3',42+- 'Programming Language :: Python :: 3.4',43+- 'Programming Language :: Python :: 3.5',44+ 'Programming Language :: Python :: 3.6',45++ 'Programming Language :: Python :: 3.7',46++ 'Programming Language :: Python :: 3.8',47++ 'Programming Language :: Python :: 3.9',48+ ],49+ packages=[50+ 'wokkel',51+@@ -60,16 +60,15 @@ setup(name='wokkel',52+ install_requires=[53+ 'incremental>=16.9.0',54+ 'python-dateutil',55++ 'Twisted[tls]>=16.4.0',56+ ],57+ extras_require={58+- ":python_version<'3'": 'Twisted[tls]>=15.5.0',59+- ":python_version>'3'": 'Twisted[tls]>=16.4.0',60+ "dev": [61+ "pyflakes",62+ "coverage",63++ "pydoctor",64+ "sphinx",65+ "towncrier",66+ ],67+- "dev:python_version<'3'": "pydoctor",68+ },69+ )70+diff --git a/wokkel/component.py b/wokkel/component.py71+index da48230..9410837 10064472+--- a/wokkel/component.py73++++ b/wokkel/component.py74+@@ -12,7 +12,6 @@ from __future__ import division, absolute_import75+ from twisted.application import service76+ from twisted.internet import reactor77+ from twisted.python import log78+-from twisted.python.compat import unicode79+ from twisted.words.protocols.jabber.jid import internJID as JID80+ from twisted.words.protocols.jabber import component, error, xmlstream81+ from twisted.words.xish import domish82+@@ -105,7 +104,7 @@ class InternalComponent(xmlstream.XMPPHandlerCollection, service.Service):83+ components of this type connect to a router in the same process. This84+ allows for one-process XMPP servers.85+86+- @ivar domains: Domains (as L{unicode}) this component will handle traffic87++ @ivar domains: Domains (as L{str}) this component will handle traffic88+ for.89+ @type domains: L{set}90+ """91+@@ -177,7 +176,7 @@ class ListenComponentAuthenticator(xmlstream.ListenAuthenticator):92+ Authenticator for accepting components.93+94+ @ivar secret: The shared used to authorized incoming component connections.95+- @type secret: L{unicode}.96++ @type secret: L{str}.97+ """98+99+ namespace = NS_COMPONENT_ACCEPT100+@@ -241,7 +240,7 @@ class ListenComponentAuthenticator(xmlstream.ListenAuthenticator):101+ L{onHandshake}.102+ """103+ if (element.uri, element.name) == (self.namespace, 'handshake'):104+- self.onHandshake(unicode(element))105++ self.onHandshake(str(element))106+ else:107+ exc = error.StreamError('not-authorized')108+ self.xmlstream.sendStreamError(exc)109+@@ -257,7 +256,7 @@ class ListenComponentAuthenticator(xmlstream.ListenAuthenticator):110+ be exchanged.111+ """112+ calculatedHash = xmlstream.hashPassword(self.xmlstream.sid,113+- unicode(self.secret))114++ str(self.secret))115+ if handshake != calculatedHash:116+ exc = error.StreamError('not-authorized', text='Invalid hash')117+ self.xmlstream.sendStreamError(exc)118+@@ -301,7 +300,7 @@ class Router(object):119+120+ @param destination: Destination of the route to be added as a host name121+ or L{None} for the default route.122+- @type destination: L{unicode} or L{NoneType}123++ @type destination: L{str} or L{NoneType}124+125+ @param xs: XML Stream to register the route for.126+ @type xs:127+@@ -316,7 +315,7 @@ class Router(object):128+ Remove a route.129+130+ @param destination: Destination of the route that should be removed.131+- @type destination: L{unicode}132++ @type destination: L{str}133+134+ @param xs: XML Stream to remove the route for.135+ @type xs:136+diff --git a/wokkel/data_form.py b/wokkel/data_form.py137+index ed9c5fc..7f1c34c 100644138+--- a/wokkel/data_form.py139++++ b/wokkel/data_form.py140+@@ -17,7 +17,6 @@ from __future__ import division, absolute_import141+ from zope.interface import implementer142+ from zope.interface.common import mapping143+144+-from twisted.python.compat import iteritems, unicode, _PY3145+ from twisted.words.protocols.jabber.jid import JID146+ from twisted.words.xish import domish147+148+@@ -51,9 +50,9 @@ class Option(object):149+ Data Forms field option.150+151+ @ivar value: Value of this option.152+- @type value: L{unicode}153++ @type value: L{str}154+ @ivar label: Optional label for this option.155+- @type label: L{unicode} or L{NoneType}156++ @type label: L{str} or L{NoneType}157+ """158+159+ def __init__(self, value, label=None):160+@@ -91,7 +90,7 @@ class Option(object):161+ raise Error("Option has no value")162+163+ label = element.getAttribute('label')164+- return Option(unicode(valueElements[0]), label)165++ return Option(str(valueElements[0]), label)166+167+168+ class Field(object):169+@@ -108,15 +107,15 @@ class Field(object):170+ @ivar var: Field name. Optional if C{fieldType} is C{'fixed'}.171+ @type var: L{str}172+ @ivar label: Human readable label for this field.173+- @type label: L{unicode}174++ @type label: L{str}175+ @ivar values: The values for this field, for multi-valued field176+- types, as a list of L{bool}, L{unicode} or L{JID}.177++ types, as a list of L{bool}, L{str} or L{JID}.178+ @type values: L{list}179+ @ivar options: List of possible values to choose from in a response180+ to this form as a list of L{Option}s.181+ @type options: L{list}182+ @ivar desc: Human readable description for this field.183+- @type desc: L{unicode}184++ @type desc: L{str}185+ @ivar required: Whether the field is required to be provided in a186+ response to this form.187+ @type required: L{bool}188+@@ -147,7 +146,7 @@ class Field(object):189+ try:190+ self.options = [Option(optionValue, optionLabel)191+ for optionValue, optionLabel192+- in iteritems(options)]193++ in options.items()]194+ except AttributeError:195+ self.options = options or []196+197+@@ -185,7 +184,7 @@ class Field(object):198+199+ Sets C{value} as the only element of L{values}.200+201+- @type value: L{bool}, L{unicode} or L{JID}202++ @type value: L{bool}, L{str} or L{JID}203+ """204+ self.values = [value]205+206+@@ -229,7 +228,7 @@ class Field(object):207+ newValues = []208+ for value in self.values:209+ if self.fieldType == 'boolean':210+- if isinstance(value, (str, unicode)):211++ if isinstance(value, str):212+ checkValue = value.lower()213+ if not checkValue in ('0', '1', 'false', 'true'):214+ raise ValueError("Not a boolean")215+@@ -263,9 +262,9 @@ class Field(object):216+217+ for value in self.values:218+ if isinstance(value, bool):219+- value = unicode(value).lower()220++ value = str(value).lower()221+ else:222+- value = unicode(value)223++ value = str(value)224+225+ field.addElement('value', content=value)226+227+@@ -288,7 +287,7 @@ class Field(object):228+229+ @staticmethod230+ def _parse_desc(field, element):231+- desc = unicode(element)232++ desc = str(element)233+ if desc:234+ field.desc = desc235+236+@@ -305,7 +304,7 @@ class Field(object):237+238+ @staticmethod239+ def _parse_value(field, element):240+- value = unicode(element)241++ value = str(element)242+ field.values.append(value)243+244+245+@@ -313,9 +312,9 @@ class Field(object):246+ def fromElement(element):247+ field = Field(None)248+249+- for eAttr, fAttr in iteritems({'type': 'fieldType',250+- 'var': 'var',251+- 'label': 'label'}):252++ for eAttr, fAttr in {'type': 'fieldType',253++ 'var': 'var',254++ 'label': 'label'}.items():255+ value = element.getAttribute(eAttr)256+ if value:257+ setattr(field, fAttr, value)258+@@ -350,7 +349,7 @@ class Field(object):259+260+ if 'options' in fieldDict:261+ options = []262+- for value, label in iteritems(fieldDict['options']):263++ for value, label in fieldDict['options'].items():264+ options.append(Option(value, label))265+ kwargs['options'] = options266+267+@@ -385,9 +384,9 @@ class Form(object):268+ @type formType: L{str}269+270+ @ivar title: Natural language title of the form.271+- @type title: L{unicode}272++ @type title: L{str}273+274+- @ivar instructions: Natural language instructions as a list of L{unicode}275++ @ivar instructions: Natural language instructions as a list of L{str}276+ strings without line breaks.277+ @type instructions: L{list}278+279+@@ -497,7 +496,7 @@ class Form(object):280+ C{fieldDefs}.281+ @type filterUnknown: L{bool}282+ """283+- for name, value in iteritems(values):284++ for name, value in values.items():285+ fieldDict = {'var': name,286+ 'type': None}287+288+@@ -542,14 +541,14 @@ class Form(object):289+290+ @staticmethod291+ def _parse_title(form, element):292+- title = unicode(element)293++ title = str(element)294+ if title:295+ form.title = title296+297+298+ @staticmethod299+ def _parse_instructions(form, element):300+- instructions = unicode(element)301++ instructions = str(element)302+ if instructions:303+ form.instructions.append(instructions)304+305+@@ -624,36 +623,19 @@ class Form(object):306+ return key in self.fields307+308+309+- def iterkeys(self):310++ def keys(self):311+ return iter(self)312+313+314+- def itervalues(self):315++ def values(self):316+ for key in self:317+ yield self[key]318+319+320+- def iteritems(self):321++ def items(self):322+ for key in self:323+ yield (key, self[key])324+325+- if _PY3:326+- keys = iterkeys327+- values = itervalues328+- items = iteritems329+- else:330+- def keys(self):331+- return list(self)332+-333+-334+- def values(self):335+- return list(self.itervalues())336+-337+-338+- def items(self):339+- return list(self.iteritems())340+-341+-342+ def getValues(self):343+ """344+ Extract values from the named form fields.345+@@ -701,7 +683,7 @@ class Form(object):346+347+ filtered = []348+349+- for name, field in iteritems(self.fields):350++ for name, field in self.fields.items():351+ if name in fieldDefs:352+ fieldDef = fieldDefs[name]353+ if 'type' not in fieldDef:354+diff --git a/wokkel/delay.py b/wokkel/delay.py355+index be06cb3..1dd1703 100644356+--- a/wokkel/delay.py357++++ b/wokkel/delay.py358+@@ -46,7 +46,7 @@ class Delay(object):359+ Render this instance into a domish Element.360+361+ @param legacy: If C{True}, use the legacy XEP-0091 format.362+- @type legacy: C{bool}363++ @type legacy: L{bool}364+ """365+ if not self.stamp:366+ raise ValueError("stamp is required")367+diff --git a/wokkel/disco.py b/wokkel/disco.py368+index 9ea43ef..227789d 100644369+--- a/wokkel/disco.py370++++ b/wokkel/disco.py371+@@ -13,7 +13,6 @@ U{XEP-0030<http://xmpp.org/extensions/xep-0030.html>}.372+ from __future__ import division, absolute_import373+374+ from twisted.internet import defer375+-from twisted.python.compat import iteritems, unicode376+ from twisted.words.protocols.jabber import error, jid377+ from twisted.words.xish import domish378+379+@@ -29,11 +28,11 @@ IQ_GET = '/iq[@type="get"]'380+ DISCO_INFO = IQ_GET + '/query[@xmlns="' + NS_DISCO_INFO + '"]'381+ DISCO_ITEMS = IQ_GET + '/query[@xmlns="' + NS_DISCO_ITEMS + '"]'382+383+-class DiscoFeature(unicode):384++class DiscoFeature(str):385+ """386+ XMPP service discovery feature.387+388+- This extends C{unicode} to convert to and from L{domish.Element}, but389++ This extends L{str} to convert to and from L{domish.Element}, but390+ further behaves identically.391+ """392+393+@@ -44,7 +43,7 @@ class DiscoFeature(unicode):394+ @rtype: L{domish.Element}.395+ """396+ element = domish.Element((NS_DISCO_INFO, 'feature'))397+- element['var'] = unicode(self)398++ element['var'] = str(self)399+ return element400+401+402+@@ -68,11 +67,11 @@ class DiscoIdentity(object):403+ XMPP service discovery identity.404+405+ @ivar category: The identity category.406+- @type category: C{unicode}407++ @type category: L{str}408+ @ivar type: The identity type.409+- @type type: C{unicode}410++ @type type: L{str}411+ @ivar name: The optional natural language name for this entity.412+- @type name: C{unicode}413++ @type name: L{str}414+ """415+416+ def __init__(self, category, idType, name=None):417+@@ -119,21 +118,21 @@ class DiscoInfo(object):418+ XMPP service discovery info.419+420+ @ivar nodeIdentifier: The optional node this info applies to.421+- @type nodeIdentifier: C{unicode}422++ @type nodeIdentifier: L{str}423+ @ivar features: Features as L{DiscoFeature}.424+- @type features: C{set}425++ @type features: L{set}426+ @ivar identities: Identities as a mapping from (category, type) to name,427+- all C{unicode}.428+- @type identities: C{dict}429++ all L{str}.430++ @type identities: L{dict}431+ @ivar extensions: Service discovery extensions as a mapping from the432+- extension form's C{FORM_TYPE} (C{unicode}) to433++ extension form's C{FORM_TYPE} (L{str}) to434+ L{data_form.Form}. Forms with no C{FORM_TYPE} field435+ are mapped as C{None}. Note that multiple forms436+ with the same C{FORM_TYPE} have the last in sequence437+ prevail.438+- @type extensions: C{dict}439++ @type extensions: L{dict}440+ @ivar _items: Sequence of added items.441+- @type _items: C{list}442++ @type _items: L{list}443+ """444+445+ def __init__(self):446+@@ -226,9 +225,9 @@ class DiscoItem(object):447+ @ivar entity: The entity holding the item.448+ @type entity: L{jid.JID}449+ @ivar nodeIdentifier: The optional node identifier for the item.450+- @type nodeIdentifier: C{unicode}451++ @type nodeIdentifier: L{str}452+ @ivar name: The optional natural language name for this entity.453+- @type name: C{unicode}454++ @type name: L{str}455+ """456+457+ def __init__(self, entity, nodeIdentifier='', name=None):458+@@ -278,9 +277,9 @@ class DiscoItems(object):459+ XMPP service discovery items.460+461+ @ivar nodeIdentifier: The optional node this info applies to.462+- @type nodeIdentifier: C{unicode}463++ @type nodeIdentifier: L{str}464+ @ivar _items: Sequence of added items.465+- @type _items: C{list}466++ @type _items: L{list}467+ """468+469+ def __init__(self):470+@@ -353,9 +352,9 @@ class _DiscoRequest(generic.Request):471+ A Service Discovery request.472+473+ @ivar verb: Type of request: C{'info'} or C{'items'}.474+- @type verb: C{str}475++ @type verb: L{str}476+ @ivar nodeIdentifier: Optional node to request info for.477+- @type nodeIdentifier: C{unicode}478++ @type nodeIdentifier: L{str}479+ """480+481+ verb = None482+@@ -366,7 +365,7 @@ class _DiscoRequest(generic.Request):483+ NS_DISCO_ITEMS: 'items',484+ }485+486+- _verbRequestMap = dict(((v, k) for k, v in iteritems(_requestVerbMap)))487++ _verbRequestMap = dict(((v, k) for k, v in _requestVerbMap.items()))488+489+ def __init__(self, verb=None, nodeIdentifier='',490+ recipient=None, sender=None):491+@@ -415,7 +414,7 @@ class DiscoClientProtocol(XMPPHandler):492+ @type entity: L{jid.JID}493+494+ @param nodeIdentifier: Optional node to request info from.495+- @type nodeIdentifier: C{unicode}496++ @type nodeIdentifier: L{str}497+498+ @param sender: Optional sender address.499+ @type sender: L{jid.JID}500+@@ -438,7 +437,7 @@ class DiscoClientProtocol(XMPPHandler):501+ @type entity: L{jid.JID}502+503+ @param nodeIdentifier: Optional node to request info from.504+- @type nodeIdentifier: C{unicode}505++ @type nodeIdentifier: L{str}506+507+ @param sender: Optional sender address.508+ @type sender: L{jid.JID}509+@@ -534,7 +533,7 @@ class DiscoHandler(XMPPHandler, IQHandlerMixin):510+511+ @param deferredList: List of deferreds for which the results should be512+ gathered.513+- @type deferredList: C{list}514++ @type deferredList: L{list}515+ @return: Deferred that fires with a list of gathered results.516+ @rtype: L{defer.Deferred}517+ """518+@@ -566,7 +565,7 @@ class DiscoHandler(XMPPHandler, IQHandlerMixin):519+ @param target: The entity the request was sent to.520+ @type target: L{JID<twisted.words.protocols.jabber.jid.JID>}521+ @param nodeIdentifier: The optional node being queried, or C{''}.522+- @type nodeIdentifier: C{unicode}523++ @type nodeIdentifier: L{str}524+ @return: Deferred with the gathered results from sibling handlers.525+ @rtype: L{defer.Deferred}526+ """527+@@ -589,7 +588,7 @@ class DiscoHandler(XMPPHandler, IQHandlerMixin):528+ @param target: The entity the request was sent to.529+ @type target: L{JID<twisted.words.protocols.jabber.jid.JID>}530+ @param nodeIdentifier: The optional node being queried, or C{''}.531+- @type nodeIdentifier: C{unicode}532++ @type nodeIdentifier: L{str}533+ @return: Deferred with the gathered results from sibling handlers.534+ @rtype: L{defer.Deferred}535+ """536+diff --git a/wokkel/formats.py b/wokkel/formats.py537+index 0eb0be6..972cc7e 100644538+--- a/wokkel/formats.py539++++ b/wokkel/formats.py540+@@ -9,8 +9,6 @@ Generic payload formats.541+542+ from __future__ import division, absolute_import543+544+-from twisted.python.compat import unicode545+-546+ NS_MOOD = 'http://jabber.org/protocol/mood'547+ NS_TUNE = 'http://jabber.org/protocol/tune'548+549+@@ -55,7 +53,7 @@ class Mood:550+ continue551+552+ if child.name == 'text':553+- text = unicode(child)554++ text = str(child)555+ else:556+ value = child.name557+558+@@ -76,19 +74,19 @@ class Tune:559+ U{XEP-0118<http://xmpp.org/extensions/xep-0118.html>}.560+561+ @ivar artist: The artist or performer of the song or piece.562+- @type artist: C{unicode}563++ @type artist: L{str}564+ @ivar length: The duration of the song or piece in seconds.565+- @type length: C{int}566++ @type length: L{int}567+ @ivar source: The collection (e.g. album) or other source.568+- @type source: C{unicode}569++ @type source: L{str}570+ @ivar title: The title of the song or piece571+- @type title: C{unicode}572++ @type title: L{str}573+ @ivar track: A unique identifier for the tune; e.g. the track number within574+ the collection or the specific URI for the object.575+- @type track: C{unicode}576++ @type track: L{str}577+ @ivar uri: A URI pointing to information about the song, collection, or578+ artist.579+- @type uri: C{str}580++ @type uri: L{str}581+582+ """583+584+@@ -122,10 +120,10 @@ class Tune:585+ continue586+587+ if child.name in ('artist', 'source', 'title', 'track', 'uri'):588+- setattr(tune, child.name, unicode(child))589++ setattr(tune, child.name, str(child))590+ elif child.name == 'length':591+ try:592+- tune.length = int(unicode(child))593++ tune.length = int(str(child))594+ except ValueError:595+ pass596+597+diff --git a/wokkel/generic.py b/wokkel/generic.py598+index 2e975f6..becff8f 100644599+--- a/wokkel/generic.py600++++ b/wokkel/generic.py601+@@ -13,14 +13,11 @@ from zope.interface import implementer602+603+ from twisted.internet import defer, protocol604+ from twisted.python import reflect605+-from twisted.python.deprecate import deprecated606+ from twisted.words.protocols.jabber import error, jid, xmlstream607+ from twisted.words.protocols.jabber.xmlstream import toResponse608+ from twisted.words.xish import domish, utility609+ from twisted.words.xish.xmlstream import BootstrapMixin610+611+-from incremental import Version612+-613+ from wokkel.iwokkel import IDisco614+ from wokkel.subprotocols import XMPPHandler615+616+@@ -35,7 +32,7 @@ def parseXml(string):617+ Parse serialized XML into a DOM structure.618+619+ @param string: The serialized XML to be parsed, UTF-8 encoded.620+- @type string: C{str}.621++ @type string: L{str}.622+ @return: The DOM structure, or C{None} on empty or incomplete input.623+ @rtype: L{domish.Element}624+ """625+@@ -332,17 +329,3 @@ class DeferredXmlStreamFactory(BootstrapMixin, protocol.ClientFactory):626+627+ def clientConnectionFailed(self, connector, reason):628+ self.deferred.errback(reason)629+-630+-631+-632+-@deprecated(Version("wokkel", 18, 0, 0), "unicode.encode('idna')")633+-def prepareIDNName(name):634+- """635+- Encode a unicode IDN Domain Name into its ACE equivalent.636+-637+- This will encode the domain labels, separated by allowed dot code points,638+- to their ASCII Compatible Encoding (ACE) equivalent, using punycode. The639+- result is an ASCII byte string of the encoded labels, separated by the640+- standard full stop.641+- """642+- return name.encode('idna')643+diff --git a/wokkel/iwokkel.py b/wokkel/iwokkel.py644+index 30a1057..35383b5 100644645+--- a/wokkel/iwokkel.py646++++ b/wokkel/iwokkel.py647+@@ -46,7 +46,7 @@ class IDisco(Interface):648+ @param nodeIdentifier: The optional identifier of the node at this649+ entity to retrieve the identify and features of. The default is650+ C{''}, meaning the root node.651+- @type nodeIdentifier: C{unicode}652++ @type nodeIdentifier: L{str}653+ """654+655+ def getDiscoItems(requestor, target, nodeIdentifier=''):656+@@ -60,7 +60,7 @@ class IDisco(Interface):657+ @param nodeIdentifier: The optional identifier of the node at this658+ entity to retrieve the identify and features of.659+ The default is C{''}, meaning the root node.660+- @type nodeIdentifier: C{unicode}661++ @type nodeIdentifier: L{str}662+ """663+664+665+@@ -109,7 +109,7 @@ class IPubSubClient(Interface):666+ @param nodeIdentifier: Optional suggestion for the new node's667+ identifier. If omitted, the creation of an668+ instant node will be attempted.669+- @type nodeIdentifier: C{unicode}670++ @type nodeIdentifier: L{str}671+ @return: a deferred that fires with the identifier of the newly created672+ node. Note that this can differ from the suggested identifier673+ if the publish subscribe service chooses to modify or ignore674+@@ -124,7 +124,7 @@ class IPubSubClient(Interface):675+ @param service: The publish-subscribe service entity.676+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}677+ @param nodeIdentifier: Identifier of the node to be deleted.678+- @type nodeIdentifier: C{unicode}679++ @type nodeIdentifier: L{str}680+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}681+ """682+683+@@ -135,7 +135,7 @@ class IPubSubClient(Interface):684+ @param service: The publish-subscribe service entity.685+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}686+ @param nodeIdentifier: Identifier of the node to subscribe to.687+- @type nodeIdentifier: C{unicode}688++ @type nodeIdentifier: L{str}689+ @param subscriber: JID to subscribe to the node.690+ @type subscriber: L{JID<twisted.words.protocols.jabber.jid.JID>}691+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}692+@@ -148,7 +148,7 @@ class IPubSubClient(Interface):693+ @param service: The publish-subscribe service entity.694+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}695+ @param nodeIdentifier: Identifier of the node to unsubscribe from.696+- @type nodeIdentifier: C{unicode}697++ @type nodeIdentifier: L{str}698+ @param subscriber: JID to unsubscribe from the node.699+ @type subscriber: L{JID<twisted.words.protocols.jabber.jid.JID>}700+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}701+@@ -165,9 +165,9 @@ class IPubSubClient(Interface):702+ @param service: The publish-subscribe service entity.703+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}704+ @param nodeIdentifier: Identifier of the node to publish to.705+- @type nodeIdentifier: C{unicode}706++ @type nodeIdentifier: L{str}707+ @param items: List of item elements.708+- @type items: C{list} of L{Item}709++ @type items: L{list} of L{Item}710+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}711+ """712+713+@@ -191,12 +191,12 @@ class IPubSubService(Interface):714+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}715+ @param nodeIdentifier: The identifier of the node that was published716+ to.717+- @type nodeIdentifier: C{unicode}718++ @type nodeIdentifier: L{str}719+ @param notifications: The notifications as tuples of subscriber, the720+ list of subscriptions and the list of items to be notified.721+- @type notifications: C{list} of722+- (L{JID<twisted.words.protocols.jabber.jid.JID>}, C{list} of723+- L{Subscription<wokkel.pubsub.Subscription>}, C{list} of724++ @type notifications: L{list} of725++ (L{JID<twisted.words.protocols.jabber.jid.JID>}, L{list} of726++ L{Subscription<wokkel.pubsub.Subscription>}, L{list} of727+ L{Element<twisted.words.xish.domish.Element>})728+ """729+730+@@ -209,14 +209,14 @@ class IPubSubService(Interface):731+ @param service: The entity the notifications will originate from.732+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}733+ @param nodeIdentifier: The identifier of the node that was deleted.734+- @type nodeIdentifier: C{unicode}735++ @type nodeIdentifier: L{str}736+ @param subscribers: The subscribers for which a notification should be737+ sent out.738+- @type subscribers: C{list} of739++ @type subscribers: L{list} of740+ L{JID<twisted.words.protocols.jabber.jid.JID>}741+ @param redirectURI: Optional XMPP URI of another node that subscribers742+ are redirected to.743+- @type redirectURI: C{str}744++ @type redirectURI: L{str}745+ """746+747+ def publish(requestor, service, nodeIdentifier, items):748+@@ -228,9 +228,9 @@ class IPubSubService(Interface):749+ @param service: The entity the request was addressed to.750+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}751+ @param nodeIdentifier: The identifier of the node to publish to.752+- @type nodeIdentifier: C{unicode}753++ @type nodeIdentifier: L{str}754+ @param items: The items to be published as elements.755+- @type items: C{list} of C{Element<twisted.words.xish.domish.Element>}756++ @type items: L{list} of C{Element<twisted.words.xish.domish.Element>}757+ @return: deferred that fires on success.758+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}759+ """760+@@ -244,7 +244,7 @@ class IPubSubService(Interface):761+ @param service: The entity the request was addressed to.762+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}763+ @param nodeIdentifier: The identifier of the node to subscribe to.764+- @type nodeIdentifier: C{unicode}765++ @type nodeIdentifier: L{str}766+ @param subscriber: The entity to be subscribed.767+ @type subscriber: L{JID<twisted.words.protocols.jabber.jid.JID>}768+ @return: A deferred that fires with a769+@@ -261,7 +261,7 @@ class IPubSubService(Interface):770+ @param service: The entity the request was addressed to.771+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}772+ @param nodeIdentifier: The identifier of the node to unsubscribe from.773+- @type nodeIdentifier: C{unicode}774++ @type nodeIdentifier: L{str}775+ @param subscriber: The entity to be unsubscribed.776+ @type subscriber: L{JID<twisted.words.protocols.jabber.jid.JID>}777+ @return: A deferred that fires with C{None} when unsubscription has778+@@ -277,7 +277,7 @@ class IPubSubService(Interface):779+ @type requestor: L{JID<twisted.words.protocols.jabber.jid.JID>}780+ @param service: The entity the request was addressed to.781+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}782+- @return: A deferred that fires with a C{list} of subscriptions as783++ @return: A deferred that fires with a L{list} of subscriptions as784+ L{Subscription<wokkel.pubsub.Subscription>}.785+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}786+ """787+@@ -290,9 +290,9 @@ class IPubSubService(Interface):788+ @type requestor: L{JID<twisted.words.protocols.jabber.jid.JID>}789+ @param service: The entity the request was addressed to.790+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}791+- @return: A deferred that fires with a C{list} of affiliations as792+- C{tuple}s of (node identifier as C{unicode}, affiliation state as793+- C{str}). The affiliation can be C{'owner'}, C{'publisher'}, or794++ @return: A deferred that fires with a L{list} of affiliations as795++ C{tuple}s of (node identifier as L{str}, affiliation state as796++ L{str}). The affiliation can be C{'owner'}, C{'publisher'}, or797+ C{'outcast'}.798+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}799+ """800+@@ -308,8 +308,8 @@ class IPubSubService(Interface):801+ @param nodeIdentifier: The suggestion for the identifier of the node802+ to be created. If the request did not include a suggestion for the803+ node identifier, the value is C{None}.804+- @type nodeIdentifier: C{unicode} or C{NoneType}805+- @return: A deferred that fires with a C{unicode} that represents806++ @type nodeIdentifier: L{str} or C{NoneType}807++ @return: A deferred that fires with a L{str} that represents808+ the identifier of the new node.809+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}810+ """811+@@ -322,10 +322,10 @@ class IPubSubService(Interface):812+ by option name. The value of each entry represents the specifics for813+ that option in a dictionary:814+815+- - C{'type'} (C{str}): The option's type (see816++ - C{'type'} (L{str}): The option's type (see817+ L{Field<wokkel.data_form.Field>}'s doc string for possible values).818+- - C{'label'} (C{unicode}): A human readable label for this option.819+- - C{'options'} (C{dict}): Optional list of possible values for this820++ - C{'label'} (L{str}): A human readable label for this option.821++ - C{'options'} (L{dict}): Optional list of possible values for this822+ option.823+824+ Example::825+@@ -346,7 +346,7 @@ class IPubSubService(Interface):826+ }827+ }828+829+- @rtype: C{dict}.830++ @rtype: L{dict}.831+ """832+833+ def getDefaultConfiguration(requestor, service, nodeType):834+@@ -359,11 +359,11 @@ class IPubSubService(Interface):835+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}836+ @param nodeType: The type of node for which the configuration is837+ retrieved, C{'leaf'} or C{'collection'}.838+- @type nodeType: C{str}839+- @return: A deferred that fires with a C{dict} representing the default840+- node configuration. Keys are C{str}s that represent the841+- field name. Values can be of types C{unicode}, C{int} or842+- C{bool}.843++ @type nodeType: L{str}844++ @return: A deferred that fires with a L{dict} representing the default845++ node configuration. Keys are L{str}s that represent the846++ field name. Values can be of types L{str}, L{int} or847++ L{bool}.848+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}849+ """850+851+@@ -377,10 +377,10 @@ class IPubSubService(Interface):852+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}853+ @param nodeIdentifier: The identifier of the node to retrieve the854+ configuration from.855+- @type nodeIdentifier: C{unicode}856+- @return: A deferred that fires with a C{dict} representing the node857+- configuration. Keys are C{str}s that represent the field name.858+- Values can be of types C{unicode}, C{int} or C{bool}.859++ @type nodeIdentifier: L{str}860++ @return: A deferred that fires with a L{dict} representing the node861++ configuration. Keys are L{str}s that represent the field name.862++ Values can be of types L{str}, L{int} or L{bool}.863+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}864+ """865+866+@@ -394,7 +394,7 @@ class IPubSubService(Interface):867+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}868+ @param nodeIdentifier: The identifier of the node to change the869+ configuration of.870+- @type nodeIdentifier: C{unicode}871++ @type nodeIdentifier: L{str}872+ @return: A deferred that fires with C{None} when the node's873+ configuration has been changed.874+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}875+@@ -410,7 +410,7 @@ class IPubSubService(Interface):876+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}877+ @param nodeIdentifier: The identifier of the node to retrieve items878+ from.879+- @type nodeIdentifier: C{unicode}880++ @type nodeIdentifier: L{str}881+ """882+883+ def retract(requestor, service, nodeIdentifier, itemIdentifiers):884+@@ -423,7 +423,7 @@ class IPubSubService(Interface):885+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}886+ @param nodeIdentifier: The identifier of the node to retract items887+ from.888+- @type nodeIdentifier: C{unicode}889++ @type nodeIdentifier: L{str}890+ """891+892+ def purge(requestor, service, nodeIdentifier):893+@@ -435,7 +435,7 @@ class IPubSubService(Interface):894+ @param service: The entity the request was addressed to.895+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}896+ @param nodeIdentifier: The identifier of the node to be purged.897+- @type nodeIdentifier: C{unicode}898++ @type nodeIdentifier: L{str}899+ """900+901+ def delete(requestor, service, nodeIdentifier):902+@@ -447,7 +447,7 @@ class IPubSubService(Interface):903+ @param service: The entity the request was addressed to.904+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}905+ @param nodeIdentifier: The identifier of the node to be delete.906+- @type nodeIdentifier: C{unicode}907++ @type nodeIdentifier: L{str}908+ """909+910+911+@@ -472,7 +472,7 @@ class IPubSubResource(Interface):912+ @param service: The publish-subscribe service entity.913+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}914+ @param nodeIdentifier: Identifier of the node to request the info for.915+- @type nodeIdentifier: C{unicode}916++ @type nodeIdentifier: L{str}917+ @return: A deferred that fires with a dictionary. If not empty,918+ it must have the keys C{'type'} and C{'meta-data'} to keep919+ respectively the node type and a dictionary with the meta920+@@ -491,7 +491,7 @@ class IPubSubResource(Interface):921+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}922+ @param nodeIdentifier: Identifier of the node to request the childs923+ for.924+- @type nodeIdentifier: C{unicode}925++ @type nodeIdentifier: L{str}926+ @return: A deferred that fires with a list of child node identifiers.927+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}928+ """929+@@ -505,10 +505,10 @@ class IPubSubResource(Interface):930+ by option name. The value of each entry represents the specifics for931+ that option in a dictionary:932+933+- - C{'type'} (C{str}): The option's type (see934++ - C{'type'} (L{str}): The option's type (see935+ L{Field<wokkel.data_form.Field>}'s doc string for possible values).936+- - C{'label'} (C{unicode}): A human readable label for this option.937+- - C{'options'} (C{dict}): Optional list of possible values for this938++ - C{'label'} (L{str}): A human readable label for this option.939++ - C{'options'} (L{dict}): Optional list of possible values for this940+ option.941+942+ Example::943+@@ -529,7 +529,7 @@ class IPubSubResource(Interface):944+ }945+ }946+947+- @rtype: C{dict}.948++ @rtype: L{dict}.949+ """950+951+952+@@ -574,7 +574,7 @@ class IPubSubResource(Interface):953+954+ @param request: The publish-subscribe request.955+ @type request: L{wokkel.pubsub.PubSubRequest}956+- @return: A deferred that fires with a C{list} of subscriptions as957++ @return: A deferred that fires with a L{list} of subscriptions as958+ L{Subscription<wokkel.pubsub.Subscription>}.959+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}960+ """961+@@ -586,9 +586,9 @@ class IPubSubResource(Interface):962+963+ @param request: The publish-subscribe request.964+ @type request: L{wokkel.pubsub.PubSubRequest}965+- @return: A deferred that fires with a C{list} of affiliations as966+- C{tuple}s of (node identifier as C{unicode}, affiliation state as967+- C{str}). The affiliation can be C{'owner'}, C{'publisher'}, or968++ @return: A deferred that fires with a L{list} of affiliations as969++ C{tuple}s of (node identifier as L{str}, affiliation state as970++ L{str}). The affiliation can be C{'owner'}, C{'publisher'}, or971+ C{'outcast'}.972+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}973+ """974+@@ -600,7 +600,7 @@ class IPubSubResource(Interface):975+976+ @param request: The publish-subscribe request.977+ @type request: L{wokkel.pubsub.PubSubRequest}978+- @return: A deferred that fires with a C{unicode} that represents979++ @return: A deferred that fires with a L{str} that represents980+ the identifier of the new node.981+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}982+ """983+@@ -612,10 +612,10 @@ class IPubSubResource(Interface):984+985+ @param request: The publish-subscribe request.986+ @type request: L{wokkel.pubsub.PubSubRequest}987+- @return: A deferred that fires with a C{dict} representing the default988+- node configuration. Keys are C{str}s that represent the989+- field name. Values can be of types C{unicode}, C{int} or990+- C{bool}.991++ @return: A deferred that fires with a L{dict} representing the default992++ node configuration. Keys are L{str}s that represent the993++ field name. Values can be of types L{str}, L{int} or994++ L{bool}.995+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}996+ """997+998+@@ -626,9 +626,9 @@ class IPubSubResource(Interface):999+1000+ @param request: The publish-subscribe request.1001+ @type request: L{wokkel.pubsub.PubSubRequest}1002+- @return: A deferred that fires with a C{dict} representing the node1003+- configuration. Keys are C{str}s that represent the field name.1004+- Values can be of types C{unicode}, C{int} or C{bool}.1005++ @return: A deferred that fires with a L{dict} representing the node1006++ configuration. Keys are L{str}s that represent the field name.1007++ Values can be of types L{str}, L{int} or L{bool}.1008+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}1009+ """1010+1011+@@ -651,7 +651,7 @@ class IPubSubResource(Interface):1012+1013+ @param request: The publish-subscribe request.1014+ @type request: L{wokkel.pubsub.PubSubRequest}1015+- @return: A deferred that fires with a C{list} of L{pubsub.Item}.1016++ @return: A deferred that fires with a L{list} of L{pubsub.Item}.1017+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}1018+ """1019+1020+@@ -698,9 +698,9 @@ class IPubSubResource(Interface):1021+1022+ @param request: The publish-subscribe request.1023+ @type request: L{wokkel.pubsub.PubSubRequest}1024+- @return: A deferred that fires with a C{dict} of affiliations with the1025++ @return: A deferred that fires with a L{dict} of affiliations with the1026+ entity as key (L{JID<twisted.words.protocols.jabber.jid.JID>}) and1027+- the affiliation state as value (C{unicode}). The affiliation can1028++ the affiliation state as value (L{str}). The affiliation can1029+ be C{u'owner'}, C{u'publisher'}, or C{u'outcast'}.1030+ @rtype: L{Deferred<twisted.internet.defer.Deferred>}1031+1032+@@ -748,7 +748,7 @@ class IMUCClient(Interface):1033+ @type user: L{muc.User}1034+1035+ @param subject: The subject of the given room.1036+- @type subject: C{unicode}1037++ @type subject: L{str}1038+ """1039+1040+1041+@@ -769,7 +769,7 @@ class IMUCClient(Interface):1042+1043+ @param options: A mapping of field names to values, or C{None} to1044+ cancel.1045+- @type options: C{dict}1046++ @type options: L{dict}1047+ """1048+1049+1050+@@ -796,14 +796,14 @@ class IMUCClient(Interface):1051+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1052+1053+ @param nick: The nick name for the entitity joining the room.1054+- @type nick: C{unicode}1055++ @type nick: L{str}1056+1057+ @param historyOptions: Options for conversation history sent by the1058+ room upon joining.1059+ @type historyOptions: L{HistoryOptions}1060+1061+ @param password: Optional password for the room.1062+- @type password: C{unicode}1063++ @type password: L{str}1064+1065+ @return: A deferred that fires when the entity is in the room or an1066+ error has occurred.1067+@@ -820,7 +820,7 @@ class IMUCClient(Interface):1068+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1069+1070+ @param nick: The new nick name within the room.1071+- @type nick: C{unicode}1072++ @type nick: L{str}1073+ """1074+1075+1076+@@ -876,7 +876,7 @@ class IMUCClient(Interface):1077+1078+ @param options: A mapping of field names to values, or C{None} to1079+ cancel.1080+- @type options: C{dict}1081++ @type options: L{dict}1082+ """1083+1084+1085+@@ -890,7 +890,7 @@ class IMUCClient(Interface):1086+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1087+1088+ @param subject: The subject you want to set.1089+- @type subject: C{unicode}1090++ @type subject: L{str}1091+ """1092+1093+1094+@@ -917,7 +917,7 @@ class IMUCClient(Interface):1095+ holding the original stanza a1096+ L{Element<twisted.words.xish.domish.Element>}, and C{'timestamp'}1097+ with the timestamp.1098+- @type messages: C{list} of1099++ @type messages: L{list} of1100+ L{Element<twisted.words.xish.domish.Element>}1101+ """1102+1103+@@ -933,7 +933,7 @@ class IMUCClient(Interface):1104+ @type entity: L{JID<twisted.words.protocols.jabber.jid.JID>}1105+1106+ @param reason: The reason for banning the entity.1107+- @type reason: C{unicode}1108++ @type reason: L{str}1109+1110+ @param sender: The entity sending the request.1111+ @type sender: L{JID<twisted.words.protocols.jabber.jid.JID>}1112+@@ -949,10 +949,10 @@ class IMUCClient(Interface):1113+1114+ @param nick: The occupant to be banned.1115+ @type nick: L{JID<twisted.words.protocols.jabber.jid.JID>} or1116+- C{unicode}1117++ L{str}1118+1119+ @param reason: The reason given for the kick.1120+- @type reason: C{unicode}1121++ @type reason: L{str}1122+1123+ @param sender: The entity sending the request.1124+ @type sender: L{JID<twisted.words.protocols.jabber.jid.JID>}1125+diff --git a/wokkel/muc.py b/wokkel/muc.py1126+index 330664b..4c826f2 1006441127+--- a/wokkel/muc.py1128++++ b/wokkel/muc.py1129+@@ -17,7 +17,6 @@ from dateutil.tz import tzutc1130+ from zope.interface import implementer1131+1132+ from twisted.internet import defer1133+-from twisted.python.compat import unicode1134+ from twisted.python.constants import Values, ValueConstant1135+ from twisted.words.protocols.jabber import jid, error, xmlstream1136+ from twisted.words.xish import domish1137+@@ -192,7 +191,7 @@ class AdminItem(object):1138+ item.role = element.getAttribute('role')1139+1140+ for child in element.elements(NS_MUC_ADMIN, 'reason'):1141+- item.reason = unicode(child)1142++ item.reason = str(child)1143+1144+ return item1145+1146+@@ -228,13 +227,13 @@ class DestructionRequest(generic.Request):1147+ Room destruction request.1148+1149+ @param reason: Optional reason for the destruction of this room.1150+- @type reason: L{unicode}.1151++ @type reason: L{str}.1152+1153+ @param alternate: Optional room JID of an alternate venue.1154+ @type alternate: L{JID<twisted.words.protocols.jabber.jid.JID>}1155+1156+ @param password: Optional password for entering the alternate venue.1157+- @type password: L{unicode}1158++ @type password: L{str}1159+ """1160+1161+ stanzaType = 'set'1162+@@ -395,10 +394,10 @@ class UserPresence(xmppim.AvailabilityPresence):1163+ Availability presence sent from MUC service to client.1164+1165+ @ivar affiliation: Affiliation of the entity to the room.1166+- @type affiliation: L{unicode}1167++ @type affiliation: L{str}1168+1169+ @ivar role: Role of the entity in the room.1170+- @type role: L{unicode}1171++ @type role: L{str}1172+1173+ @ivar entity: The real JID of the entity this presence is from.1174+ @type entity: L{JID<twisted.words.protocols.jabber.jid.JID>}1175+@@ -408,7 +407,7 @@ class UserPresence(xmppim.AvailabilityPresence):1176+ @type mucStatuses: L{Statuses}1177+1178+ @ivar nick: The nick name of the entity in the room.1179+- @type nick: L{unicode}1180++ @type nick: L{str}1181+ """1182+1183+ affiliation = None1184+@@ -451,7 +450,7 @@ class UserPresence(xmppim.AvailabilityPresence):1185+ self.role = child.getAttribute('role')1186+1187+ for reason in child.elements(NS_MUC_ADMIN, 'reason'):1188+- self.reason = unicode(reason)1189++ self.reason = str(reason)1190+1191+ # TODO: destroy1192+1193+@@ -595,14 +594,14 @@ class MUCClientProtocol(xmppim.BasePresenceProtocol):1194+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1195+1196+ @param nick: The nick name for the entitity joining the room.1197+- @type nick: L{unicode}1198++ @type nick: L{str}1199+1200+ @param historyOptions: Options for conversation history sent by the1201+ room upon joining.1202+ @type historyOptions: L{HistoryOptions}1203+1204+ @param password: Optional password for the room.1205+- @type password: L{unicode}1206++ @type password: L{str}1207+1208+ @return: A deferred that fires when the entity is in the room or an1209+ error has occurred.1210+@@ -628,7 +627,7 @@ class MUCClientProtocol(xmppim.BasePresenceProtocol):1211+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1212+1213+ @param nick: The new nick name within the room.1214+- @type nick: L{unicode}1215++ @type nick: L{str}1216+ """1217+ occupantJID = jid.JID(tuple=(roomJID.user, roomJID.host, nick))1218+ presence = BasicPresence(recipient=occupantJID)1219+@@ -646,10 +645,10 @@ class MUCClientProtocol(xmppim.BasePresenceProtocol):1220+1221+ @param show: The availability of the entity. Common values are xa,1222+ available, etc1223+- @type show: L{unicode}1224++ @type show: L{str}1225+1226+ @param status: The current status of the entity.1227+- @type status: L{unicode}1228++ @type status: L{str}1229+ """1230+ occupantJID = self._roomOccupantMap[roomJID]1231+ presence = BasicPresence(recipient=occupantJID, show=show,1232+@@ -704,7 +703,7 @@ class MUCClientProtocol(xmppim.BasePresenceProtocol):1233+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1234+1235+ @param subject: The subject you want to set.1236+- @type subject: L{unicode}1237++ @type subject: L{str}1238+ """1239+ message = GroupChat(roomJID.userhostJID(), subject=subject)1240+ self.send(message.toElement())1241+@@ -723,7 +722,7 @@ class MUCClientProtocol(xmppim.BasePresenceProtocol):1242+ @type invitee: L{JID<twisted.words.protocols.jabber.jid.JID>}1243+1244+ @param reason: The reason for the invite.1245+- @type reason: L{unicode}1246++ @type reason: L{str}1247+ """1248+ message = InviteMessage(recipient=roomJID, invitee=invitee,1249+ reason=reason)1250+@@ -970,7 +969,7 @@ class MUCClientProtocol(xmppim.BasePresenceProtocol):1251+ L{JID<twisted.words.protocols.jabber.jid.JID>}1252+1253+ @param affiliation: The affilation to the entities will acquire.1254+- @type affiliation: L{unicode}1255++ @type affiliation: L{str}1256+1257+ @param sender: The entity sending the request.1258+ @type sender: L{JID<twisted.words.protocols.jabber.jid.JID>}1259+@@ -992,10 +991,10 @@ class MUCClientProtocol(xmppim.BasePresenceProtocol):1260+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1261+1262+ @param nick: The nick name for the user in this room.1263+- @type nick: L{unicode}1264++ @type nick: L{str}1265+1266+ @param reason: The reason for granting voice to the entity.1267+- @type reason: L{unicode}1268++ @type reason: L{str}1269+1270+ @param sender: The entity sending the request.1271+ @type sender: L{JID<twisted.words.protocols.jabber.jid.JID>}1272+@@ -1015,10 +1014,10 @@ class MUCClientProtocol(xmppim.BasePresenceProtocol):1273+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1274+1275+ @param nick: The nick name for the user in this room.1276+- @type nick: L{unicode}1277++ @type nick: L{str}1278+1279+ @param reason: The reason for revoking voice from the entity.1280+- @type reason: L{unicode}1281++ @type reason: L{str}1282+1283+ @param sender: The entity sending the request.1284+ @type sender: L{JID<twisted.words.protocols.jabber.jid.JID>}1285+@@ -1035,10 +1034,10 @@ class MUCClientProtocol(xmppim.BasePresenceProtocol):1286+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1287+1288+ @param nick: The nick name for the user in this room.1289+- @type nick: L{unicode}1290++ @type nick: L{str}1291+1292+ @param reason: The reason for granting moderation to the entity.1293+- @type reason: L{unicode}1294++ @type reason: L{str}1295+1296+ @param sender: The entity sending the request.1297+ @type sender: L{JID<twisted.words.protocols.jabber.jid.JID>}1298+@@ -1058,7 +1057,7 @@ class MUCClientProtocol(xmppim.BasePresenceProtocol):1299+ @type entity: L{JID<twisted.words.protocols.jabber.jid.JID>}1300+1301+ @param reason: The reason for banning the entity.1302+- @type reason: L{unicode}1303++ @type reason: L{str}1304+1305+ @param sender: The entity sending the request.1306+ @type sender: L{JID<twisted.words.protocols.jabber.jid.JID>}1307+@@ -1075,10 +1074,10 @@ class MUCClientProtocol(xmppim.BasePresenceProtocol):1308+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1309+1310+ @param nick: The occupant to be banned.1311+- @type nick: L{unicode}1312++ @type nick: L{str}1313+1314+ @param reason: The reason given for the kick.1315+- @type reason: L{unicode}1316++ @type reason: L{str}1317+1318+ @param sender: The entity sending the request.1319+ @type sender: L{JID<twisted.words.protocols.jabber.jid.JID>}1320+@@ -1095,7 +1094,7 @@ class MUCClientProtocol(xmppim.BasePresenceProtocol):1321+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1322+1323+ @param reason: The reason for the destruction of the room.1324+- @type reason: L{unicode}1325++ @type reason: L{str}1326+1327+ @param alternate: The JID of the room suggested as an alternate venue.1328+ @type alternate: L{JID<twisted.words.protocols.jabber.jid.JID>}1329+@@ -1135,7 +1134,7 @@ class Room(object):1330+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1331+1332+ @ivar nick: The nick name for the client in this room.1333+- @type nick: L{unicode}1334++ @type nick: L{str}1335+1336+ @ivar occupantJID: The JID of the occupant in the room. Generated from1337+ roomJID and nick.1338+@@ -1190,7 +1189,7 @@ class Room(object):1339+ Get a user from the room's roster.1340+1341+ @param nick: The nick for the user in the MUC room.1342+- @type nick: L{unicode}1343++ @type nick: L{str}1344+ """1345+ return self.roster.get(nick)1346+1347+@@ -1444,14 +1443,14 @@ class MUCClient(MUCClientProtocol):1348+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1349+1350+ @param nick: The nick name for the entitity joining the room.1351+- @type nick: L{unicode}1352++ @type nick: L{str}1353+1354+ @param historyOptions: Options for conversation history sent by the1355+ room upon joining.1356+ @type historyOptions: L{HistoryOptions}1357+1358+ @param password: Optional password for the room.1359+- @type password: L{unicode}1360++ @type password: L{str}1361+1362+ @return: A deferred that fires with the room when the entity is in the1363+ room, or with a failure if an error has occurred.1364+@@ -1488,7 +1487,7 @@ class MUCClient(MUCClientProtocol):1365+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1366+1367+ @param nick: The new nick name within the room.1368+- @type nick: L{unicode}1369++ @type nick: L{str}1370+ """1371+ def cb(presence):1372+ # Presence confirmation, change the nickname.1373+@@ -1530,10 +1529,10 @@ class MUCClient(MUCClientProtocol):1374+1375+ @param show: The availability of the entity. Common values are xa,1376+ available, etc1377+- @type show: L{unicode}1378++ @type show: L{str}1379+1380+ @param status: The current status of the entity.1381+- @type status: L{unicode}1382++ @type status: L{str}1383+ """1384+ room = self._getRoom(roomJID)1385+ d = MUCClientProtocol.status(self, roomJID, show, status)1386+@@ -1549,7 +1548,7 @@ class MUCClient(MUCClientProtocol):1387+ @type roomJID: L{JID<twisted.words.protocols.jabber.jid.JID>}1388+1389+ @param reason: The reason for the destruction of the room.1390+- @type reason: L{unicode}1391++ @type reason: L{str}1392+1393+ @param alternate: The JID of the room suggested as an alternate venue.1394+ @type alternate: L{JID<twisted.words.protocols.jabber.jid.JID>}1395+diff --git a/wokkel/pubsub.py b/wokkel/pubsub.py1396+index 689a6e2..2eb1b44 1006441397+--- a/wokkel/pubsub.py1398++++ b/wokkel/pubsub.py1399+@@ -16,7 +16,6 @@ from zope.interface import implementer1400+1401+ from twisted.internet import defer1402+ from twisted.python import log1403+-from twisted.python.compat import StringType, iteritems, unicode1404+ from twisted.words.protocols.jabber import jid, error1405+ from twisted.words.xish import domish1406+1407+@@ -107,20 +106,20 @@ class Subscription(object):1408+1409+ @ivar nodeIdentifier: The identifier of the node subscribed to. The root1410+ node is denoted by L{None}.1411+- @type nodeIdentifier: L{unicode}1412++ @type nodeIdentifier: L{str}1413+1414+ @ivar subscriber: The subscribing entity.1415+ @type subscriber: L{jid.JID}1416+1417+ @ivar state: The subscription state. One of C{'subscribed'}, C{'pending'},1418+ C{'unconfigured'}.1419+- @type state: L{unicode}1420++ @type state: L{str}1421+1422+ @ivar options: Optional list of subscription options.1423+ @type options: L{dict}1424+1425+ @ivar subscriptionIdentifier: Optional subscription identifier.1426+- @type subscriptionIdentifier: L{unicode}1427++ @type subscriptionIdentifier: L{str}1428+ """1429+1430+ def __init__(self, nodeIdentifier, subscriber, state, options=None,1431+@@ -150,7 +149,7 @@ class Subscription(object):1432+ element = domish.Element((defaultUri, 'subscription'))1433+ if self.nodeIdentifier:1434+ element['node'] = self.nodeIdentifier1435+- element['jid'] = unicode(self.subscriber)1436++ element['jid'] = str(self.subscriber)1437+ element['subscription'] = self.state1438+ if self.subscriptionIdentifier:1439+ element['subid'] = self.subscriptionIdentifier1440+@@ -171,17 +170,17 @@ class Item(domish.Element):1441+ def __init__(self, id=None, payload=None):1442+ """1443+ @param id: optional item identifier1444+- @type id: L{unicode}1445++ @type id: L{str}1446+ @param payload: optional item payload. Either as a domish element, or1447+ as serialized XML.1448+- @type payload: object providing L{domish.IElement} or L{unicode}.1449++ @type payload: object providing L{domish.IElement} or L{str}.1450+ """1451+1452+ domish.Element.__init__(self, (None, 'item'))1453+ if id is not None:1454+ self['id'] = id1455+ if payload is not None:1456+- if isinstance(payload, StringType):1457++ if isinstance(payload, str):1458+ self.addRawXml(payload)1459+ else:1460+ self.addChild(payload)1461+@@ -213,7 +212,7 @@ class PubSubRequest(generic.Stanza):1462+ @type maxItems: L{int}.1463+1464+ @ivar nodeIdentifier: Identifier of the node the request is about.1465+- @type nodeIdentifier: L{unicode}1466++ @type nodeIdentifier: L{str}1467+1468+ @ivar nodeType: The type of node that should be created, or for which the1469+ configuration is retrieved. C{'leaf'} or C{'collection'}.1470+@@ -227,7 +226,7 @@ class PubSubRequest(generic.Stanza):1471+ @type subscriber: L{JID<twisted.words.protocols.jabber.jid.JID>}1472+1473+ @ivar subscriptionIdentifier: Identifier for a specific subscription.1474+- @type subscriptionIdentifier: L{unicode}1475++ @type subscriptionIdentifier: L{str}1476+1477+ @ivar subscriptions: Subscriptions to be modified, as a set of1478+ L{Subscription}.1479+@@ -235,7 +234,7 @@ class PubSubRequest(generic.Stanza):1480+1481+ @ivar affiliations: Affiliations to be modified, as a dictionary of entity1482+ (L{JID<twisted.words.protocols.jabber.jid.JID>} to affiliation1483+- (L{unicode}).1484++ (L{str}).1485+ @type affiliations: L{dict}1486+ """1487+1488+@@ -277,7 +276,7 @@ class PubSubRequest(generic.Stanza):1489+ }1490+1491+ # Map request verb to request iq type and subelement name1492+- _verbRequestMap = dict(((v, k) for k, v in iteritems(_requestVerbMap)))1493++ _verbRequestMap = dict(((v, k) for k, v in _requestVerbMap.items()))1494+1495+ # Map request verb to parameter handler names1496+ _parameters = {1497+@@ -487,7 +486,7 @@ class PubSubRequest(generic.Stanza):1498+ Render maximum items into an items request.1499+ """1500+ if self.maxItems:1501+- verbElement['max_items'] = unicode(self.maxItems)1502++ verbElement['max_items'] = str(self.maxItems)1503+1504+1505+ def _parse_subidOrNone(self, verbElement):1506+@@ -648,7 +647,7 @@ class PubSubEvent(object):1507+ @param recipient: The entity to which the notification was sent.1508+ @type recipient: L{wokkel.pubsub.ItemsEvent}1509+ @param nodeIdentifier: Identifier of the node the event pertains to.1510+- @type nodeIdentifier: L{unicode}1511++ @type nodeIdentifier: L{str}1512+ @param headers: SHIM headers, see L{wokkel.shim.extractHeaders}.1513+ @type headers: L{dict}1514+ """1515+@@ -772,7 +771,7 @@ class PubSubClient(XMPPHandler):1516+ @param service: The publish subscribe service to create the node at.1517+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}1518+ @param nodeIdentifier: Optional suggestion for the id of the node.1519+- @type nodeIdentifier: L{unicode}1520++ @type nodeIdentifier: L{str}1521+ @param options: Optional node configuration options.1522+ @type options: L{dict}1523+ """1524+@@ -807,7 +806,7 @@ class PubSubClient(XMPPHandler):1525+ @param service: The publish subscribe service to delete the node from.1526+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}1527+ @param nodeIdentifier: The identifier of the node.1528+- @type nodeIdentifier: L{unicode}1529++ @type nodeIdentifier: L{str}1530+ """1531+ request = PubSubRequest('delete')1532+ request.recipient = service1533+@@ -825,7 +824,7 @@ class PubSubClient(XMPPHandler):1534+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}1535+1536+ @param nodeIdentifier: The identifier of the node.1537+- @type nodeIdentifier: L{unicode}1538++ @type nodeIdentifier: L{str}1539+1540+ @param subscriber: The entity to subscribe to the node. This entity1541+ will get notifications of new published items.1542+@@ -877,13 +876,13 @@ class PubSubClient(XMPPHandler):1543+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}1544+1545+ @param nodeIdentifier: The identifier of the node.1546+- @type nodeIdentifier: L{unicode}1547++ @type nodeIdentifier: L{str}1548+1549+ @param subscriber: The entity to unsubscribe from the node.1550+ @type subscriber: L{JID<twisted.words.protocols.jabber.jid.JID>}1551+1552+ @param subscriptionIdentifier: Optional subscription identifier.1553+- @type subscriptionIdentifier: L{unicode}1554++ @type subscriptionIdentifier: L{str}1555+ """1556+ request = PubSubRequest('unsubscribe')1557+ request.recipient = service1558+@@ -901,7 +900,7 @@ class PubSubClient(XMPPHandler):1559+ @param service: The publish subscribe service that keeps the node.1560+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}1561+ @param nodeIdentifier: The identifier of the node.1562+- @type nodeIdentifier: L{unicode}1563++ @type nodeIdentifier: L{str}1564+ @param items: Optional list of L{Item}s to publish.1565+ @type items: L{list}1566+ """1567+@@ -922,7 +921,7 @@ class PubSubClient(XMPPHandler):1568+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}1569+1570+ @param nodeIdentifier: The identifier of the node.1571+- @type nodeIdentifier: L{unicode}1572++ @type nodeIdentifier: L{str}1573+1574+ @param maxItems: Optional limit on the number of retrieved items.1575+ @type maxItems: L{int}1576+@@ -930,10 +929,10 @@ class PubSubClient(XMPPHandler):1577+ @param subscriptionIdentifier: Optional subscription identifier. In1578+ case the node has been subscribed to multiple times, this narrows1579+ the results to the specific subscription.1580+- @type subscriptionIdentifier: L{unicode}1581++ @type subscriptionIdentifier: L{str}1582+1583+ @param itemIdentifiers: Identifiers of the items to be retrieved.1584+- @type itemIdentifiers: L{set} of L{unicode}1585++ @type itemIdentifiers: L{set} of L{str}1586+ """1587+ request = PubSubRequest('items')1588+ request.recipient = service1589+@@ -965,13 +964,13 @@ class PubSubClient(XMPPHandler):1590+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}1591+1592+ @param nodeIdentifier: The identifier of the node.1593+- @type nodeIdentifier: L{unicode}1594++ @type nodeIdentifier: L{str}1595+1596+ @param subscriber: The entity subscribed to the node.1597+ @type subscriber: L{JID<twisted.words.protocols.jabber.jid.JID>}1598+1599+ @param subscriptionIdentifier: Optional subscription identifier.1600+- @type subscriptionIdentifier: L{unicode}1601++ @type subscriptionIdentifier: L{str}1602+1603+ @rtype: L{data_form.Form}1604+ """1605+@@ -1002,7 +1001,7 @@ class PubSubClient(XMPPHandler):1606+ @type service: L{JID<twisted.words.protocols.jabber.jid.JID>}1607+1608+ @param nodeIdentifier: The identifier of the node.1609+- @type nodeIdentifier: L{unicode}1610++ @type nodeIdentifier: L{str}1611+1612+ @param subscriber: The entity subscribed to the node.1613+ @type subscriber: L{JID<twisted.words.protocols.jabber.jid.JID>}1614+@@ -1011,7 +1010,7 @@ class PubSubClient(XMPPHandler):1615+ @type options: L{dict}.1616+1617+ @param subscriptionIdentifier: Optional subscription identifier.1618+- @type subscriptionIdentifier: L{unicode}1619++ @type subscriptionIdentifier: L{str}1620+ """1621+ request = PubSubRequest('optionsSet')1622+ request.recipient = service1623+@@ -1356,7 +1355,7 @@ class PubSubService(XMPPHandler, IQHandlerMixin):1624+ if request.nodeIdentifier:1625+ affiliations['node'] = request.nodeIdentifier1626+1627+- for entity, affiliation in iteritems(result):1628++ for entity, affiliation in result.items():1629+ item = affiliations.addElement('affiliation')1630+ item['jid'] = entity.full()1631+ item['affiliation'] = affiliation1632+diff --git a/wokkel/server.py b/wokkel/server.py1633+index 54517a2..fbd8452 1006441634+--- a/wokkel/server.py1635++++ b/wokkel/server.py1636+@@ -22,7 +22,6 @@ from zope.interface import implementer1637+ from twisted.internet import defer, reactor1638+ from twisted.names.srvconnect import SRVConnector1639+ from twisted.python import log, randbytes1640+-from twisted.python.compat import iteritems, unicode1641+ from twisted.words.protocols.jabber import error, ijabber, jid, xmlstream1642+ from twisted.words.xish import domish1643+1644+@@ -40,15 +39,15 @@ def generateKey(secret, receivingServer, originatingServer, streamID):1645+1646+ @param secret: the shared secret known to the Originating Server and1647+ Authoritive Server.1648+- @type secret: L{unicode}1649++ @type secret: L{str}1650+ @param receivingServer: the Receiving Server host name.1651+- @type receivingServer: L{unicode}1652++ @type receivingServer: L{str}1653+ @param originatingServer: the Originating Server host name.1654+- @type originatingServer: L{unicode}1655++ @type originatingServer: L{str}1656+ @param streamID: the Stream ID as generated by the Receiving Server.1657+- @type streamID: L{unicode}1658++ @type streamID: L{str}1659+ @return: hexadecimal digest of the generated key.1660+- @type: C{str}1661++ @type: L{str}1662+ """1663+1664+ hashObject = sha256()1665+@@ -340,7 +339,7 @@ class XMPPServerListenAuthenticator(xmlstream.ListenAuthenticator):1666+ try:1667+ if xmlstream.NS_STREAMS != rootElement.uri or \1668+ self.namespace != self.xmlstream.namespace or \1669+- ('db', NS_DIALBACK) not in iteritems(rootElement.localPrefixes):1670++ ('db', NS_DIALBACK) not in rootElement.localPrefixes.items():1671+ raise error.StreamError('invalid-namespace')1672+1673+ if targetDomain and targetDomain not in self.service.domains:1674+@@ -379,7 +378,7 @@ class XMPPServerListenAuthenticator(xmlstream.ListenAuthenticator):1675+ raise error.StreamError('invalid-from')1676+1677+ streamID = verify.getAttribute('id', '')1678+- key = unicode(verify)1679++ key = str(verify)1680+1681+ calculatedKey = generateKey(self.service.secret, receivingServer,1682+ originatingServer, streamID)1683+@@ -415,7 +414,7 @@ class XMPPServerListenAuthenticator(xmlstream.ListenAuthenticator):1684+1685+ receivingServer = result['to']1686+ originatingServer = result['from']1687+- key = unicode(result)1688++ key = str(result)1689+1690+ d = self.service.validateConnection(receivingServer, originatingServer,1691+ self.xmlstream.sid, key)1692+diff --git a/wokkel/shim.py b/wokkel/shim.py1693+index 3b12349..85a0848 1006441694+--- a/wokkel/shim.py1695++++ b/wokkel/shim.py1696+@@ -12,7 +12,6 @@ U{XEP-0131<http://xmpp.org/extensions/xep-0131.html>}.1697+1698+ from __future__ import division, absolute_import1699+1700+-from twisted.python.compat import unicode1701+ from twisted.words.xish import domish1702+1703+ NS_SHIM = "http://jabber.org/protocol/shim"1704+@@ -30,7 +29,7 @@ def extractHeaders(stanza):1705+ @param stanza: The stanza to extract headers from.1706+ @type stanza: L{Element<twisted.words.xish.domish.Element>}1707+ @return: Headers as a mapping from header name to a list of values.1708+- @rtype: C{dict}1709++ @rtype: L{dict}1710+ """1711+ headers = {}1712+1713+@@ -38,6 +37,6 @@ def extractHeaders(stanza):1714+ 'headers', NS_SHIM):1715+ for header in domish.generateElementsQNamed(element.children,1716+ 'header', NS_SHIM):1717+- headers.setdefault(header['name'], []).append(unicode(header))1718++ headers.setdefault(header['name'], []).append(str(header))1719+1720+ return headers1721+diff --git a/wokkel/subprotocols.py b/wokkel/subprotocols.py1722+index f0a6090..b4cde14 1006441723+--- a/wokkel/subprotocols.py1724++++ b/wokkel/subprotocols.py1725+@@ -14,7 +14,6 @@ from zope.interface import implementer1726+ from twisted.internet import defer1727+ from twisted.internet.error import ConnectionDone1728+ from twisted.python import failure, log1729+-from twisted.python.compat import iteritems, itervalues1730+ from twisted.python.deprecate import deprecatedModuleAttribute1731+ from twisted.words.protocols.jabber import error, ijabber, xmlstream1732+ from twisted.words.protocols.jabber.xmlstream import toResponse1733+@@ -130,15 +129,15 @@ class StreamManager(XMPPHandlerCollection):1734+ @ivar xmlstream: currently managed XML stream1735+ @type xmlstream: L{XmlStream}1736+ @ivar logTraffic: if true, log all traffic.1737+- @type logTraffic: C{bool}1738++ @type logTraffic: L{bool}1739+ @ivar _initialized: Whether the stream represented by L{xmlstream} has1740+ been initialized. This is used when caching outgoing1741+ stanzas.1742+- @type _initialized: C{bool}1743++ @type _initialized: L{bool}1744+ @ivar _packetQueue: internal buffer of unsent data. See L{send} for details.1745+ @type _packetQueue: L{list}1746+ @ivar timeout: Default IQ request timeout in seconds.1747+- @type timeout: C{int}1748++ @type timeout: L{int}1749+ @ivar _reactor: A provider of L{IReactorTime} to track timeouts.1750+ """1751+ timeout = None1752+@@ -277,7 +276,7 @@ class StreamManager(XMPPHandlerCollection):1753+ # deferreds will never be fired.1754+ iqDeferreds = self._iqDeferreds1755+ self._iqDeferreds = {}1756+- for d in itervalues(iqDeferreds):1757++ for d in iqDeferreds.values():1758+ d.errback(reason)1759+1760+1761+@@ -420,7 +419,7 @@ class IQHandlerMixin(object):1762+1763+ @cvar iqHandlers: Mapping from XPath queries (as a string) to the method1764+ name that will handle requests that match the query.1765+- @type iqHandlers: C{dict}1766++ @type iqHandlers: L{dict}1767+ """1768+1769+ iqHandlers = None1770+@@ -455,7 +454,7 @@ class IQHandlerMixin(object):1771+ return error.StanzaError('internal-server-error').toResponse(iq)1772+1773+ handler = None1774+- for queryString, method in iteritems(self.iqHandlers):1775++ for queryString, method in self.iqHandlers.items():1776+ if xpath.internQuery(queryString).matches(iq):1777+ handler = getattr(self, method)1778+1779+diff --git a/wokkel/test/helpers.py b/wokkel/test/helpers.py1780+index 102b3dc..c76a4a0 1006441781+--- a/wokkel/test/helpers.py1782++++ b/wokkel/test/helpers.py1783+@@ -8,7 +8,6 @@ Unit test helpers.1784+ from __future__ import division, absolute_import1785+1786+ from twisted.internet import defer1787+-from twisted.python.compat import iteritems1788+ from twisted.words.xish import xpath1789+ from twisted.words.xish.utility import EventDispatcher1790+1791+@@ -79,14 +78,14 @@ class TestableRequestHandlerMixin(object):1792+ Find a handler and call it directly.1793+1794+ @param xml: XML stanza that may yield a handler being called.1795+- @type xml: C{str}.1796++ @type xml: L{str}.1797+ @return: Deferred that fires with the result of a handler for this1798+ stanza. If no handler was found, the deferred has its errback1799+ called with a C{NotImplementedError} exception.1800+ """1801+ handler = None1802+ iq = parseXml(xml)1803+- for queryString, method in iteritems(self.service.iqHandlers):1804++ for queryString, method in self.service.iqHandlers.items():1805+ if xpath.internQuery(queryString).matches(iq):1806+ handler = getattr(self.service, method)1807+1808+diff --git a/wokkel/test/test_client.py b/wokkel/test/test_client.py1809+index ef367f7..ef9adfd 1006441810+--- a/wokkel/test/test_client.py1811++++ b/wokkel/test/test_client.py1812+@@ -8,6 +8,7 @@ Tests for L{wokkel.client}.1813+ from __future__ import division, absolute_import1814+1815+ from twisted.internet import defer1816++from twisted.python.compat import nativeString1817+ from twisted.trial import unittest1818+ from twisted.words.protocols.jabber import xmlstream1819+ from twisted.words.protocols.jabber.client import XMPPAuthenticator1820+@@ -152,7 +153,7 @@ class ClientCreatorTest(unittest.TestCase):1821+1822+ def cb(connector):1823+ self.assertEqual('xmpp-client', connector.service)1824+- self.assertEqual('example.org', connector.domain)1825++ self.assertEqual('example.org', nativeString(connector.domain))1826+ self.assertEqual(factory, connector.factory)1827+1828+ def connect(connector):1829+diff --git a/wokkel/test/test_data_form.py b/wokkel/test/test_data_form.py1830+index 60e36f4..246f1c5 1006441831+--- a/wokkel/test/test_data_form.py1832++++ b/wokkel/test/test_data_form.py1833+@@ -10,7 +10,6 @@ from __future__ import division, absolute_import1834+ from zope.interface import verify1835+ from zope.interface.common.mapping import IIterableMapping1836+1837+-from twisted.python.compat import unicode, _PY31838+ from twisted.trial import unittest1839+ from twisted.words.xish import domish1840+ from twisted.words.protocols.jabber import jid1841+@@ -34,7 +33,7 @@ class OptionTest(unittest.TestCase):1842+ self.assertEqual('option', element.name)1843+ self.assertEqual(NS_X_DATA, element.uri)1844+ self.assertEqual(NS_X_DATA, element.value.uri)1845+- self.assertEqual('value', unicode(element.value))1846++ self.assertEqual('value', str(element.value))1847+ self.assertFalse(element.hasAttribute('label'))1848+1849+1850+@@ -48,7 +47,7 @@ class OptionTest(unittest.TestCase):1851+ self.assertEqual('option', element.name)1852+ self.assertEqual(NS_X_DATA, element.uri)1853+ self.assertEqual(NS_X_DATA, element.value.uri)1854+- self.assertEqual('value', unicode(element.value))1855++ self.assertEqual('value', str(element.value))1856+ self.assertEqual('label', element['label'])1857+1858+1859+@@ -225,7 +224,7 @@ class FieldTest(unittest.TestCase):1860+ child = element.children[0]1861+ self.assertEqual('desc', child.name)1862+ self.assertEqual(NS_X_DATA, child.uri)1863+- self.assertEqual(u'My desc', unicode(child))1864++ self.assertEqual(u'My desc', str(child))1865+1866+1867+ def test_toElementRequired(self):1868+@@ -248,7 +247,7 @@ class FieldTest(unittest.TestCase):1869+ field = data_form.Field(fieldType='jid-single', var='test',1870+ value=jid.JID(u'test@example.org'))1871+ element = field.toElement()1872+- self.assertEqual(u'test@example.org', unicode(element.value))1873++ self.assertEqual(u'test@example.org', str(element.value))1874+1875+1876+ def test_toElementJIDTextSingle(self):1877+@@ -258,7 +257,7 @@ class FieldTest(unittest.TestCase):1878+ field = data_form.Field(fieldType='text-single', var='test',1879+ value=jid.JID(u'test@example.org'))1880+ element = field.toElement()1881+- self.assertEqual(u'test@example.org', unicode(element.value))1882++ self.assertEqual(u'test@example.org', str(element.value))1883+1884+1885+ def test_toElementBoolean(self):1886+@@ -268,7 +267,7 @@ class FieldTest(unittest.TestCase):1887+ field = data_form.Field(fieldType='boolean', var='test',1888+ value=True)1889+ element = field.toElement()1890+- self.assertEqual(u'true', unicode(element.value))1891++ self.assertEqual(u'true', str(element.value))1892+1893+1894+ def test_toElementBooleanTextSingle(self):1895+@@ -277,7 +276,7 @@ class FieldTest(unittest.TestCase):1896+ """1897+ field = data_form.Field(var='test', value=True)1898+ element = field.toElement()1899+- self.assertEqual(u'true', unicode(element.value))1900++ self.assertEqual(u'true', str(element.value))1901+1902+1903+ def test_toElementNoType(self):1904+@@ -396,7 +395,7 @@ class FieldTest(unittest.TestCase):1905+1906+ def test_fromElementValueTextSingle(self):1907+ """1908+- Parsed text-single field values should be of type C{unicode}.1909++ Parsed text-single field values should be of type L{str}.1910+ """1911+ element = domish.Element((NS_X_DATA, 'field'))1912+ element['type'] = 'text-single'1913+@@ -407,7 +406,7 @@ class FieldTest(unittest.TestCase):1914+1915+ def test_fromElementValueJID(self):1916+ """1917+- Parsed jid-single field values should be of type C{unicode}.1918++ Parsed jid-single field values should be of type L{str}.1919+ """1920+ element = domish.Element((NS_X_DATA, 'field'))1921+ element['type'] = 'jid-single'1922+@@ -418,7 +417,7 @@ class FieldTest(unittest.TestCase):1923+1924+ def test_fromElementValueJIDMalformed(self):1925+ """1926+- Parsed jid-single field values should be of type C{unicode}.1927++ Parsed jid-single field values should be of type L{str}.1928+1929+ No validation should be done at this point, so invalid JIDs should1930+ also be passed as-is.1931+@@ -432,7 +431,7 @@ class FieldTest(unittest.TestCase):1932+1933+ def test_fromElementValueBoolean(self):1934+ """1935+- Parsed boolean field values should be of type C{unicode}.1936++ Parsed boolean field values should be of type L{str}.1937+ """1938+ element = domish.Element((NS_X_DATA, 'field'))1939+ element['type'] = 'boolean'1940+@@ -561,7 +560,7 @@ class FormTest(unittest.TestCase):1941+ title = elements[0]1942+ self.assertEqual('title', title.name)1943+ self.assertEqual(NS_X_DATA, title.uri)1944+- self.assertEqual('Bot configuration', unicode(title))1945++ self.assertEqual('Bot configuration', str(title))1946+1947+1948+ def test_toElementInstructions(self):1949+@@ -576,7 +575,7 @@ class FormTest(unittest.TestCase):1950+ instructions = elements[0]1951+ self.assertEqual('instructions', instructions.name)1952+ self.assertEqual(NS_X_DATA, instructions.uri)1953+- self.assertEqual('Fill out this form!', unicode(instructions))1954++ self.assertEqual('Fill out this form!', str(instructions))1955+1956+1957+ def test_toElementInstructionsMultiple(self):1958+@@ -593,10 +592,10 @@ class FormTest(unittest.TestCase):1959+ instructions2 = elements[1]1960+ self.assertEqual('instructions', instructions1.name)1961+ self.assertEqual(NS_X_DATA, instructions1.uri)1962+- self.assertEqual('Fill out this form!', unicode(instructions1))1963++ self.assertEqual('Fill out this form!', str(instructions1))1964+ self.assertEqual('instructions', instructions2.name)1965+ self.assertEqual(NS_X_DATA, instructions2.uri)1966+- self.assertEqual('no really', unicode(instructions2))1967++ self.assertEqual('no really', str(instructions2))1968+1969+1970+ def test_toElementFormType(self):1971+@@ -613,7 +612,7 @@ class FormTest(unittest.TestCase):1972+ self.assertEqual(NS_X_DATA, formTypeField.uri)1973+ self.assertEqual('FORM_TYPE', formTypeField['var'])1974+ self.assertEqual('hidden', formTypeField['type'])1975+- self.assertEqual('jabber:bot', unicode(formTypeField.value))1976++ self.assertEqual('jabber:bot', str(formTypeField.value))1977+1978+1979+ def test_toElementFields(self):1980+@@ -1091,7 +1090,7 @@ class FormTest(unittest.TestCase):1981+ self.assertNotIn('features', form)1982+1983+1984+- def test_iterkeys(self):1985++ def test_keys(self):1986+ """1987+ Iterating over the keys of a form yields all field names.1988+ """1989+@@ -1101,10 +1100,10 @@ class FormTest(unittest.TestCase):1990+ values=['news', 'search'])]1991+ form = data_form.Form('submit', fields=fields)1992+ self.assertEqual(set(['botname', 'public', 'features']),1993+- set(form.iterkeys()))1994++ set(form.keys()))1995+1996+1997+- def test_itervalues(self):1998++ def test_values(self):1999+ """2000+ Iterating over the values of a form yields all field values.2001+ """2002+@@ -1112,63 +1111,19 @@ class FormTest(unittest.TestCase):2003+ data_form.Field('boolean', var='public', value=True)]2004+ form = data_form.Form('submit', fields=fields)2005+ self.assertEqual(set(['The Jabber Bot', True]),2006+- set(form.itervalues()))2007+-2008+-2009+- def test_iteritems(self):2010+- """2011+- Iterating over the values of a form yields all item tuples.2012+- """2013+- fields = [data_form.Field(var='botname', value='The Jabber Bot'),2014+- data_form.Field('boolean', var='public', value=True)]2015+- form = data_form.Form('submit', fields=fields)2016+- self.assertEqual(set([('botname', 'The Jabber Bot'),2017+- ('public', True)]),2018+- set(form.iteritems()))2019+-2020+-2021+- def test_keys(self):2022+- """2023+- Getting the keys of a form yields a list of field names.2024+- """2025+- fields = [data_form.Field(var='botname', value='The Jabber Bot'),2026+- data_form.Field('boolean', var='public', value=True),2027+- data_form.Field('list-multi', var='features',2028+- values=['news', 'search'])]2029+- form = data_form.Form('submit', fields=fields)2030+- keys = form.keys()2031+- if not _PY3:2032+- self.assertIsInstance(keys, list)2033+- self.assertEqual(set(['botname', 'public', 'features']),2034+- set(keys))2035+-2036+-2037+- def test_values(self):2038+- """2039+- Getting the values of a form yields a list of field values.2040+- """2041+- fields = [data_form.Field(var='botname', value='The Jabber Bot'),2042+- data_form.Field('boolean', var='public', value=True)]2043+- form = data_form.Form('submit', fields=fields)2044+- values = form.values()2045+- if not _PY3:2046+- self.assertIsInstance(values, list)2047+- self.assertEqual(set(['The Jabber Bot', True]), set(values))2048++ set(form.values()))2049+2050+2051+ def test_items(self):2052+ """2053+- Iterating over the values of a form yields a list of all item tuples.2054++ Iterating over the values of a form yields all item tuples.2055+ """2056+ fields = [data_form.Field(var='botname', value='The Jabber Bot'),2057+ data_form.Field('boolean', var='public', value=True)]2058+ form = data_form.Form('submit', fields=fields)2059+- items = form.items()2060+- if not _PY3:2061+- self.assertIsInstance(items, list)2062+ self.assertEqual(set([('botname', 'The Jabber Bot'),2063+ ('public', True)]),2064+- set(items))2065++ set(form.items()))2066+2067+2068+ def test_getValues(self):2069+diff --git a/wokkel/test/test_generic.py b/wokkel/test/test_generic.py2070+index 94c39e5..4e4ab45 1006442071+--- a/wokkel/test/test_generic.py2072++++ b/wokkel/test/test_generic.py2073+@@ -7,19 +7,12 @@ Tests for L{wokkel.generic}.2074+2075+ from __future__ import division, absolute_import2076+2077+-import re2078+-2079+ from zope.interface.verify import verifyObject2080+2081+-from twisted.python import deprecate2082+-from twisted.python.compat import unicode2083+ from twisted.trial import unittest2084+-from twisted.trial.util import suppress as SUPPRESS2085+ from twisted.words.xish import domish2086+ from twisted.words.protocols.jabber.jid import JID2087+2088+-from incremental import Version2089+-2090+ from wokkel import generic2091+ from wokkel.iwokkel import IDisco2092+ from wokkel.test.helpers import XmlStreamStub2093+@@ -66,11 +59,11 @@ class VersionHandlerTest(unittest.TestCase):2094+ elements = list(domish.generateElementsQNamed(response.query.children,2095+ 'name', NS_VERSION))2096+ self.assertEquals(1, len(elements))2097+- self.assertEquals('Test', unicode(elements[0]))2098++ self.assertEquals('Test', str(elements[0]))2099+ elements = list(domish.generateElementsQNamed(response.query.children,2100+ 'version', NS_VERSION))2101+ self.assertEquals(1, len(elements))2102+- self.assertEquals('0.1.0', unicode(elements[0]))2103++ self.assertEquals('0.1.0', str(elements[0]))2104+2105+2106+2107+@@ -314,67 +307,3 @@ class RequestTest(unittest.TestCase):2108+2109+ request = SetRequest()2110+ self.assertEqual('set', request.stanzaType)2111+-2112+-2113+-2114+-class PrepareIDNNameTests(unittest.TestCase):2115+- """2116+- Tests for L{wokkel.generic.prepareIDNName}.2117+- """2118+-2119+- suppress = [SUPPRESS(category=DeprecationWarning,2120+- message=re.escape(2121+- deprecate.getDeprecationWarningString(2122+- generic.prepareIDNName,2123+- Version("wokkel", 18, 0, 0),2124+- replacement="unicode.encode('idna')")))]2125+-2126+-2127+- def test_deprecated(self):2128+- """2129+- prepareIDNName is deprecated.2130+- """2131+- self.callDeprecated((Version("wokkel", 18, 0, 0),2132+- "unicode.encode('idna')"),2133+- generic.prepareIDNName, ("example.com"))2134+- test_deprecated.suppress = []2135+-2136+-2137+- def test_unicode(self):2138+- """2139+- A unicode all-ASCII name is converted to an ASCII byte string.2140+- """2141+- name = u"example.com"2142+- result = generic.prepareIDNName(name)2143+- self.assertEqual(b"example.com", result)2144+-2145+-2146+- def test_unicodeNonASCII(self):2147+- """2148+- A unicode with non-ASCII is converted to its ACE equivalent.2149+- """2150+- name = u"\u00e9chec.example.com"2151+- result = generic.prepareIDNName(name)2152+- self.assertEqual(b"xn--chec-9oa.example.com", result)2153+-2154+-2155+- def test_unicodeHalfwidthIdeographicFullStop(self):2156+- """2157+- Exotic dots in unicode names are converted to Full Stop.2158+- """2159+- name = u"\u00e9chec.example\uff61com"2160+- result = generic.prepareIDNName(name)2161+- self.assertEqual(b"xn--chec-9oa.example.com", result)2162+-2163+-2164+- def test_unicodeTrailingDot(self):2165+- """2166+- Unicode names with trailing dots retain the trailing dot.2167+-2168+- L{encodings.idna.ToASCII} doesn't allow the empty string as the input,2169+- hence the implementation needs to strip a trailing dot, and re-add it2170+- after encoding the labels.2171+- """2172+- name = u"example.com."2173+- result = generic.prepareIDNName(name)2174+- self.assertEqual(b"example.com.", result)2175+diff --git a/wokkel/test/test_muc.py b/wokkel/test/test_muc.py2176+index f690d05..282a8a1 1006442177+--- a/wokkel/test/test_muc.py2178++++ b/wokkel/test/test_muc.py2179+@@ -14,7 +14,6 @@ from zope.interface import verify2180+2181+ from twisted.trial import unittest2182+ from twisted.internet import defer, task2183+-from twisted.python.compat import iteritems, unicode2184+ from twisted.words.xish import domish, xpath2185+ from twisted.words.protocols.jabber.jid import JID2186+ from twisted.words.protocols.jabber.error import StanzaError2187+@@ -81,7 +80,7 @@ class StatusCodeTest(unittest.TestCase):2188+ 332: 'removed-shutdown',2189+ }2190+2191+- for code, condition in iteritems(codes):2192++ for code, condition in codes.items():2193+ constantName = condition.replace('-', '_').upper()2194+ self.assertEqual(getattr(muc.STATUS_CODE, constantName),2195+ muc.STATUS_CODE.lookupByValue(code))2196+@@ -757,7 +756,7 @@ class MUCClientProtocolTest(unittest.TestCase):2197+ self.assertEquals('message', message.name)2198+ self.assertEquals(self.roomJID.full(), message.getAttribute('to'))2199+ self.assertEquals('groupchat', message.getAttribute('type'))2200+- self.assertEquals(u'This is a test', unicode(message.body))2201++ self.assertEquals(u'This is a test', str(message.body))2202+2203+2204+ def test_chat(self):2205+@@ -773,7 +772,7 @@ class MUCClientProtocolTest(unittest.TestCase):2206+ self.assertEquals('message', message.name)2207+ self.assertEquals(otherOccupantJID.full(), message.getAttribute('to'))2208+ self.assertEquals('chat', message.getAttribute('type'))2209+- self.assertEquals(u'This is a test', unicode(message.body))2210++ self.assertEquals(u'This is a test', str(message.body))2211+2212+2213+ def test_subject(self):2214+@@ -787,7 +786,7 @@ class MUCClientProtocolTest(unittest.TestCase):2215+ self.assertEquals('message', message.name)2216+ self.assertEquals(self.roomJID.full(), message.getAttribute('to'))2217+ self.assertEquals('groupchat', message.getAttribute('type'))2218+- self.assertEquals(u'This is a test', unicode(message.subject))2219++ self.assertEquals(u'This is a test', str(message.subject))2220+2221+2222+ def test_invite(self):2223+@@ -806,7 +805,7 @@ class MUCClientProtocolTest(unittest.TestCase):2224+ self.assertEquals(muc.NS_MUC_USER, message.x.invite.uri)2225+ self.assertEquals(invitee.full(), message.x.invite.getAttribute('to'))2226+ self.assertEquals(muc.NS_MUC_USER, message.x.invite.reason.uri)2227+- self.assertEquals(u'This is a test', unicode(message.x.invite.reason))2228++ self.assertEquals(u'This is a test', str(message.x.invite.reason))2229+2230+2231+ def test_getRegisterForm(self):2232+@@ -1399,7 +1398,7 @@ class MUCClientProtocolTest(unittest.TestCase):2233+ nodes = xpath.queryForNodes(query, iq)2234+ self.assertNotIdentical(None, nodes, 'Bad configure request')2235+ destroy = nodes[0]2236+- self.assertEquals('Time to leave', unicode(destroy.reason))2237++ self.assertEquals('Time to leave', str(destroy.reason))2238+2239+ response = toResponse(iq, 'result')2240+ self.stub.send(response)2241+diff --git a/wokkel/test/test_server.py b/wokkel/test/test_server.py2242+index 3e3c923..1efb6e5 1006442243+--- a/wokkel/test/test_server.py2244++++ b/wokkel/test/test_server.py2245+@@ -8,7 +8,11 @@ Tests for L{wokkel.server}.2246+ from __future__ import division, absolute_import2247+ from twisted.internet import defer2248+ from twisted.python import failure2249+-from twisted.test.proto_helpers import StringTransport2250++try:2251++ from twisted.internet.testing import StringTransport2252++except ImportError:2253++ from twisted.test.proto_helpers import StringTransport2254++2255+ from twisted.trial import unittest2256+ from twisted.words.protocols.jabber import error, jid, xmlstream2257+ from twisted.words.xish import domish2258+diff --git a/wokkel/test/test_shim.py b/wokkel/test/test_shim.py2259+index ded4679..d3b76cf 1006442260+--- a/wokkel/test/test_shim.py2261++++ b/wokkel/test/test_shim.py2262+@@ -9,7 +9,6 @@ Tests for {wokkel.shim}.2263+2264+ from __future__ import division, absolute_import2265+2266+-from twisted.python.compat import unicode2267+ from twisted.trial import unittest2268+2269+ from wokkel import shim2270+@@ -36,7 +35,7 @@ class HeadersTest(unittest.TestCase):2271+ self.assertEquals(NS_SHIM, header.uri)2272+ self.assertEquals('header', header.name)2273+ self.assertEquals('Urgency', header['name'])2274+- self.assertEquals('high', unicode(header))2275++ self.assertEquals('high', str(header))2276+2277+2278+ def test_headerRepeated(self):2279+@@ -47,7 +46,7 @@ class HeadersTest(unittest.TestCase):2280+ ('Collection', 'node2')])2281+ elements = list(headers.elements())2282+ self.assertEquals(2, len(elements))2283+- collections = set((unicode(element) for element in elements2284++ collections = set((str(element) for element in elements2285+ if element['name'] == 'Collection'))2286+ self.assertIn('node1', collections)2287+ self.assertIn('node2', collections)2288+diff --git a/wokkel/test/test_xmppim.py b/wokkel/test/test_xmppim.py2289+index faab8ed..0d4fdbf 1006442290+--- a/wokkel/test/test_xmppim.py2291++++ b/wokkel/test/test_xmppim.py2292+@@ -9,7 +9,6 @@ from __future__ import division, absolute_import2293+2294+ from twisted.internet import defer2295+ from twisted.trial import unittest2296+-from twisted.python.compat import unicode2297+ from twisted.words.protocols.jabber import error2298+ from twisted.words.protocols.jabber.jid import JID2299+ from twisted.words.protocols.jabber.xmlstream import toResponse2300+@@ -55,7 +54,7 @@ class PresenceClientProtocolTest(unittest.TestCase):2301+ self.assertEquals(None, presence.uri)2302+ self.assertEquals("user@example.com", presence.getAttribute('to'))2303+ self.assertEquals("unavailable", presence.getAttribute('type'))2304+- self.assertEquals("Disconnected", unicode(presence.status))2305++ self.assertEquals("Disconnected", str(presence.status))2306+2307+ def test_unavailableBroadcast(self):2308+ """2309+@@ -298,9 +297,9 @@ class PresenceProtocolTest(unittest.TestCase):2310+ element = self.output[-1]2311+ self.assertEquals("user@example.com", element.getAttribute('to'))2312+ self.assertIdentical(None, element.getAttribute('type'))2313+- self.assertEquals(u'chat', unicode(element.show))2314+- self.assertEquals(u'Talk to me!', unicode(element.status))2315+- self.assertEquals(u'50', unicode(element.priority))2316++ self.assertEquals(u'chat', str(element.show))2317++ self.assertEquals(u'Talk to me!', str(element.status))2318++ self.assertEquals(u'50', str(element.priority))2319+2320+ def test_availableLanguages(self):2321+ """2322+@@ -314,19 +313,19 @@ class PresenceProtocolTest(unittest.TestCase):2323+ element = self.output[-1]2324+ self.assertEquals("user@example.com", element.getAttribute('to'))2325+ self.assertIdentical(None, element.getAttribute('type'))2326+- self.assertEquals(u'chat', unicode(element.show))2327++ self.assertEquals(u'chat', str(element.show))2328+2329+ statuses = {}2330+ for status in element.elements():2331+ if status.name == 'status':2332+ lang = status.getAttribute((NS_XML, 'lang'))2333+- statuses[lang] = unicode(status)2334++ statuses[lang] = str(status)2335+2336+ self.assertIn(None, statuses)2337+ self.assertEquals(u'Talk to me!', statuses[None])2338+ self.assertIn('nl', statuses)2339+ self.assertEquals(u'Praat met me!', statuses['nl'])2340+- self.assertEquals(u'50', unicode(element.priority))2341++ self.assertEquals(u'50', str(element.priority))2342+2343+2344+ def test_availableSender(self):2345+@@ -363,7 +362,7 @@ class PresenceProtocolTest(unittest.TestCase):2346+ self.assertEquals(None, element.uri)2347+ self.assertEquals("user@example.com", element.getAttribute('to'))2348+ self.assertEquals("unavailable", element.getAttribute('type'))2349+- self.assertEquals("Disconnected", unicode(element.status))2350++ self.assertEquals("Disconnected", str(element.status))2351+2352+2353+ def test_unavailableBroadcast(self):2354+@@ -568,7 +567,7 @@ class RosterItemTest(unittest.TestCase):2355+ foundGroups = set()2356+ for child in element.elements():2357+ if child.uri == NS_ROSTER and child.name == 'group':2358+- foundGroups.add(unicode(child))2359++ foundGroups.add(str(child))2360+2361+ self.assertEqual(groups, foundGroups)2362+2363+diff --git a/wokkel/xmppim.py b/wokkel/xmppim.py2364+index e6af929..683577b 1006442365+--- a/wokkel/xmppim.py2366++++ b/wokkel/xmppim.py2367+@@ -15,7 +15,6 @@ from __future__ import division, absolute_import2368+ import warnings2369+2370+ from twisted.internet import defer2371+-from twisted.python.compat import iteritems, itervalues, unicode2372+ from twisted.words.protocols.jabber import error2373+ from twisted.words.protocols.jabber.jid import JID2374+ from twisted.words.xish import domish2375+@@ -48,20 +47,20 @@ class AvailablePresence(Presence):2376+ self.addElement('show', content=show)2377+2378+ if statuses is not None:2379+- for lang, status in iteritems(statuses):2380++ for lang, status in statuses.items():2381+ s = self.addElement('status', content=status)2382+ if lang:2383+ s[(NS_XML, "lang")] = lang2384+2385+ if priority != 0:2386+- self.addElement('priority', content=unicode(int(priority)))2387++ self.addElement('priority', content=str(int(priority)))2388+2389+ class UnavailablePresence(Presence):2390+ def __init__(self, to=None, statuses=None):2391+ Presence.__init__(self, to, type='unavailable')2392+2393+ if statuses is not None:2394+- for lang, status in iteritems(statuses):2395++ for lang, status in statuses.items():2396+ s = self.addElement('status', content=status)2397+ if lang:2398+ s[(NS_XML, "lang")] = lang2399+@@ -76,7 +75,7 @@ class PresenceClientProtocol(XMPPHandler):2400+ for element in presence.elements():2401+ if element.name == 'status':2402+ lang = element.getAttribute((NS_XML, 'lang'))2403+- text = unicode(element)2404++ text = str(element)2405+ statuses[lang] = text2406+ return statuses2407+2408+@@ -92,14 +91,14 @@ class PresenceClientProtocol(XMPPHandler):2409+ def _onPresenceAvailable(self, presence):2410+ entity = JID(presence["from"])2411+2412+- show = unicode(presence.show or '')2413++ show = str(presence.show or '')2414+ if show not in ['away', 'xa', 'chat', 'dnd']:2415+ show = None2416+2417+ statuses = self._getStatuses(presence)2418+2419+ try:2420+- priority = int(unicode(presence.priority or '')) or 02421++ priority = int(str(presence.priority or '')) or 02422+ except ValueError:2423+ priority = 02424+2425+@@ -133,14 +132,14 @@ class PresenceClientProtocol(XMPPHandler):2426+ @type entity: {JID}2427+ @param show: detailed presence information. One of C{'away'}, C{'xa'},2428+ C{'chat'}, C{'dnd'} or C{None}.2429+- @type show: C{str} or C{NoneType}2430++ @type show: L{str} or C{NoneType}2431+ @param statuses: dictionary of natural language descriptions of the2432+ availability status, keyed by the language2433+ descriptor. A status without a language2434+ specified, is keyed with C{None}.2435+- @type statuses: C{dict}2436++ @type statuses: L{dict}2437+ @param priority: priority level of the resource.2438+- @type priority: C{int}2439++ @type priority: L{int}2440+ """2441+2442+ def unavailableReceived(self, entity, statuses=None):2443+@@ -153,7 +152,7 @@ class PresenceClientProtocol(XMPPHandler):2444+ availability status, keyed by the language2445+ descriptor. A status without a language2446+ specified, is keyed with C{None}.2447+- @type statuses: C{dict}2448++ @type statuses: L{dict}2449+ """2450+2451+ def subscribedReceived(self, entity):2452+@@ -196,14 +195,14 @@ class PresenceClientProtocol(XMPPHandler):2453+ @type entity: {JID}2454+ @param show: optional detailed presence information. One of C{'away'},2455+ C{'xa'}, C{'chat'}, C{'dnd'}.2456+- @type show: C{str}2457++ @type show: L{str}2458+ @param statuses: dictionary of natural language descriptions of the2459+ availability status, keyed by the language2460+ descriptor. A status without a language2461+ specified, is keyed with C{None}.2462+- @type statuses: C{dict}2463++ @type statuses: L{dict}2464+ @param priority: priority level of the resource.2465+- @type priority: C{int}2466++ @type priority: L{int}2467+ """2468+ self.send(AvailablePresence(entity, show, statuses, priority))2469+2470+@@ -217,7 +216,7 @@ class PresenceClientProtocol(XMPPHandler):2471+ availability status, keyed by the language2472+ descriptor. A status without a language2473+ specified, is keyed with C{None}.2474+- @type statuses: C{dict}2475++ @type statuses: L{dict}2476+ """2477+ self.send(UnavailablePresence(entity, statuses))2478+2479+@@ -275,19 +274,19 @@ class AvailabilityPresence(BasePresence):2480+ L{SubscriptionPresence}).2481+2482+ @ivar available: The availability being communicated.2483+- @type available: C{bool}2484++ @type available: L{bool}2485+ @ivar show: More specific availability. Can be one of C{'chat'}, C{'away'},2486+ C{'xa'}, C{'dnd'} or C{None}.2487+- @type show: C{str} or C{NoneType}2488++ @type show: L{str} or C{NoneType}2489+ @ivar statuses: Natural language texts to detail the (un)availability.2490+ These are represented as a mapping from language code2491+- (C{str} or C{None}) to the corresponding text (C{unicode}).2492++ (L{str} or C{None}) to the corresponding text (L{str}).2493+ If the key is C{None}, the associated text is in the2494+ default language.2495+- @type statuses: C{dict}2496++ @type statuses: L{dict}2497+ @ivar priority: Priority level for this resource. Must be between -128 and2498+ 127. Defaults to 0.2499+- @type priority: C{int}2500++ @type priority: L{int}2501+ """2502+2503+ childParsers = {(None, 'show'): '_childParser_show',2504+@@ -309,7 +308,7 @@ class AvailabilityPresence(BasePresence):2505+ if None in self.statuses:2506+ return self.statuses[None]2507+ elif self.statuses:2508+- for status in itervalues(self.status):2509++ for status in self.status.values():2510+ return status2511+ else:2512+ return None2513+@@ -318,20 +317,20 @@ class AvailabilityPresence(BasePresence):2514+2515+2516+ def _childParser_show(self, element):2517+- show = unicode(element)2518++ show = str(element)2519+ if show in ('chat', 'away', 'xa', 'dnd'):2520+ self.show = show2521+2522+2523+ def _childParser_status(self, element):2524+ lang = element.getAttribute((NS_XML, 'lang'), None)2525+- text = unicode(element)2526++ text = str(element)2527+ self.statuses[lang] = text2528+2529+2530+ def _childParser_priority(self, element):2531+ try:2532+- self.priority = int(unicode(element))2533++ self.priority = int(str(element))2534+ except ValueError:2535+ pass2536+2537+@@ -353,9 +352,9 @@ class AvailabilityPresence(BasePresence):2538+ if self.show in ('chat', 'away', 'xa', 'dnd'):2539+ presence.addElement('show', content=self.show)2540+ if self.priority != 0:2541+- presence.addElement('priority', content=unicode(self.priority))2542++ presence.addElement('priority', content=str(self.priority))2543+2544+- for lang, text in iteritems(self.statuses):2545++ for lang, text in self.statuses.items():2546+ status = presence.addElement('status', content=text)2547+ if lang:2548+ status[(NS_XML, 'lang')] = lang2549+@@ -400,7 +399,7 @@ class BasePresenceProtocol(XMPPHandler):2550+2551+ @cvar presenceTypeParserMap: Maps presence stanza types to their respective2552+ stanza parser classes (derived from L{Stanza}).2553+- @type presenceTypeParserMap: C{dict}2554++ @type presenceTypeParserMap: L{dict}2555+ """2556+2557+ presenceTypeParserMap = {}2558+@@ -515,15 +514,15 @@ class PresenceProtocol(BasePresenceProtocol):2559+2560+ @param show: Optional detailed presence information. One of C{'away'},2561+ C{'xa'}, C{'chat'}, C{'dnd'}.2562+- @type show: C{str}2563++ @type show: L{str}2564+2565+ @param statuses: Mapping of natural language descriptions of the2566+ availability status, keyed by the language descriptor. A status2567+ without a language specified, is keyed with C{None}.2568+- @type statuses: C{dict}2569++ @type statuses: L{dict}2570+2571+ @param priority: priority level of the resource.2572+- @type priority: C{int}2573++ @type priority: L{int}2574+ """2575+ presence = AvailabilityPresence(recipient=recipient, sender=sender,2576+ show=show, statuses=statuses,2577+@@ -541,7 +540,7 @@ class PresenceProtocol(BasePresenceProtocol):2578+ @param statuses: dictionary of natural language descriptions of the2579+ availability status, keyed by the language descriptor. A status2580+ without a language specified, is keyed with C{None}.2581+- @type statuses: C{dict}2582++ @type statuses: L{dict}2583+ """2584+ presence = AvailabilityPresence(recipient=recipient, sender=sender,2585+ available=False, statuses=statuses)2586+@@ -617,25 +616,25 @@ class RosterItem(object):2587+ @ivar entity: The JID of the contact.2588+ @type entity: L{JID}2589+ @ivar name: The associated nickname for this contact.2590+- @type name: C{unicode}2591++ @type name: L{str}2592+ @ivar subscriptionTo: Subscription state to contact's presence. If C{True},2593+ the roster owner is subscribed to the presence2594+ information of the contact.2595+- @type subscriptionTo: C{bool}2596++ @type subscriptionTo: L{bool}2597+ @ivar subscriptionFrom: Contact's subscription state. If C{True}, the2598+ contact is subscribed to the presence information2599+ of the roster owner.2600+- @type subscriptionFrom: C{bool}2601++ @type subscriptionFrom: L{bool}2602+ @ivar pendingOut: Whether the subscription request to this contact is2603+ pending.2604+- @type pendingOut: C{bool}2605++ @type pendingOut: L{bool}2606+ @ivar groups: Set of groups this contact is categorized in. Groups are2607+- represented by an opaque identifier of type C{unicode}.2608+- @type groups: C{set}2609++ represented by an opaque identifier of type L{str}.2610++ @type groups: L{set}2611+ @ivar approved: Signals pre-approved subscription.2612+- @type approved: C{bool}2613++ @type approved: L{bool}2614+ @ivar remove: Signals roster item removal.2615+- @type remove: C{bool}2616++ @type remove: L{bool}2617+ """2618+2619+ __subscriptionStates = {(False, False): None,2620+@@ -755,7 +754,7 @@ class RosterItem(object):2621+ item.approved = element.getAttribute('approved') in ('true', '1')2622+ for subElement in domish.generateElementsQNamed(element.children,2623+ 'group', NS_ROSTER):2624+- item.groups.add(unicode(subElement))2625++ item.groups.add(str(subElement))2626+ return item2627+2628+2629+@@ -771,7 +770,7 @@ class RosterRequest(Request):2630+ retrieving the roster as a delta from a known cached version. This2631+ should only be set if the recipient is known to support roster2632+ versioning.2633+- @type version: C{unicode}2634++ @type version: L{str}2635+2636+ @ivar rosterSet: If set, this is a roster set request. This flag is used2637+ to make sure some attributes of the roster item are not rendered by2638+@@ -821,7 +820,7 @@ class Roster(dict):2639+ identifier for this version of the roster.2640+2641+ @ivar version: Roster version identifier.2642+- @type version: C{unicode}.2643++ @type version: L{str}.2644+ """2645+2646+ version = None2647+@@ -892,7 +891,7 @@ class RosterClientProtocol(XMPPHandler, IQHandlerMixin):2648+ known to support roster versioning. If there is no (valid) cached2649+ version of the roster, but roster versioning is desired,2650+ C{version} should be set to the empty string (C{u''}).2651+- @type version: C{unicode}2652++ @type version: L{str}2653+2654+ @return: Roster as a mapping from L{JID} to L{RosterItem}.2655+ @rtype: L{twisted.internet.defer.Deferred}2656+@@ -1023,11 +1022,11 @@ class Message(Stanza):2657+2658+2659+ def _childParser_body(self, element):2660+- self.body = unicode(element)2661++ self.body = str(element)2662+2663+2664+ def _childParser_subject(self, element):2665+- self.subject = unicode(element)2666++ self.subject = str(element)2667+2668+2669+ def toElement(self):2670+-- 2671+2.44.1
···3334 ]35 ++ lib.optionals (stdenv.buildPlatform.config != stdenv.hostPlatform.config) [00000000036 # ./configure: sysdep posixspawnearlyreturn cannot be autodetected37 # when cross-compiling. Please manually provide a value with the38 # --with-sysdep-posixspawnearlyreturn=yes|no|... option.
···3334 ]35 ++ lib.optionals (stdenv.buildPlatform.config != stdenv.hostPlatform.config) [36+ # There's a fallback path for BSDs.37+ "--with-sysdep-procselfexe=${38+ if stdenv.hostPlatform.isLinux then39+ "/proc/self/exe"40+ else if stdenv.hostPlatform.isSunOS then41+ "/proc/self/path/a.out"42+ else43+ "none"44+ }"45 # ./configure: sysdep posixspawnearlyreturn cannot be autodetected46 # when cross-compiling. Please manually provide a value with the47 # --with-sysdep-posixspawnearlyreturn=yes|no|... option.
+1
pkgs/top-level/aliases.nix
···773 svn_all_fast_export = svn-all-fast-export;774 topGit = top-git;775 }; # Added 2021-01-140776 givaro_3 = throw "'givaro_3' has been removed as it is end-of-life. Consider using the up-to-date 'givaro' instead"; # Added 2025-05-07777 givaro_3_7 = throw "'givaro_3_7' has been removed as it is end-of-life. Consider using the up-to-date 'givaro' instead"; # Added 2025-05-07778 gkraken = throw "'gkraken' has been deprecated by upstream. Consider using the replacement 'coolercontrol' instead."; # Added 2024-11-22
···773 svn_all_fast_export = svn-all-fast-export;774 topGit = top-git;775 }; # Added 2021-01-14776+ github-copilot-cli = throw "'github-copilot-cli' has been removed because GitHub has replaced it with 'gh-copilot'."; # Added 2025-06-01777 givaro_3 = throw "'givaro_3' has been removed as it is end-of-life. Consider using the up-to-date 'givaro' instead"; # Added 2025-05-07778 givaro_3_7 = throw "'givaro_3_7' has been removed as it is end-of-life. Consider using the up-to-date 'givaro' instead"; # Added 2025-05-07779 gkraken = throw "'gkraken' has been deprecated by upstream. Consider using the replacement 'coolercontrol' instead."; # Added 2024-11-22