Hello,
In Python 2, Exception has only two built-in subclasses: StandardError,
and StopIteration.
This makes StandardError pretty useless, and Python 3 removes it.

This patch replaces StandardError with Exception. It has no effect on
IPA code. However, it could theoretically affect external plugins (e.g.
if they do "except StandardError").


-- 
Petr Viktorin
From d9abf2480f158fd1b84860ea3b59bee908724aee Mon Sep 17 00:00:00 2001
From: Robert Kuska <rku...@redhat.com>
Date: Mon, 24 Aug 2015 12:40:33 +0200
Subject: [PATCH] Replace StandardError with Exception

StandardError was removed in Python3 and instead
Exception should be used.

Signed-off-by: Robert Kuska <rku...@redhat.com>
---
 doc/guide/guide.org                        |  2 +-
 doc/guide/wsgi.py.txt                      |  2 +-
 install/share/wsgi.py                      |  2 +-
 ipa-client/ipa-install/ipa-client-install  |  2 +-
 ipalib/backend.py                          |  6 +++---
 ipalib/cli.py                              |  2 +-
 ipalib/config.py                           |  4 ++--
 ipalib/constants.py                        |  2 +-
 ipalib/errors.py                           |  6 +++---
 ipalib/parameters.py                       |  6 +++---
 ipalib/plugable.py                         |  4 ++--
 ipalib/plugins/migration.py                |  4 ++--
 ipapython/errors.py                        |  2 +-
 ipaserver/rpcserver.py                     |  8 ++++----
 ipatests/test_cmdline/test_ipagetkeytab.py |  4 ++--
 ipatests/test_ipalib/test_backend.py       |  6 +++---
 ipatests/test_ipalib/test_config.py        | 10 +++++-----
 ipatests/test_ipalib/test_errors.py        | 10 +++++-----
 ipatests/test_ipalib/test_plugable.py      |  8 ++++----
 ipatests/test_ipaserver/test_rpcserver.py  |  4 ++--
 ipatests/test_xmlrpc/xmlrpc_test.py        |  4 ++--
 21 files changed, 49 insertions(+), 49 deletions(-)

diff --git a/doc/guide/guide.org b/doc/guide/guide.org
index ad0c5953a9682a63d922e69264a6385751cd6bef..55c172535007b71e95f804f1a171fa547cfdf032 100644
--- a/doc/guide/guide.org
+++ b/doc/guide/guide.org
@@ -754,7 +754,7 @@ def run(api):
         api.log.info('operation aborted')
     except PublicError, e:
         error = e
-    except StandardError, e:
+    except Exception, e:
         api.log.exception('%s: %s', e.__class__.__name__, str(e))
         error = InternalError()
     if error is not None:
diff --git a/doc/guide/wsgi.py.txt b/doc/guide/wsgi.py.txt
index 2c4a9aaaaf6d14f89a2418517e9bd8da056fd624..eb64f3a8285495ac0131872c99ab05485587556b 100644
--- a/doc/guide/wsgi.py.txt
+++ b/doc/guide/wsgi.py.txt
@@ -13,7 +13,7 @@ env._finalize_core(**dict(DEFAULT_CONFIG))
 api.bootstrap(context='server', debug=env.debug, log=None) (ref:wsgi-app-bootstrap)
 try:
     api.finalize() (ref:wsgi-app-finalize)
-except StandardError, e:
+except Exception, e:
     api.log.error('Failed to start IPA: %s' % e)
 else:
     api.log.info('*** PROCESS START ***')
diff --git a/install/share/wsgi.py b/install/share/wsgi.py
index eab61205361df4c64ebcffb8cee15721be589a90..ee9311e4eab8b95b5143170469cac7dc0b8b8e5e 100644
--- a/install/share/wsgi.py
+++ b/install/share/wsgi.py
@@ -38,7 +38,7 @@
 api.bootstrap(context='server', debug=env.debug, log=None)
 try:
     api.finalize()
-except StandardError as e:
+except Exception as e:
     api.log.error('Failed to start IPA: %s' % e)
 else:
     api.log.info('*** PROCESS START ***')
diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install
index 91c78c9b3579c16fdbf6b31466fdce707c768127..ff44fbb9b07e49c637affbf70b5976a1b6d5b917 100755
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -1818,7 +1818,7 @@ def update_ssh_keys(server, hostname, ssh_dir, create_sshfp):
         )
     except errors.EmptyModlist:
         pass
-    except StandardError as e:
+    except Exception as e:
         root_logger.info("host_mod: %s", str(e))
         root_logger.warning("Failed to upload host SSH public keys.")
         return
diff --git a/ipalib/backend.py b/ipalib/backend.py
index 288a0edf2ab8b4c8d8a51b1970641f4ebedd7b74..b8fa29626ea3e9eaa0537e7c09d80d89bd8aa83e 100644
--- a/ipalib/backend.py
+++ b/ipalib/backend.py
@@ -56,7 +56,7 @@ def connect(self, *args, **kw):
         Create thread-local connection.
         """
         if hasattr(context, self.id):
-            raise StandardError(
+            raise Exception(
                 "connect: 'context.%s' already exists in thread %r" % (
                     self.id, threading.currentThread().getName()
                 )
@@ -71,7 +71,7 @@ def create_connection(self, *args, **kw):
 
     def disconnect(self):
         if not hasattr(context, self.id):
-            raise StandardError(
+            raise Exception(
                 "disconnect: 'context.%s' does not exist in thread %r" % (
                     self.id, threading.currentThread().getName()
                 )
@@ -130,7 +130,7 @@ def execute(self, _name, *args, **options):
             result = self.Command[_name](*args, **options)
         except PublicError as e:
             error = e
-        except StandardError as e:
+        except Exception as e:
             self.exception(
                 'non-public: %s: %s', e.__class__.__name__, str(e)
             )
diff --git a/ipalib/cli.py b/ipalib/cli.py
index b0e138925155f2547d6abb8f89d98b61f52cc318..44ef61d3033c0a187ba84f682b5d88b2130076bf 100644
--- a/ipalib/cli.py
+++ b/ipalib/cli.py
@@ -1350,7 +1350,7 @@ def run(api):
         api.log.info('operation aborted')
     except PublicError as e:
         error = e
-    except StandardError as e:
+    except Exception as e:
         api.log.exception('%s: %s', e.__class__.__name__, str(e))
         error = InternalError()
     if error is not None:
diff --git a/ipalib/config.py b/ipalib/config.py
index 14368e2b40cc7bd641a0bacdac2d567f25e3a1b5..eb823d85154c53eb7e4aa168e74913c6b8cd2ade 100644
--- a/ipalib/config.py
+++ b/ipalib/config.py
@@ -210,7 +210,7 @@ def __lock__(self):
         Prevent further changes to environment.
         """
         if self.__locked is True:
-            raise StandardError(
+            raise Exception(
                 '%s.__lock__() already called' % self.__class__.__name__
             )
         object.__setattr__(self, '_Env__locked', True)
@@ -407,7 +407,7 @@ def _join(self, key, *parts):
 
     def __doing(self, name):
         if name in self.__done:
-            raise StandardError(
+            raise Exception(
                 '%s.%s() already called' % (self.__class__.__name__, name)
             )
         self.__done.add(name)
diff --git a/ipalib/constants.py b/ipalib/constants.py
index 53c3106cdd16fef0eba42a70518f7633b3fd95d1..987d40901cce29985770f61eb35f8e55f2851b0b 100644
--- a/ipalib/constants.py
+++ b/ipalib/constants.py
@@ -49,7 +49,7 @@
 # Stardard format for TypeError message when a callable is expected:
 CALLABLE_ERROR = '%s: need a callable; got %r (which is a %r)'
 
-# Standard format for StandardError message when overriding an attribute:
+# Standard format for Exception message when overriding an attribute:
 OVERRIDE_ERROR = 'cannot override %s.%s value %r with %r'
 
 # Standard format for AttributeError message when a read-only attribute is
diff --git a/ipalib/errors.py b/ipalib/errors.py
index 2f7c77c1cecbb4275cf66a74a2e3efa13a0e6e2b..49b628aad6b09e13ee2fbaeb942fac30ca57d544 100644
--- a/ipalib/errors.py
+++ b/ipalib/errors.py
@@ -107,7 +107,7 @@
 from ipaplatform.paths import paths
 
 
-class PrivateError(StandardError):
+class PrivateError(Exception):
     """
     Base class for exceptions that are *never* forwarded in an RPC response.
     """
@@ -122,7 +122,7 @@ def __init__(self, **kw):
                 self.__class__.__name__, key, value,
             )
             setattr(self, key, value)
-        StandardError.__init__(self, self.msg)
+        Exception.__init__(self, self.msg)
 
 
 class SubprocessError(PrivateError):
@@ -239,7 +239,7 @@ def _(message):
     return message
 
 
-class PublicError(StandardError):
+class PublicError(Exception):
     """
     **900** Base class for exceptions that can be forwarded in an RPC response.
     """
diff --git a/ipalib/parameters.py b/ipalib/parameters.py
index 176df09ea89e4392feadb4e82bfe17d180836c2a..dab235a2482f6707a813ad891d28d5e3a56e2e96 100644
--- a/ipalib/parameters.py
+++ b/ipalib/parameters.py
@@ -242,7 +242,7 @@ def __call__(self, **kw):
             return
         try:
             return self.callback(*vals)
-        except StandardError:
+        except Exception:
             pass
 
     def __json__(self):
@@ -740,7 +740,7 @@ def _normalize_scalar(self, value):
             return value
         try:
             return self.normalizer(value)
-        except StandardError:
+        except Exception:
             return value
 
     def convert(self, value):
@@ -917,7 +917,7 @@ def get_default(self, **kw):
             if default is not None:
                 try:
                     return self.convert(self.normalize(default))
-                except StandardError:
+                except Exception:
                     pass
         return self.default
 
diff --git a/ipalib/plugable.py b/ipalib/plugable.py
index 2a608d8cb67a65e2dcebf2531585b96bab01a3b0..2b593ec3ba1def8b38d295bab92ead4b2ef3baa4 100644
--- a/ipalib/plugable.py
+++ b/ipalib/plugable.py
@@ -360,7 +360,7 @@ def is_production_mode(self):
 
     def __doing(self, name):
         if name in self.__done:
-            raise StandardError(
+            raise Exception(
                 '%s.%s() already called' % (self.__class__.__name__, name)
             )
         self.__done.add(name)
@@ -572,7 +572,7 @@ def import_plugins(self, module):
                 module = importlib.import_module(name)
             except errors.SkipPluginModule as e:
                 self.log.debug("skipping plugin module %s: %s", name, e.reason)
-            except StandardError as e:
+            except Exception as e:
                 if self.env.startup_traceback:
                     import traceback
                     self.log.error("could not load plugin module %s\n%s", name,
diff --git a/ipalib/plugins/migration.py b/ipalib/plugins/migration.py
index 3e3c0fe19cdcd0ce31b342830b29ca066653b44a..59c49fae5441531015a45532df07439daac35290 100644
--- a/ipalib/plugins/migration.py
+++ b/ipalib/plugins/migration.py
@@ -31,7 +31,7 @@
 if api.env.in_server and api.env.context in ['lite', 'server']:
     try:
         from ipaserver.plugins.ldap2 import ldap2
-    except StandardError as e:
+    except Exception as e:
         raise e
 from ipalib import _
 from ipapython.dn import DN
@@ -922,7 +922,7 @@ def execute(self, ldapuri, bindpw, **options):
                     ds_base_dn = DN(entries[0]['namingcontexts'][0])
                     assert isinstance(ds_base_dn, DN)
                 except (IndexError, KeyError) as e:
-                    raise StandardError(str(e))
+                    raise Exception(str(e))
 
         # migrate!
         (migrated, failed) = self.migrate(
diff --git a/ipapython/errors.py b/ipapython/errors.py
index 9fc28359cf69d24fda3668aa2bfce508ad2b90fc..aad485b0fde853093727d0b5f253ffdfbcf5d898 100644
--- a/ipapython/errors.py
+++ b/ipapython/errors.py
@@ -18,7 +18,7 @@
 #
 
 
-class SetseboolError(StandardError):
+class SetseboolError(Exception):
     """Raised when setting a SELinux boolean fails
 
     :param failed: Dictionary mapping boolean names to intended values
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index 298f8bab176f45cb0398420ef20296cd0cd8e649..cf655d7aba9cb084f0dca93a1a4aa8640a8a6b51 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -282,11 +282,11 @@ def mount(self, app, key):
         Mount the WSGI application *app* at *key*.
         """
 #        if self.__islocked__():
-#            raise StandardError('%s.mount(): locked, cannot mount %r at %r' % (
+#            raise Exception('%s.mount(): locked, cannot mount %r at %r' % (
 #                self.name, app, key)
 #            )
         if key in self.__apps:
-            raise StandardError('%s.mount(): cannot replace %r with %r at %r' % (
+            raise Exception('%s.mount(): cannot replace %r with %r at %r' % (
                 self.name, self.__apps[key], app, key)
             )
         self.debug('Mounting %r at %r', app, key)
@@ -354,7 +354,7 @@ def wsgi_execute(self, environ):
             if self.api.env.debug:
                 self.debug('WSGI wsgi_execute PublicError: %s', traceback.format_exc())
             error = e
-        except StandardError as e:
+        except Exception as e:
             self.exception(
                 'non-public: %s: %s', e.__class__.__name__, str(e)
             )
@@ -407,7 +407,7 @@ def __call__(self, environ, start_response):
             status = HTTP_STATUS_SUCCESS
             response = self.wsgi_execute(environ)
             headers = [('Content-Type', self.content_type + '; charset=utf-8')]
-        except StandardError as e:
+        except Exception as e:
             self.exception('WSGI %s.__call__():', self.name)
             status = HTTP_STATUS_SERVER_ERROR
             response = status
diff --git a/ipatests/test_cmdline/test_ipagetkeytab.py b/ipatests/test_cmdline/test_ipagetkeytab.py
index d9ab0daaa8e46c70bda8a758a1bb8d00760747d9..7b57ba194f90750a221b2d9075912f0a08674fd4 100644
--- a/ipatests/test_cmdline/test_ipagetkeytab.py
+++ b/ipatests/test_cmdline/test_ipagetkeytab.py
@@ -46,7 +46,7 @@ def use_keytab(principal, keytab):
         conn.connect(autobind=ipaldap.AUTOBIND_DISABLED)
         conn.disconnect()
     except gssapi.exceptions.GSSError as e:
-        raise StandardError('Unable to bind to LDAP. Error initializing principal %s in %s: %s' % (principal, keytab, str(e)))
+        raise Exception('Unable to bind to LDAP. Error initializing principal %s in %s: %s' % (principal, keytab, str(e)))
     finally:
         os.environ.pop('KRB5CCNAME', None)
         if tmpdir:
@@ -138,7 +138,7 @@ def test_5_use_disabled(self):
         """
         try:
             use_keytab(self.service_princ, self.keytabname)
-        except StandardError as errmsg:
+        except Exception as errmsg:
             assert('Unable to bind to LDAP. Error initializing principal' in str(errmsg))
 
     def test_9_cleanup(self):
diff --git a/ipatests/test_ipalib/test_backend.py b/ipatests/test_ipalib/test_backend.py
index f7887bf64d1e2c20d72cc32d2abba31d9cc70bcb..4e014f6545d16d2b9a63a71f80f5a73a1c23fdbf 100644
--- a/ipatests/test_ipalib/test_backend.py
+++ b/ipatests/test_ipalib/test_backend.py
@@ -90,9 +90,9 @@ def create_connection(self, *args, **kw):
         assert conn.conn == 'The connection.'
         assert conn.disconnect == o.disconnect
 
-        # Test that StandardError is raised if already connected:
+        # Test that Exception is raised if already connected:
         m = "connect: 'context.%s' already exists in thread %r"
-        e = raises(StandardError, o.connect, *args, **kw)
+        e = raises(Exception, o.connect, *args, **kw)
         assert str(e) == m % ('example', threading.currentThread().getName())
 
         # Double check that it works after deleting context.example:
@@ -121,7 +121,7 @@ class example(self.cls):
         o = example(api, shared_instance=True)
 
         m = "disconnect: 'context.%s' does not exist in thread %r"
-        e = raises(StandardError, o.disconnect)
+        e = raises(Exception, o.disconnect)
         assert str(e) == m % ('example', threading.currentThread().getName())
 
         context.example = 'The connection.'
diff --git a/ipatests/test_ipalib/test_config.py b/ipatests/test_ipalib/test_config.py
index b8cba516da21d88448f35ffb9a3e624dc7d8c147..5a0de1e1f6c51f4a4e3a7ee610495283cca5c9a0 100644
--- a/ipatests/test_ipalib/test_config.py
+++ b/ipatests/test_ipalib/test_config.py
@@ -166,7 +166,7 @@ def test_lock(self):
         assert o.__islocked__() is False
         o.__lock__()
         assert o.__islocked__() is True
-        e = raises(StandardError, o.__lock__)
+        e = raises(Exception, o.__lock__)
         assert str(e) == 'Env.__lock__() already called'
 
         # Also test with base.lock() function:
@@ -429,7 +429,7 @@ def bootstrap(self, **overrides):
         assert o._isdone('_bootstrap') is False
         o._bootstrap(**overrides)
         assert o._isdone('_bootstrap') is True
-        e = raises(StandardError, o._bootstrap)
+        e = raises(Exception, o._bootstrap)
         assert str(e) == 'Env._bootstrap() already called'
         return (o, home)
 
@@ -512,7 +512,7 @@ def finalize_core(self, ctx, **defaults):
             assert key in o
 
         # Check that it can't be called twice:
-        e = raises(StandardError, o._finalize_core)
+        e = raises(Exception, o._finalize_core)
         assert str(e) == 'Env._finalize_core() already called'
 
         return (o, home)
@@ -586,7 +586,7 @@ def test_finalize(self):
         assert o._isdone('_finalize') is True
 
         # Check that it can't be called twice:
-        e = raises(StandardError, o._finalize)
+        e = raises(Exception, o._finalize)
         assert str(e) == 'Env._finalize() already called'
 
         # Check that _finalize() calls __lock__()
@@ -594,7 +594,7 @@ def test_finalize(self):
         assert o.__islocked__() is False
         o._finalize()
         assert o.__islocked__() is True
-        e = raises(StandardError, o.__lock__)
+        e = raises(Exception, o.__lock__)
         assert str(e) == 'Env.__lock__() already called'
 
         # Check that **lastchance works
diff --git a/ipatests/test_ipalib/test_errors.py b/ipatests/test_ipalib/test_errors.py
index 8cc9cd27661ccc51e04c564d8e76291c0f43375b..6dd9e6cce1d75bc147911078feee2cd8b9862651 100644
--- a/ipatests/test_ipalib/test_errors.py
+++ b/ipatests/test_ipalib/test_errors.py
@@ -45,7 +45,7 @@ class PrivateExceptionTester(object):
     def __get_klass(self):
         if self.__klass is None:
             self.__klass = self._klass
-        assert issubclass(self.__klass, StandardError)
+        assert issubclass(self.__klass, Exception)
         assert issubclass(self.__klass, errors.PrivateError)
         assert not issubclass(self.__klass, errors.PublicError)
         return self.__klass
@@ -55,7 +55,7 @@ def new(self, **kw):
         for (key, value) in kw.items():
             assert not hasattr(self.klass, key), key
         inst = self.klass(**kw)
-        assert isinstance(inst, StandardError)
+        assert isinstance(inst, Exception)
         assert isinstance(inst, errors.PrivateError)
         assert isinstance(inst, self.klass)
         assert not isinstance(inst, errors.PublicError)
@@ -203,7 +203,7 @@ class PublicExceptionTester(object):
     def __get_klass(self):
         if self.__klass is None:
             self.__klass = self._klass
-        assert issubclass(self.__klass, StandardError)
+        assert issubclass(self.__klass, Exception)
         assert issubclass(self.__klass, errors.PublicError)
         assert not issubclass(self.__klass, errors.PrivateError)
         assert type(self.__klass.errno) is int
@@ -234,7 +234,7 @@ class test_PublicError(PublicExceptionTester):
     Test the `ipalib.errors.PublicError` exception.
     """
     _klass = errors.PublicError
-    required_classes = StandardError, errors.PublicError
+    required_classes = Exception, errors.PublicError
 
     def test_init(self):
         message = u'The translated, interpolated message'
@@ -375,7 +375,7 @@ def extratest(self, cls):
 class test_PublicErrors(object):
     message_list = errors.public_errors
     errno_range = list(range(900, 5999))
-    required_classes = (StandardError, errors.PublicError)
+    required_classes = (Exception, errors.PublicError)
     texts = errors._texts
 
     def extratest(self, cls):
diff --git a/ipatests/test_ipalib/test_plugable.py b/ipatests/test_ipalib/test_plugable.py
index 1481394648d191e20d3605ff49d405725421e8ea..caf08d6b9059bb2f7128b19c3494a79f83e85e81 100644
--- a/ipatests/test_ipalib/test_plugable.py
+++ b/ipatests/test_ipalib/test_plugable.py
@@ -80,7 +80,7 @@ class another_subclass(self.cls):
         # whose names conflict with the logger methods set in Plugin.__init__():
         class check(self.cls):
             info = 'whatever'
-        e = raises(StandardError, check, api)
+        e = raises(Exception, check, api)
         assert str(e) == \
             "info is already bound to ipatests.test_ipalib.test_plugable.check()"
 
@@ -257,7 +257,7 @@ def get_plugin_name(b, p):
                 assert inst.method(7) == 7 + b
 
         # Test that calling finilize again raises AssertionError:
-        e = raises(StandardError, api.finalize)
+        e = raises(Exception, api.finalize)
         assert str(e) == 'API.finalize() already called', str(e)
 
     def test_bootstrap(self):
@@ -273,7 +273,7 @@ def test_bootstrap(self):
         assert o.env._isdone('_bootstrap') is True
         assert o.env._isdone('_finalize_core') is True
         assert o.env.my_test_override == 'Hello, world!'
-        e = raises(StandardError, o.bootstrap)
+        e = raises(Exception, o.bootstrap)
         assert str(e) == 'API.bootstrap() already called'
 
     def test_load_plugins(self):
@@ -286,5 +286,5 @@ def test_load_plugins(self):
         o.load_plugins()
         assert o.isdone('bootstrap') is True
         assert o.isdone('load_plugins') is True
-        e = raises(StandardError, o.load_plugins)
+        e = raises(Exception, o.load_plugins)
         assert str(e) == 'API.load_plugins() already called'
diff --git a/ipatests/test_ipaserver/test_rpcserver.py b/ipatests/test_ipaserver/test_rpcserver.py
index 95980eb05bc3030c5ece841acf41901b2c51e368..ce5a03a13e82194835d94d3e463bcc054ce3a3e6 100644
--- a/ipatests/test_ipaserver/test_rpcserver.py
+++ b/ipatests/test_ipaserver/test_rpcserver.py
@@ -173,8 +173,8 @@ def app2(environ, start_response):
         assert inst['foo'] is app1
         assert list(inst) == ['foo']
 
-        # Test that StandardError is raise if trying override a mount:
-        e = raises(StandardError, inst.mount, app2, 'foo')
+        # Test that Exception is raise if trying override a mount:
+        e = raises(Exception, inst.mount, app2, 'foo')
         assert str(e) == '%s.mount(): cannot replace %r with %r at %r' % (
             'wsgi_dispatch', app1, app2, 'foo'
         )
diff --git a/ipatests/test_xmlrpc/xmlrpc_test.py b/ipatests/test_xmlrpc/xmlrpc_test.py
index 56ddad9b8a0a1164c29f38970e0a97513d1a8d1f..80638e2efdd9d7ff07fd89688397acb7d44654cd 100644
--- a/ipatests/test_xmlrpc/xmlrpc_test.py
+++ b/ipatests/test_xmlrpc/xmlrpc_test.py
@@ -313,7 +313,7 @@ def check_exception(self, nice, cmd, args, options, expected):
         name = klass.__name__
         try:
             output = api.Command[cmd](*args, **options)
-        except StandardError as e:
+        except Exception as e:
             pass
         else:
             raise AssertionError(
@@ -336,7 +336,7 @@ def check_callable(self, nice, cmd, args, options, expected):
         e = None
         try:
             output = api.Command[cmd](*args, **options)
-        except StandardError as e:
+        except Exception as e:
             pass
         if not expected(e, output):
             raise AssertionError(
-- 
2.1.0

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to