From b07bc1a78b56d28f99ed41202c65c118c78412db Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Sat, 25 Mar 2017 12:41:58 +0800 Subject: [PATCH] Docstrings should not start with a space As per OpenStack Docstrings guide lines [1]: [H401] Docstrings should not start with a space. [H403] Multi line docstrings should end on a new line. [H404] Multi line docstrings should start without a leading new line. [H405] Multi line docstrings should start with a one line summary followed by an empty line. [1] http://docs.openstack.org/developer/hacking/#docstrings trivialfix Change-Id: I7683085edbd6b82c1efaa75ff507165ee51c16fd --- glare/api/v1/api_version_request.py | 2 +- glare/api/v1/api_versioning.py | 2 +- glare/common/config.py | 9 ++-- glare/common/exception.py | 3 +- glare/common/semver_db.py | 10 ++-- glare/common/utils.py | 33 ++++-------- glare/common/wsgi.py | 42 +++++---------- glare/db/migration/migration.py | 5 ++ glare/db/sqlalchemy/api.py | 15 +++--- glare/engine.py | 25 +++++---- glare/tests/functional/__init__.py | 52 ++++++------------- glare/tests/unit/base.py | 3 +- .../unit/db/migrations/test_migrations.py | 1 + glare/tests/utils.py | 40 +++++++------- 14 files changed, 100 insertions(+), 142 deletions(-) diff --git a/glare/api/v1/api_version_request.py b/glare/api/v1/api_version_request.py index 675b5ed..b32ab75 100644 --- a/glare/api/v1/api_version_request.py +++ b/glare/api/v1/api_version_request.py @@ -40,7 +40,7 @@ class APIVersionRequest(object): """Create an API version request object. :param version_string: String representation of APIVersionRequest. - Correct format is 'X.Y', where 'X' and 'Y' are int values. + Correct format is 'X.Y', where 'X' and 'Y' are int values. """ match = re.match(r"^([1-9]\d*)\.([1-9]\d*|0)$", version_string) if match: diff --git a/glare/api/v1/api_versioning.py b/glare/api/v1/api_versioning.py index b7fcba5..25eb92c 100644 --- a/glare/api/v1/api_versioning.py +++ b/glare/api/v1/api_versioning.py @@ -133,7 +133,7 @@ class VersionedResource(object): :returns: Returns the result of the method called :raises: VersionNotFoundForAPIMethod if there is no method which - matches the name and version constraints + matches the name and version constraints """ # versioning is used in 3 classes: request deserializer and # controller have request as first argument diff --git a/glare/common/config.py b/glare/common/config.py index e004f65..bdfc9e6 100644 --- a/glare/common/config.py +++ b/glare/common/config.py @@ -77,8 +77,7 @@ def parse_args(args=None, usage=None, default_config_files=None): def _get_deployment_flavor(flavor=None): - """ - Retrieve the paste_deploy.flavor config item, formatted appropriately + """Retrieve the paste_deploy.flavor config item, formatted appropriately for appending to the application name. :param flavor: if specified, use this setting rather than the @@ -102,8 +101,7 @@ def _get_paste_config_path(): def _get_deployment_config_file(): - """ - Retrieve the deployment_config_file config item, formatted as an + """Retrieve the deployment_config_file config item, formatted as an absolute pathname. """ path = CONF.paste_deploy.config_file @@ -116,8 +114,7 @@ def _get_deployment_config_file(): def load_paste_app(app_name, flavor=None, conf_file=None): - """ - Builds and returns a WSGI app from a paste config file. + """Builds and returns a WSGI app from a paste config file. We assume the last config file specified in the supplied ConfigOpts object is the paste config file, if conf_file is None. diff --git a/glare/common/exception.py b/glare/common/exception.py index e3c4543..f65fbd6 100644 --- a/glare/common/exception.py +++ b/glare/common/exception.py @@ -23,8 +23,7 @@ LOG = logging.getLogger(__name__) class GlareException(Exception): - """ - Base Glare Exception class. + """Base Glare Exception class. To correctly use this class, inherit from it and define a 'message' property. That message will get printf'd diff --git a/glare/common/semver_db.py b/glare/common/semver_db.py index a82515f..828ad80 100644 --- a/glare/common/semver_db.py +++ b/glare/common/semver_db.py @@ -27,15 +27,14 @@ MAX_NUMERIC_PRERELEASE_LENGTH = 6 class DBVersion(object): def __init__(self, components_long, prerelease, build): - """ - Creates a DBVersion object out of 3 component fields. This initializer + """Creates a DBVersion object out of 3 component fields. This initializer is supposed to be called from SQLAlchemy if 3 database columns are mapped to this composite field. :param components_long: a 64-bit long value, containing numeric - components of the version + components of the version :param prerelease: a prerelease label of the version, optionally - preformatted with leading zeroes in numeric-only parts of the label + preformatted with leading zeroes in numeric-only parts of the label :param build: a build label of the version """ version_string = '%s.%s.%s' % _long_to_components(components_long) @@ -80,8 +79,7 @@ def _check_limit(value): def _version_to_long(version): - """ - Converts the numeric part of the semver version into the 64-bit long value + """Converts the numeric part of the semver version into the 64-bit long value using the following logic: * major version is stored in first 16 bits of the value diff --git a/glare/common/utils.py b/glare/common/utils.py index 2c08371..8c82ba3 100644 --- a/glare/common/utils.py +++ b/glare/common/utils.py @@ -56,8 +56,7 @@ GLARE_TEST_SOCKET_FD_STR = 'GLARE_TEST_SOCKET_FD' def chunkreadable(iter, chunk_size=65536): - """ - Wrap a readable iterator with a reader yielding chunks of + """Wrap a readable iterator with a reader yielding chunks of a preferred size, otherwise leave iterator unchanged. :param iter: an iter which may also be readable @@ -67,8 +66,7 @@ def chunkreadable(iter, chunk_size=65536): def chunkiter(fp, chunk_size=65536): - """ - Return an iterator to a file-like obj which yields fixed size chunks. + """Return an iterator to a file-like obj which yields fixed size chunks. :param fp: a file-like object :param chunk_size: maximum size of chunk @@ -82,8 +80,7 @@ def chunkiter(fp, chunk_size=65536): def cooperative_iter(iter): - """ - Return an iterator which schedules after each + """Return an iterator which schedules after each iteration. This can prevent eventlet thread starvation. :param iter: an iterator to wrap @@ -99,8 +96,7 @@ def cooperative_iter(iter): def cooperative_read(fd): - """ - Wrap a file descriptor's read with a partial function which schedules + """Wrap a file descriptor's read with a partial function which schedules after each read. This can prevent eventlet thread starvation. :param fd: a file descriptor to wrap @@ -116,8 +112,7 @@ MAX_COOP_READER_BUFFER_SIZE = 134217728 # 128M seems like a sane buffer limit class CooperativeReader(object): - """ - An eventlet thread friendly class for reading in blob data. + """An eventlet thread friendly class for reading in blob data. When accessing data either through the iterator or the read method we perform a sleep to allow a co-operative yield. When there is more than @@ -126,8 +121,7 @@ class CooperativeReader(object): having the same thread be continuously active. """ def __init__(self, fd): - """ - :param fd: Underlying blob file object + """:param fd: Underlying blob file object """ self.fd = fd self.iterator = None @@ -204,8 +198,7 @@ class CooperativeReader(object): class LimitingReader(object): - """ - Reader designed to fail when reading blob data past the configured + """Reader designed to fail when reading blob data past the configured allowable amount. """ def __init__(self, data, limit): @@ -361,8 +354,7 @@ except re.error: def no_4byte_params(f): - """ - Checks that no 4 byte unicode characters are allowed + """Checks that no 4 byte unicode characters are allowed in dicts' keys/values and string's parameters. """ def wrapper(*args, **kwargs): @@ -400,8 +392,7 @@ def no_4byte_params(f): def stash_conf_values(): - """ - Make a copy of some of the current global CONF's settings. + """Make a copy of some of the current global CONF's settings. Allows determining if any of these values have changed when the config is reloaded. """ @@ -608,8 +599,7 @@ def _get_element_type(element_type): class DictDiffer(object): - """ - Calculate the difference between two dictionaries as: + """Calculate the difference between two dictionaries as: (1) items added (2) items removed (3) keys same in both but changed values @@ -647,8 +637,7 @@ class DictDiffer(object): class BlobIterator(object): - """ - Reads data from a blob, one chunk at a time. + """Reads data from a blob, one chunk at a time. """ def __init__(self, data, chunk_size=65536): diff --git a/glare/common/wsgi.py b/glare/common/wsgi.py index 7ce799e..11f4abd 100644 --- a/glare/common/wsgi.py +++ b/glare/common/wsgi.py @@ -129,8 +129,7 @@ def get_bind_addr(default_port=None): def ssl_wrap_socket(sock): - """ - Wrap an existing socket in SSL + """Wrap an existing socket in SSL :param sock: non-SSL socket to wrap @@ -153,8 +152,7 @@ def ssl_wrap_socket(sock): def get_socket(default_port): - """ - Bind socket to bind ip:port in conf + """Bind socket to bind ip:port in conf :param default_port: port to bind to if none is specified in conf @@ -260,8 +258,7 @@ class Server(object): self.pgid = 0 def hup(self, *args): - """ - Reloads configuration files with zero down time + """Reloads configuration files with zero down time """ signal.signal(signal.SIGHUP, signal.SIG_IGN) raise glare_exc.SIGHUPInterrupt @@ -274,8 +271,7 @@ class Server(object): os.killpg(self.pgid, signal.SIGTERM) def start(self, application, default_port): - """ - Run a WSGI server with the given application. + """Run a WSGI server with the given application. :param application: The application to be run in the WSGI server :param default_port: Port to bind to if none is specified in conf @@ -348,8 +344,7 @@ class Server(object): LOG.debug('Exited') def configure(self, old_conf=None, has_changed=None): - """ - Apply configuration settings + """Apply configuration settings :param old_conf: Cached old configuration settings (if any) :param has_changed: callable to determine if a parameter has changed @@ -370,8 +365,7 @@ class Server(object): initialize_glance_store() def reload(self): - """ - Reload and re-apply configuration settings + """Reload and re-apply configuration settings Existing child processes are sent a SIGHUP signal and will exit after completing existing requests. @@ -466,8 +460,7 @@ class Server(object): socket_timeout=self.client_socket_timeout) def configure_socket(self, old_conf=None, has_changed=None): - """ - Ensure a socket exists and is appropriately configured. + """Ensure a socket exists and is appropriately configured. This function is called on start up, and can also be called in the event of a configuration reload. @@ -536,8 +529,7 @@ class Server(object): class APIMapper(routes.Mapper): - """ - Handle route matching when url is '' because routes.Mapper returns + """Handle route matching when url is '' because routes.Mapper returns an error in this case. """ @@ -557,13 +549,11 @@ class RejectMethodController(object): class Router(object): - """ - WSGI middleware that maps incoming requests to WSGI apps. + """WSGI middleware that maps incoming requests to WSGI apps. """ def __init__(self, mapper): - """ - Create a router for the given routes.Mapper. + """Create a router for the given routes.Mapper. Each route in `mapper` must specify a 'controller', which is a WSGI app to call. You'll probably want to specify an 'action' as @@ -596,8 +586,7 @@ class Router(object): @webob.dec.wsgify def __call__(self, req): - """ - Route the incoming request to a controller based on self.map. + """Route the incoming request to a controller based on self.map. If no match, return either a 404(Not Found) or 501(Not Implemented). """ return self._router @@ -605,8 +594,7 @@ class Router(object): @staticmethod @webob.dec.wsgify def _dispatch(req): - """ - Called by self._router after matching the incoming request to a route + """Called by self._router after matching the incoming request to a route and putting the information into req.environ. Either returns 404, 501, or the routed WSGI app's response. """ @@ -658,8 +646,7 @@ class JSONRequestDeserializer(object): 'gzip', 'identity']) def has_body(self, request): - """ - Returns whether a Webob.Request object will possess an entity body. + """Returns whether a Webob.Request object will possess an entity body. :param request: Webob.Request object """ @@ -735,8 +722,7 @@ def translate_exception(req, e): class Resource(object): - """ - WSGI app that handles (de)serialization and controller dispatch. + """WSGI app that handles (de)serialization and controller dispatch. Reads routing information supplied by RoutesMiddleware and calls the requested action method upon its deserializer, controller, diff --git a/glare/db/migration/migration.py b/glare/db/migration/migration.py index 6114d7d..3befd2e 100644 --- a/glare/db/migration/migration.py +++ b/glare/db/migration/migration.py @@ -38,6 +38,7 @@ def version(engine=None): def upgrade(revision, config=None): """Used for upgrading database. + :param revision: Desired database version :type revision: string """ @@ -49,6 +50,7 @@ def upgrade(revision, config=None): def downgrade(revision, config=None): """Used for downgrading database. + :param revision: Desired database version7 :type revision: string """ @@ -59,7 +61,9 @@ def downgrade(revision, config=None): def stamp(revision, config=None): """Stamps database with provided revision. + Don't run any migrations. + :param revision: Should match one from repository or head - to stamp database with most recent revision :type revision: string @@ -70,6 +74,7 @@ def stamp(revision, config=None): def revision(message=None, autogenerate=False, config=None): """Creates template for migration. + :param message: Text that will be used for migration title :type message: string :param autogenerate: If True - generates diff based on current database diff --git a/glare/db/sqlalchemy/api.py b/glare/db/sqlalchemy/api.py index cc1c966..31f6d56 100644 --- a/glare/db/sqlalchemy/api.py +++ b/glare/db/sqlalchemy/api.py @@ -91,8 +91,7 @@ def get_session(autocommit=True, expire_on_commit=False): def clear_db_env(): - """ - Unset global configuration variables for database. + """Unset global configuration variables for database. """ global _FACADE _FACADE = None @@ -113,8 +112,7 @@ def delete(context, artifact_id, session): def _drop_protected_attrs(model_class, values): - """ - Removed protected attributes from values dictionary using the models + """Removed protected attributes from values dictionary using the models __protected_attributes__ field. """ for attr in model_class.__protected_attributes__: @@ -193,15 +191,16 @@ def get(context, artifact_id, session): def get_all(context, session, filters=None, marker=None, limit=None, sort=None, latest=False): """List all visible artifacts + :param filters: dict of filter keys and values. :param marker: artifact id after which to start page :param limit: maximum number of artifacts to return :param sort: a tuple (key, dir, type) where key is an attribute by - which results should be sorted, dir is a direction: 'asc' or 'desc', - and type is type of the attribute: 'bool', 'string', 'numeric' or 'int' or - None if attribute is base. + which results should be sorted, dir is a direction: 'asc' or 'desc', + and type is type of the attribute: 'bool', 'string', 'numeric' or 'int' or + None if attribute is base. :param latest: flag that indicates, that only artifacts with highest - versions should be returned in output + versions should be returned in output """ artifacts = _get_all( context, session, filters, marker, limit, sort, latest) diff --git a/glare/engine.py b/glare/engine.py index 1223332..1a0d02c 100644 --- a/glare/engine.py +++ b/glare/engine.py @@ -37,14 +37,16 @@ LOG = logging.getLogger(__name__) class Engine(object): """Engine is responsible for executing different helper operations when processing incoming requests from Glare API. + Engine receives incoming data and does the following: - - check basic policy permissions; - - requests artifact definition from artifact type registry; - - check access permission(ro, rw); - - lock artifact for update if needed; - - pass data to base artifact to execute all business logic operations - with database; - - notify other users about finished operation. + - check basic policy permissions; + - requests artifact definition from artifact type registry; + - check access permission(ro, rw); + - lock artifact for update if needed; + - pass data to base artifact to execute all business logic operations + with database; + - notify other users about finished operation. + Engine should not include any business logic and validation related to Artifacts. Engine should not know any internal details of artifact type, because this part of the work is done by Base artifact type. @@ -63,13 +65,14 @@ class Engine(object): @classmethod def _get_artifact(cls, ctx, type_name, artifact_id, read_only=False): """Return artifact requested by user. + Check access permissions and policies. :param ctx: user context :param type_name: artifact type name :param artifact_id: id of the artifact to be updated :param read_only: flag, if set to True only read access is checked, - if False then engine checks if artifact can be modified by the user + if False then engine checks if artifact can be modified by the user """ artifact_type = registry.ArtifactRegistry.get_artifact_type(type_name) # only artifact is available for class users @@ -196,12 +199,12 @@ class Engine(object): :param type_name: Artifact type name :param filters: filters that need to be applied to artifact :param marker: the artifact that considered as begin of the list - so all artifacts before marker (including marker itself) will not be - added to artifact list + so all artifacts before marker (including marker itself) will not be + added to artifact list :param limit: maximum number of items in list :param sort: sorting options :param latest: flag that indicates, that only artifacts with highest - versions should be returned in output + versions should be returned in output :return: list of artifact definitions """ policy.authorize("artifact:list", {}, context) diff --git a/glare/tests/functional/__init__.py b/glare/tests/functional/__init__.py index b2d51ed..3aa1ee0 100644 --- a/glare/tests/functional/__init__.py +++ b/glare/tests/functional/__init__.py @@ -57,13 +57,11 @@ eventlet.patcher.monkey_patch() class Server(object): - """ - Class used to easily manage starting and stopping + """Class used to easily manage starting and stopping a server during functional test runs. """ def __init__(self, test_dir, port, sock=None): - """ - Creates a new Server object. + """Creates a new Server object. :param test_dir: The directory where all test stuff is kept. This is passed from the FunctionalTestCase. @@ -87,8 +85,7 @@ class Server(object): self.stop_kill = False def write_conf(self, **kwargs): - """ - Writes the configuration file for the server to its intended + """Writes the configuration file for the server to its intended destination. Returns the name of the configuration file and the over-ridden config content (may be useful for populating error messages). @@ -132,8 +129,7 @@ class Server(object): return self.conf_file_name, overridden def start(self, expect_exit=True, expected_exitcode=0, **kwargs): - """ - Starts the server. + """Starts the server. Any kwargs passed to this method will override the configuration value in the conf file used in starting the servers. @@ -190,8 +186,7 @@ class Server(object): return (rc, '', '') def reload(self, expect_exit=True, expected_exitcode=0, **kwargs): - """ - Start and stop the service to reload + """Start and stop the service to reload Any kwargs passed to this method will override the configuration value in the conf file used in starting the servers. @@ -240,9 +235,7 @@ class Server(object): atexit.register(_delete_cached_db) def stop(self): - """ - Spin down the server. - """ + """Spin down the server.""" if not self.process_pid: raise Exception('why is this being called? %s' % self.server_name) @@ -262,9 +255,7 @@ class Server(object): class GlareServer(Server): - """ - Server object that starts/stops/manages Glare server - """ + """Server object that starts/stops/manages Glare server""" def __init__(self, test_dir, port, policy_file, delayed_delete=False, pid_file=None, sock=None, **kwargs): @@ -347,8 +338,7 @@ paste.filter_factory = class FunctionalTest(test_utils.BaseTestCase): - """ - Base test class for any test that wants to test the actual + """Base test class for any test that wants to test the actual servers and clients and not just the stubbed out interfaces """ @@ -424,8 +414,7 @@ class FunctionalTest(test_utils.BaseTestCase): self.assertEqual(0, exitcode) def cleanup(self): - """ - Makes sure anything we created or started up in the + """Makes sure anything we created or started up in the tests are destroyed or spun down """ @@ -451,8 +440,7 @@ class FunctionalTest(test_utils.BaseTestCase): expect_exit=True, expected_exitcode=0, **kwargs): - """ - Starts a server on an unused port. + """Starts a server on an unused port. Any kwargs passed to this method will override the configuration value in the conf file used in starting the server. @@ -483,8 +471,7 @@ class FunctionalTest(test_utils.BaseTestCase): def start_with_retry(self, server, port_name, max_retries, expect_launch=True, **kwargs): - """ - Starts a server, with retries if the server launches but + """Starts a server, with retries if the server launches but fails to start listening on the expected port. :param server: the server to launch @@ -514,8 +501,7 @@ class FunctionalTest(test_utils.BaseTestCase): self.assertTrue(launch_msg is None, launch_msg) def start_servers(self, **kwargs): - """ - Starts the Glare server on unused port. + """Starts the Glare server on unused port. Any kwargs passed to this method will override the configuration value in the conf file used in starting the servers. @@ -525,8 +511,7 @@ class FunctionalTest(test_utils.BaseTestCase): self.start_with_retry(self.glare_server, 'glare_port', 3, **kwargs) def ping_server(self, port): - """ - Simple ping on the port. If responsive, return True, else + """Simple ping on the port. If responsive, return True, else return False. :note We use raw sockets, not ping here, since ping uses ICMP and @@ -542,8 +527,7 @@ class FunctionalTest(test_utils.BaseTestCase): s.close() def wait_for_servers(self, servers, expect_launch=True, timeout=30): - """ - Tight loop, waiting for the given server port(s) to be available. + """Tight loop, waiting for the given server port(s) to be available. Returns when all are pingable. There is a timeout on waiting for the servers to come up. @@ -597,8 +581,7 @@ class FunctionalTest(test_utils.BaseTestCase): return msg if expect_launch else None def stop_server(self, server, name): - """ - Called to stop a single server in a normal fashion. + """Called to stop a single server in a normal fashion. :param server: the server to stop """ @@ -611,9 +594,8 @@ class FunctionalTest(test_utils.BaseTestCase): self._reset_database(self.glare_server.sql_connection) def run_sql_cmd(self, sql): - """ - Provides a crude mechanism to run manual SQL commands for backend - DB verification within the functional tests. + """Provides a crude mechanism to run manual SQL commands + for backend DB verification within the functional tests. The raw result set is returned. """ engine = db_api.get_engine() diff --git a/glare/tests/unit/base.py b/glare/tests/unit/base.py index ba79c21..456c24c 100644 --- a/glare/tests/unit/base.py +++ b/glare/tests/unit/base.py @@ -103,8 +103,7 @@ class BaseTestCase(testtools.TestCase): return dst_file_name def config(self, **kw): - """ - Override some configuration values. + """Override some configuration values. The keyword arguments are the names of configuration options to override and their values. diff --git a/glare/tests/unit/db/migrations/test_migrations.py b/glare/tests/unit/db/migrations/test_migrations.py index c19648f..ab2aba2 100644 --- a/glare/tests/unit/db/migrations/test_migrations.py +++ b/glare/tests/unit/db/migrations/test_migrations.py @@ -76,6 +76,7 @@ class WalkVersionsMixin(object): def _migrate_up(self, engine, config, version, with_data=False): """migrate up to a new version of the db. + We allow for data insertion and post checks at every migration version with special _pre_upgrade_### and _check_### functions in the main test. diff --git a/glare/tests/utils.py b/glare/tests/utils.py index 685c0f4..f1fc78a 100644 --- a/glare/tests/utils.py +++ b/glare/tests/utils.py @@ -76,8 +76,8 @@ class BaseTestCase(testtools.TestCase): return dst_file_name def config(self, **kw): - """ - Override some configuration values. + """Override some configuration values. + The keyword arguments are the names of configuration options to override and their values. If a group argument is supplied, the overrides are applied to @@ -142,8 +142,8 @@ def fork_exec(cmd, exec_env=None, logfile=None, pass_fds=None): - """ - Execute a command using fork/exec. + """Execute a command using fork/exec. + This is needed for programs system executions that need path searching but cannot have a shell as their parent process, for example: glare. When glare starts it sets itself as @@ -151,6 +151,7 @@ def fork_exec(cmd, a Popen process would have is not the right pid to use for killing the process group. This patch gives the test env direct access to the actual pid. + :param cmd: Command to execute as an array of arguments. :param exec_env: A dictionary representing the environment with which to run the command. @@ -192,8 +193,8 @@ def fork_exec(cmd, def wait_for_fork(pid, raise_error=True, expected_exitcode=0): - """ - Wait for a process to complete + """Wait for a process to complete + This function will wait for the given pid to complete. If the exit code does not match that of the expected_exitcode an error is raised. @@ -220,11 +221,12 @@ def execute(cmd, expect_exit=True, expected_exitcode=0, context=None): - """ - Executes a command in a subprocess. Returns a tuple - of (exitcode, out, err), where out is the string output - from stdout and err is the string output from stderr when + """Executes a command in a subprocess. + + Returns a tuple of (exitcode, out, err), where out is the string + output from stdout and err is the string output from stderr when executing the command. + :param cmd: Command string to execute :param raise_error: If returncode is not 0 (success), then raise a RuntimeError? Default: True) @@ -291,10 +293,11 @@ def execute(cmd, def find_executable(cmdname): - """ - Searches the path for a given cmdname. Returns an absolute - filename if an executable with the given name exists in the path, - or None if one does not. + """Searches the path for a given cmdname. + + Returns an absolute filename if an executable with the given + name exists in the path, or None if one does not. + :param cmdname: The bare name of the executable to search for """ @@ -317,8 +320,7 @@ def find_executable(cmdname): def get_unused_port(): - """ - Returns an unused port on localhost. + """Returns an unused port on localhost. """ port, s = get_unused_port_and_socket() s.close() @@ -326,8 +328,7 @@ def get_unused_port(): def get_unused_port_and_socket(): - """ - Returns an unused port on localhost and the open socket + """Returns an unused port on localhost and the open socket from which it was created. """ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -337,8 +338,7 @@ def get_unused_port_and_socket(): def xattr_writes_supported(path): - """ - Returns True if the we can write a file to the supplied + """Returns True if the we can write a file to the supplied path and subsequently write a xattr to that file. """ try: