Hello community,

here is the log from the commit of package python-marathon for openSUSE:Factory 
checked in at 2019-03-27 16:22:59
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-marathon (Old)
 and      /work/SRC/openSUSE:Factory/.python-marathon.new.25356 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-marathon"

Wed Mar 27 16:22:59 2019 rev:4 rq:689090 version:0.11.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-marathon/python-marathon.changes  
2018-12-24 11:39:34.601548754 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-marathon.new.25356/python-marathon.changes   
    2019-03-27 16:23:14.839506710 +0100
@@ -1,0 +2,25 @@
+Wed Mar 27 12:00:32 UTC 2019 - [email protected]
+
+- version update to 0.11.0
+  * Added region and zone members to task model. #260
+  * Exception #259
+  * SSE SSL authentication not supported #247
+  * Lack of support for container.networks #243
+  * __init__() got an unexpected keyword argument 'port_mappings' #237
+  * Wrong health check object generated for COMMAND protocol #222
+  * Add support for mesos 1.6 #255 
+  * Possibility for send the full json object on create #252 
+  * events: add a few attributes #251 
+  * install-marathon.sh: do not remove oracle-java7-installer #250 
+  * MarathonClient: set verify when using sse_session #248 
+  * add reset delay api #246 
+  * fixes for issue 244 #245 
+  * Test against 1.4.11 #240 
+  * fix isuuse-238 #239 (yudong2015)
+  * Test against 1.4.10 instead of 1.4.9 #236 
+  * make models.info compatible with 1.4.9 #233 
+  * Fix health check 'command' #231 
+  * Feature/marathon constraint model improvements #229 
+  * Removes id validation from MarathonGroup() #228 
+
+-------------------------------------------------------------------

Old:
----
  marathon-0.9.0.tar.gz

New:
----
  marathon-0.11.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-marathon.spec ++++++
--- /var/tmp/diff_new_pack.WK7uSA/_old  2019-03-27 16:23:15.463506580 +0100
+++ /var/tmp/diff_new_pack.WK7uSA/_new  2019-03-27 16:23:15.467506579 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-marathon
 #
-# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-marathon
-Version:        0.9.0
+Version:        0.11.0
 Release:        0
 Summary:        Marathon Client Library
 License:        MIT
@@ -27,7 +27,8 @@
 Source:         
https://files.pythonhosted.org/packages/source/m/marathon/marathon-%{version}.tar.gz
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  python-rpm-macros
-Requires:       python-requests >= 2.0.0
+Requires:       python-requests >= 2.4.0
+Requires:       python-requests-toolbelt >= 0.4.0
 BuildArch:      noarch
 %python_subpackages
 
@@ -43,6 +44,9 @@
 %install
 %python_install
 
+%check
+# requires Docker and Marathon server installed there
+
 %files %{python_files}
 %license LICENSE
 %{python_sitelib}/*

++++++ marathon-0.9.0.tar.gz -> marathon-0.11.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/PKG-INFO new/marathon-0.11.0/PKG-INFO
--- old/marathon-0.9.0/PKG-INFO 2017-06-21 18:55:35.000000000 +0200
+++ new/marathon-0.11.0/PKG-INFO        2019-01-15 20:14:09.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: marathon
-Version: 0.9.0
+Version: 0.11.0
 Summary: Marathon Client Library
 Home-page: https://github.com/thefactory/marathon-python
 Author: Mike Babineau
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/README.md 
new/marathon-0.11.0/README.md
--- old/marathon-0.9.0/README.md        1970-01-01 01:00:00.000000000 +0100
+++ new/marathon-0.11.0/README.md       2019-01-15 20:07:53.000000000 +0100
@@ -0,0 +1,132 @@
+# marathon-python
+
+[![Build 
Status](https://travis-ci.org/thefactory/marathon-python.svg?branch=master)](https://travis-ci.org/thefactory/marathon-python)
+
+This is a Python library for interfacing with 
[Marathon](https://github.com/mesosphere/marathon) servers via Marathon's [REST 
API](https://mesosphere.github.io/marathon/docs/rest-api.html).
+
+#### Compatibility
+
+* For Marathon 1.6.x, use at least 0.10.0
+* For Marathon 1.4.1, use at least 0.8.13
+* For Marathon 1.1.1, use at least 0.8.1
+* For all version changes, please see `CHANGELOG.md`
+
+If you find a feature that is broken, please submit a PR that adds a test for
+it so it will be fixed and will continue to stay fixed as Marathon changes over
+time.
+
+Just because this library is tested against a specific version of Marathon,
+doesn't necessarily mean that it supports every feature and API Marathon
+provides.
+
+## Installation
+
+#### From PyPi (recommended)
+```bash
+pip install marathon
+```
+
+#### From GitHub
+```bash
+pip install -e [email protected]:thefactory/marathon-python.git#egg=marathon
+```
+
+#### From source
+```bash
+git clone [email protected]:thefactory/marathon-python
+python marathon-python/setup.py install
+```
+
+## Testing
+
+`marathon-python` uses Travis to test the code against different versions of 
Marathon.
+You can run the tests locally on a Linux machine that has docker on it:
+
+### Running The Tests
+
+```bash
+make itests
+```
+
+### Running The Tests Against a Specific Version of Marathon
+
+```bash
+MARATHONVERSION=1.6.322 make itests
+```
+
+## Documentation
+
+API documentation is [here](http://thefactory.github.io/marathon-python).
+
+Or you can build the documentation yourself:
+```bash
+pip install sphinx
+pip install sphinx_rtd_theme
+cd docs/
+make html
+```
+
+The documentation will be in `<project-root>/gh-pages/html`:
+```bash
+open gh-pages/html/index.html
+```
+
+## Basic Usage
+
+Create a `MarathonClient()` instance pointing at your Marathon server(s):
+```python
+>>> from marathon import MarathonClient
+>>> c = MarathonClient('http://localhost:8080')
+
+>>> # or multiple servers:
+>>> c = MarathonClient(['http://host1:8080', 'http://host2:8080'])
+```
+
+Then try calling some methods:
+```python
+>>> c.list_apps()
+[MarathonApp::myapp1, MarathonApp::myapp2]
+```
+
+```python
+>>> from marathon.models import MarathonApp
+>>> c.create_app('myapp3', MarathonApp(cmd='sleep 100', mem=16, cpus=1))
+MarathonApp::myapp3
+```
+
+```python
+>>> app = c.get_app('myapp3')
+>>> app.ports
+[19671]
+>>> app.mem = 32
+>>> c.update_app('myapp3', app)
+{'deploymentId': '83b215a6-4e26-4e44-9333-5c385eda6438', 'version': 
'2014-08-26T07:37:50.462Z'}
+>>> c.get_app('myapp3').mem
+32.0
+```
+
+```python
+>>> c.get_app('myapp3').instances
+1
+>>> c.scale_app('myapp3', instances=3)
+{'deploymentId': '611b89e3-99f2-4d8a-afe1-ec0b83fdbb88', 'version': 
'2014-08-26T07:40:20.121Z'}
+>>> c.get_app('myapp3').instances
+3
+>>> c.scale_app('myapp3', delta=-1)
+{'deploymentId': '1081a99c-55e8-4404-907b-4a3697059848', 'version': 
'2014-08-26T07:43:30.232Z'}
+>>> c.get_app('myapp3').instances
+2
+```
+
+```python
+>>> c.list_tasks('myapp1')
+[MarathonTask:myapp1-1398201790254]
+>>> c.kill_tasks('myapp1', scale=True)
+[MarathonTask:myapp1-1398201790254]
+>>> c.list_tasks('myapp1')
+[]
+```
+
+## License
+
+Open source under the MIT License. See [LICENSE](LICENSE).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon/__init__.py 
new/marathon-0.11.0/marathon/__init__.py
--- old/marathon-0.9.0/marathon/__init__.py     2017-02-22 22:17:07.000000000 
+0100
+++ new/marathon-0.11.0/marathon/__init__.py    2018-08-08 19:24:04.000000000 
+0200
@@ -1,7 +1,6 @@
-import logging
-
 from .client import MarathonClient
 from .models import MarathonResource, MarathonApp, MarathonTask, 
MarathonConstraint
 from .exceptions import MarathonError, MarathonHttpError, NotFoundError, 
InvalidChoiceError
+from .util import get_log
 
-log = logging.getLogger(__name__)
+log = get_log()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon/client.py 
new/marathon-0.11.0/marathon/client.py
--- old/marathon-0.9.0/marathon/client.py       2017-06-21 18:48:06.000000000 
+0200
+++ new/marathon-0.11.0/marathon/client.py      2019-01-15 20:07:53.000000000 
+0100
@@ -8,11 +8,12 @@
 
 import requests
 import requests.exceptions
+from requests_toolbelt.adapters import socket_options
 
 import marathon
 from .models import MarathonApp, MarathonDeployment, MarathonGroup, 
MarathonInfo, MarathonTask, MarathonEndpoint, MarathonQueueItem
-from .exceptions import InternalServerError, NotFoundError, MarathonHttpError, 
MarathonError
-from .models.events import EventFactory
+from .exceptions import ConflictError, InternalServerError, NotFoundError, 
MarathonHttpError, MarathonError, NoResponseError
+from .models.events import EventFactory, MarathonEvent
 from .util import MarathonJsonEncoder, MarathonMinimalJsonEncoder
 
 
@@ -21,7 +22,7 @@
     """Client interface for the Marathon REST API."""
 
     def __init__(self, servers, username=None, password=None, timeout=10, 
session=None,
-                 auth_token=None, verify=True):
+                 auth_token=None, verify=True, sse_session=None):
         """Create a MarathonClient instance.
 
         If multiple servers are specified, each will be tried in succession 
until a non-"Connection Error"-type
@@ -36,11 +37,19 @@
         :param int timeout: Timeout (in seconds) for requests to Marathon
         :param str auth_token: Token-based auth token, used with DCOS + Oauth
         :param bool verify: Enable SSL certificate verification
+        :param requests.session sse_session: requests.session for event stream 
connections, which by default enables tcp keepalive
         """
         if session is None:
             self.session = requests.Session()
         else:
             self.session = session
+        if sse_session is None:
+            self.sse_session = requests.Session()
+            keep_alive = socket_options.TCPKeepAliveAdapter()
+            self.sse_session.mount('http://', keep_alive)
+            self.sse_session.mount('https://', keep_alive)
+        else:
+            self.sse_session = sse_session
         self.servers = servers if isinstance(servers, list) else [servers]
         self.auth = (username, password) if username and password else None
         self.verify = verify
@@ -87,7 +96,7 @@
                     'Error while calling %s: %s', url, str(e))
 
         if response is None:
-            raise MarathonError('No remaining Marathon servers to try')
+            raise NoResponseError('No remaining Marathon servers to try')
 
         if response.status_code >= 500:
             marathon.log.error('Got HTTP {code}: {body}'.format(
@@ -98,6 +107,8 @@
                 code=response.status_code, body=response.text.encode('utf-8')))
             if response.status_code == 404:
                 raise NotFoundError(response)
+            elif response.status_code == 409:
+                raise ConflictError(response)
             else:
                 raise MarathonHttpError(response)
         elif response.status_code >= 300:
@@ -109,19 +120,22 @@
 
         return response
 
-    def _do_sse_request(self, path):
+    def _do_sse_request(self, path, params=None):
         """Query Marathon server for events."""
         for server in list(self.servers):
             url = ''.join([server.rstrip('/'), path])
             try:
-                response = requests.get(
+                response = self.sse_session.get(
                     url,
+                    params=params,
                     stream=True,
                     headers={'Accept': 'text/event-stream'},
-                    auth=self.auth
+                    auth=self.auth,
+                    verify=self.verify,
                 )
             except Exception as e:
-                marathon.log.error('Error while calling %s: %s', url, 
e.message)
+                marathon.log.error(
+                    'Error while calling %s: %s', url, e.message)
             else:
                 if response.ok:
                     return response.iter_lines()
@@ -136,17 +150,18 @@
         """
         return MarathonEndpoint.from_tasks(self.list_tasks())
 
-    def create_app(self, app_id, app):
+    def create_app(self, app_id, app, minimal=True):
         """Create and start an app.
 
         :param str app_id: application ID
         :param :class:`marathon.models.app.MarathonApp` app: the application 
to create
+        :param bool minimal: ignore nulls and empty collections
 
         :returns: the created app (on success)
         :rtype: :class:`marathon.models.app.MarathonApp` or False
         """
         app.id = app_id
-        data = app.to_json()
+        data = app.to_json(minimal=minimal)
         response = self._do_request('POST', '/v2/apps', data=data)
         if response.status_code == 201:
             return self._parse_response(response, MarathonApp)
@@ -156,7 +171,7 @@
     def list_apps(self, cmd=None, embed_tasks=False, embed_counts=False,
                   embed_deployments=False, embed_readiness=False,
                   embed_last_task_failure=False, embed_failures=False,
-                  embed_task_stats=False, app_id=None, **kwargs):
+                  embed_task_stats=False, app_id=None, label=None, **kwargs):
         """List all apps.
 
         :param str cmd: if passed, only show apps with a matching `cmd`
@@ -168,6 +183,7 @@
         :param bool embed_failures: shorthand for embed_last_task_failure
         :param bool embed_task_stats: embed task stats in result
         :param str app_id: if passed, only show apps with an 'id' that matches 
or contains this value
+        :param str label: if passed, only show apps with the selected labels
         :param kwargs: arbitrary search filters
 
         :returns: list of applications
@@ -178,6 +194,8 @@
             params['cmd'] = cmd
         if app_id:
             params['id'] = app_id
+        if label:
+            params['label'] = label
 
         embed_params = {
             'app.tasks': embed_tasks,
@@ -437,7 +455,8 @@
         params = {'force': force}
         response = self._do_request(
             'PUT',
-            
'/v2/groups/{group_id}/versions/{version}'.format(group_id=group_id, 
version=version),
+            '/v2/groups/{group_id}/versions/{version}'.format(
+                group_id=group_id, version=version),
             params=params)
         return response.json()
 
@@ -464,9 +483,9 @@
         :returns: a dict containing the deployment id and version
         :rtype: dict
         """
-        params = {'scaleBy': scale_by}
+        data = {'scaleBy': scale_by}
         response = self._do_request(
-            'PUT', '/v2/groups/{group_id}'.format(group_id=group_id), 
params=params)
+            'PUT', '/v2/groups/{group_id}'.format(group_id=group_id), 
data=json.dumps(data))
         return response.json()
 
     def list_tasks(self, app_id=None, **kwargs):
@@ -658,13 +677,17 @@
         response = self._do_request('GET', '/v2/deployments')
         return self._parse_response(response, MarathonDeployment, is_list=True)
 
-    def list_queue(self):
+    def list_queue(self, embed_last_unused_offers=False):
         """List all the tasks queued up or waiting to be scheduled.
 
         :returns: list of queue items
         :rtype: list[:class:`marathon.models.queue.MarathonQueueItem`]
         """
-        response = self._do_request('GET', '/v2/queue')
+        if embed_last_unused_offers:
+            params = {'embed': 'lastUnusedOffers'}
+        else:
+            params = {}
+        response = self._do_request('GET', '/v2/queue', params=params)
         return self._parse_response(response, MarathonQueueItem, is_list=True, 
resource_name='queue')
 
     def delete_deployment(self, deployment_id, force=False):
@@ -688,6 +711,11 @@
                 'DELETE', 
'/v2/deployments/{deployment}'.format(deployment=deployment_id))
             return response.json()
 
+    def reset_delay(self, app_id):
+        self._do_request(
+            "DELETE", '/v2/queue/{app_id}/delay'.format(app_id=app_id)
+        )
+
     def get_info(self):
         """Get server configuration information.
 
@@ -733,17 +761,27 @@
         response = self._do_request('GET', '/metrics')
         return response.json()
 
-    def event_stream(self, raw=False):
+    def event_stream(self, raw=False, event_types=None):
         """Polls event bus using /v2/events
 
         :param bool raw: if true, yield raw event text, else yield 
MarathonEvent object
+        :param event_types: a list of event types to consume
+        :type event_types: list[type] or list[str]
         :returns: iterator with events
         :rtype: iterator
         """
 
         ef = EventFactory()
 
-        for raw_message in self._do_sse_request('/v2/events'):
+        params = {
+            'event_type': [
+                EventFactory.class_to_event[et] if isinstance(
+                    et, type) and issubclass(et, MarathonEvent) else et
+                for et in event_types or []
+            ]
+        }
+
+        for raw_message in self._do_sse_request('/v2/events', params=params):
             try:
                 _data = raw_message.decode('utf8').split(':', 1)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon/exceptions.py 
new/marathon-0.11.0/marathon/exceptions.py
--- old/marathon-0.9.0/marathon/exceptions.py   2017-03-24 17:33:20.000000000 
+0100
+++ new/marathon-0.11.0/marathon/exceptions.py  2019-01-15 20:07:53.000000000 
+0100
@@ -32,6 +32,10 @@
     pass
 
 
+class ConflictError(MarathonHttpError):
+    pass
+
+
 class InvalidChoiceError(MarathonError):
 
     def __init__(self, param, value, options):
@@ -40,3 +44,7 @@
                 param=param, value=value, options=options
             )
         )
+
+
+class NoResponseError(MarathonError):
+    pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon/models/app.py 
new/marathon-0.11.0/marathon/models/app.py
--- old/marathon-0.9.0/marathon/models/app.py   2017-06-21 18:48:06.000000000 
+0200
+++ new/marathon-0.11.0/marathon/models/app.py  2018-08-08 19:24:04.000000000 
+0200
@@ -6,6 +6,9 @@
 from .container import MarathonContainer
 from .deployment import MarathonDeployment
 from .task import MarathonTask
+from ..util import is_stringy, get_log
+
+log = get_log()
 
 
 class MarathonApp(MarathonResource):
@@ -210,7 +213,21 @@
 
     def __init__(self, command=None, grace_period_seconds=None, 
interval_seconds=None, max_consecutive_failures=None,
                  path=None, port_index=None, protocol=None, 
timeout_seconds=None, ignore_http1xx=None, **kwargs):
-        self.command = command
+
+        if command is None:
+            self.command = None
+        elif is_stringy(command):
+            self.command = {
+                "value": command
+            }
+        elif type(command) is dict and 'value' in command:
+            log.warn('Deprecated: Using command as dict instead of string is 
deprecated')
+            self.command = {
+                "value": command['value']
+            }
+        else:
+            raise ValueError('Invalid command format: {}'.format(command))
+
         self.grace_period_seconds = grace_period_seconds
         self.interval_seconds = interval_seconds
         self.max_consecutive_failures = max_consecutive_failures
@@ -317,7 +334,10 @@
     :param str host: mesos slave running the task
     """
 
-    DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
+    DATETIME_FORMATS = [
+        '%Y-%m-%dT%H:%M:%S.%fZ',
+        '%Y-%m-%dT%H:%M:%SZ',
+    ]
 
     def __init__(self, last_scaling_at=None, last_config_change_at=None):
         self.last_scaling_at = self._to_datetime(last_scaling_at)
@@ -327,7 +347,12 @@
         if (timestamp is None or isinstance(timestamp, datetime)):
             return timestamp
         else:
-            return datetime.strptime(timestamp, self.DATETIME_FORMAT)
+            for fmt in self.DATETIME_FORMATS:
+                try:
+                    return datetime.strptime(timestamp, fmt)
+                except ValueError:
+                    pass
+            raise ValueError('Unrecognized datetime format: 
{}'.format(timestamp))
 
 
 class MarathonTaskStats(MarathonObject):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon/models/base.py 
new/marathon-0.11.0/marathon/models/base.py
--- old/marathon-0.9.0/marathon/models/base.py  2017-06-21 18:48:06.000000000 
+0200
+++ new/marathon-0.11.0/marathon/models/base.py 2018-08-08 19:24:04.000000000 
+0200
@@ -13,7 +13,7 @@
     def __eq__(self, other):
         try:
             return self.__dict__ == other.__dict__
-        except:
+        except Exception:
             return False
 
     def __hash__(self):
@@ -68,9 +68,15 @@
     def __eq__(self, other):
         try:
             return self.__dict__ == other.__dict__
-        except:
+        except Exception:
             return False
 
+    def __hash__(self):
+        # Technically this class shouldn't be hashable because it often
+        # contains mutable fields, but in practice this class is used more
+        # like a record or namedtuple.
+        return hash(self.to_json())
+
     def __str__(self):
         return "{clazz}::".format(clazz=self.__class__.__name__) + 
str(self.__dict__)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon/models/constraint.py 
new/marathon-0.11.0/marathon/models/constraint.py
--- old/marathon-0.9.0/marathon/models/constraint.py    2017-04-19 
23:55:42.000000000 +0200
+++ new/marathon-0.11.0/marathon/models/constraint.py   2018-08-08 
19:24:04.000000000 +0200
@@ -55,3 +55,19 @@
         if len(obj) > 2:
             (field, operator, value) = obj
             return cls(field, operator, value)
+
+    @classmethod
+    def from_string(cls, constraint):
+        """
+        :param str constraint: The string representation of a constraint
+
+        :rtype: :class:`MarathonConstraint`
+        """
+        obj = constraint.split(':')
+        marathon_constraint = cls.from_json(obj)
+
+        if marathon_constraint:
+            return marathon_constraint
+
+        raise ValueError("Invalid string format. "
+                         "Expected `field:operator:value`")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon/models/container.py 
new/marathon-0.11.0/marathon/models/container.py
--- old/marathon-0.9.0/marathon/models/container.py     2017-02-22 
22:17:07.000000000 +0100
+++ new/marathon-0.11.0/marathon/models/container.py    2018-08-08 
19:24:04.000000000 +0200
@@ -11,6 +11,8 @@
     :param docker: docker field (e.g., {"image": "mygroup/myimage"})'
     :type docker: :class:`marathon.models.container.MarathonDockerContainer` 
or dict
     :param str type:
+    :param port_mappings: New in Marathon v1.5. container.docker.port_mappings 
moved here.
+    :type port_mappings: 
list[:class:`marathon.models.container.MarathonContainerPortMapping`] or 
list[dict]
     :param volumes:
     :type volumes: 
list[:class:`marathon.models.container.MarathonContainerVolume`] or list[dict]
     """
@@ -18,11 +20,20 @@
     TYPES = ['DOCKER', 'MESOS']
     """Valid container types"""
 
-    def __init__(self, docker=None, type='DOCKER', volumes=None):
+    def __init__(self, docker=None, type='DOCKER', port_mappings=None, 
volumes=None):
         if type not in self.TYPES:
             raise InvalidChoiceError('type', type, self.TYPES)
         self.type = type
 
+        # Marathon v1.5 moved portMappings from within container.docker object 
directly
+        # under the container object
+        if port_mappings:
+            self.port_mappings = [
+                pm if isinstance(
+                    pm, MarathonContainerPortMapping) else 
MarathonContainerPortMapping().from_json(pm)
+                for pm in (port_mappings or [])
+            ]
+
         if docker:
             self.docker = docker if isinstance(docker, 
MarathonDockerContainer) \
                 else MarathonDockerContainer().from_json(docker)
@@ -49,10 +60,10 @@
     :param bool force_pull_image: Force a docker pull before launching
     """
 
-    NETWORK_MODES = ['BRIDGE', 'HOST', 'NONE']
+    NETWORK_MODES = ['BRIDGE', 'HOST', 'USER', 'NONE']
     """Valid network modes"""
 
-    def __init__(self, image=None, network='HOST', port_mappings=None, 
parameters=None, privileged=None,
+    def __init__(self, image=None, network=None, port_mappings=None, 
parameters=None, privileged=None,
                  force_pull_image=None, **kwargs):
         self.image = image
         if network:
@@ -83,10 +94,10 @@
     :param object labels:
     """
 
-    PROTOCOLS = ['tcp', 'udp']
+    PROTOCOLS = ['tcp', 'udp', 'udp,tcp']
     """Valid protocols"""
 
-    def __init__(self, name=None, container_port=None, host_port=0, 
service_port=None, protocol='tcp', labels=None):
+    def __init__(self, name=None, container_port=None, host_port=None, 
service_port=None, protocol='tcp', labels=None):
         self.name = name
         self.container_port = container_port
         self.host_port = host_port
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon/models/events.py 
new/marathon-0.11.0/marathon/models/events.py
--- old/marathon-0.9.0/marathon/models/events.py        2017-06-21 
18:48:06.000000000 +0200
+++ new/marathon-0.11.0/marathon/models/events.py       2018-08-08 
19:24:04.000000000 +0200
@@ -1,10 +1,13 @@
 """
 This module is used to translate Events from Marathon's EventBus system.
-See: https://mesosphere.github.io/marathon/docs/event-bus.html
+See:
+* https://mesosphere.github.io/marathon/docs/event-bus.html
+* 
https://github.com/mesosphere/marathon/blob/master/src/main/scala/mesosphere/marathon/core/event/Events.scala
 """
 
 from marathon.models.base import MarathonObject
 from marathon.models.app import MarathonHealthCheck
+from marathon.models.task import MarathonIpAddress
 from marathon.models.deployment import MarathonDeploymentPlan
 from marathon.exceptions import MarathonError
 
@@ -19,7 +22,11 @@
     KNOWN_ATTRIBUTES = []
     attribute_name_to_marathon_object = {  # Allows embedding of 
MarathonObjects inside events.
         'health_check': MarathonHealthCheck,
-        'plan': MarathonDeploymentPlan
+        'plan': MarathonDeploymentPlan,
+        'ip_address': MarathonIpAddress,
+    }
+    seq_name_to_singular = {
+        'ip_addresses': 'ip_address',
     }
 
     def __init__(self, event_type, timestamp, **kwargs):
@@ -28,13 +35,25 @@
         for attribute in self.KNOWN_ATTRIBUTES:
             self._set(attribute, kwargs.get(attribute))
 
+    def __to_marathon_object(self, attribute_name, attribute):
+        if attribute_name in self.attribute_name_to_marathon_object:
+            clazz = self.attribute_name_to_marathon_object[attribute_name]
+            # If this attribute already has a Marathon object instantiate it.
+            attribute = clazz.from_json(attribute)
+        return attribute
+
     def _set(self, attribute_name, attribute):
         if not attribute:
             return
-        if attribute_name in self.attribute_name_to_marathon_object:
-            clazz = self.attribute_name_to_marathon_object[attribute_name]
-            attribute = clazz.from_json(
-                attribute)  # If this attribute already has a Marathon object 
instantiate it.
+        # Special handling for lists...
+        if isinstance(attribute, list):
+            name = self.seq_name_to_singular.get(attribute_name)
+            attribute = [
+                self.__to_marathon_object(name, v)
+                for v in attribute
+            ]
+        else:
+            attribute = self.__to_marathon_object(attribute_name, attribute)
         setattr(self, attribute_name, attribute)
 
 
@@ -44,7 +63,7 @@
 
 class MarathonStatusUpdateEvent(MarathonEvent):
     KNOWN_ATTRIBUTES = [
-        'slave_id', 'task_id', 'task_status', 'app_id', 'host', 'ports', 
'version', 'message']
+        'slave_id', 'task_id', 'task_status', 'app_id', 'host', 'ports', 
'version', 'message', 'ip_addresses']
 
 
 class MarathonFrameworkMessageEvent(MarathonEvent):
@@ -68,11 +87,11 @@
 
 
 class MarathonFailedHealthCheckEvent(MarathonEvent):
-    KNOWN_ATTRIBUTES = ['app_id', 'health_check', 'task_id']
+    KNOWN_ATTRIBUTES = ['app_id', 'health_check', 'task_id', 'instance_id']
 
 
 class MarathonHealthStatusChangedEvent(MarathonEvent):
-    KNOWN_ATTRIBUTES = ['app_id', 'health_check', 'task_id', 'alive']
+    KNOWN_ATTRIBUTES = ['app_id', 'health_check', 'task_id', 'instance_id', 
'alive']
 
 
 class MarathonGroupChangeSuccess(MarathonEvent):
@@ -92,7 +111,7 @@
 
 
 class MarathonDeploymentInfo(MarathonEvent):
-    KNOWN_ATTRIBUTES = ['plan']
+    KNOWN_ATTRIBUTES = ['plan', 'current_step']
 
 
 class MarathonDeploymentStepSuccess(MarathonEvent):
@@ -112,7 +131,7 @@
 
 
 class MarathonUnhealthyTaskKillEvent(MarathonEvent):
-    KNOWN_ATTRIBUTES = ['app_id', 'task_id', 'version', 'reason']
+    KNOWN_ATTRIBUTES = ['app_id', 'task_id', 'instance_id', 'version', 
'reason']
 
 
 class MarathonAppTerminatedEvent(MarathonEvent):
@@ -127,7 +146,7 @@
     KNOWN_ATTRIBUTES = ['instance_id', 'run_spec_id', 'condition']
 
 
-class MarathonInstanceHealthChanged(MarathonEvent):
+class MarathonInstanceHealthChangedEvent(MarathonEvent):
     KNOWN_ATTRIBUTES = ['instance_id', 'run_spec_id', 'run_spec_version', 
'healthy']
 
 
@@ -181,12 +200,14 @@
         'instance_changed_event': MarathonInstanceChangedEvent,
         'unknown_instance_terminated_event': MarathonUnknownInstanceTerminated,
         'unhealthy_instance_kill_event': MarathonUnhealthyInstanceKillEvent,
-        'instance_health_changed_event': MarathonInstanceChangedEvent,
+        'instance_health_changed_event': MarathonInstanceHealthChangedEvent,
         'pod_created_event': MarathonPodCreatedEvent,
         'pod_updated_event': MarathonPodUpdatedEvent,
         'pod_deleted_event': MarathonPodDeletedEvent,
     }
 
+    class_to_event = dict((v, k) for k, v in event_to_class.items())
+
     def process(self, event):
         event_type = event['eventType']
         if event_type in self.event_to_class:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon/models/group.py 
new/marathon-0.11.0/marathon/models/group.py
--- old/marathon-0.9.0/marathon/models/group.py 2017-02-22 22:17:07.000000000 
+0100
+++ new/marathon-0.11.0/marathon/models/group.py        2018-08-08 
19:24:04.000000000 +0200
@@ -1,4 +1,4 @@
-from .base import MarathonResource, assert_valid_id
+from .base import MarathonResource
 from .app import MarathonApp
 
 
@@ -36,5 +36,5 @@
         #     p if isinstance(p, MarathonPod) else MarathonPod().from_json(p)
         #     for p in (pods or [])
         # ]
-        self.id = assert_valid_id(id)
+        self.id = id
         self.version = version
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon/models/info.py 
new/marathon-0.11.0/marathon/models/info.py
--- old/marathon-0.9.0/marathon/models/info.py  2017-02-22 22:17:07.000000000 
+0100
+++ new/marathon-0.11.0/marathon/models/info.py 2018-08-08 19:24:04.000000000 
+0200
@@ -74,13 +74,48 @@
     :param int task_launch_timeout:
     :param int task_reservation_timeout:
     :param int marathon_store_timeout:
+    :param str access_control_allow_origin:
+    :param int decline_offer_duration:
+    :param str default_network_name:
+    :param str env_vars_prefix:
+    :param int launch_token:
+    :param int launch_token_refresh_interval:
+    :param int max_instances_per_offer:
+    :param str mesos_bridge_name:
+    :param int mesos_heartbeat_failure_threshold:
+    :param int mesos_heartbeat_interval:
+    :param int min_revive_offers_interval:
+    :param int offer_matching_timeout:
+    :param int on_elected_prepare_timeout:
+    :param bool revive_offers_for_new_apps:
+    :param int revive_offers_repetitions:
+    :param int scale_apps_initial_delay:
+    :param int scale_apps_interval:
+    :param bool store_cache:
+    :param int task_launch_confirm_timeout:
+    :param int task_lost_expunge_initial_delay:
+    :param int task_lost_expunge_interval:
     """
 
     def __init__(self, checkpoint=None, executor=None, failover_timeout=None, 
framework_name=None, ha=None,
                  hostname=None, leader_proxy_connection_timeout_ms=None, 
leader_proxy_read_timeout_ms=None,
                  local_port_min=None, local_port_max=None, master=None, 
mesos_leader_ui_url=None, mesos_role=None, mesos_user=None,
                  webui_url=None, reconciliation_initial_delay=None, 
reconciliation_interval=None,
-                 task_launch_timeout=None, marathon_store_timeout=None, 
task_reservation_timeout=None, features=None):
+                 task_launch_timeout=None, marathon_store_timeout=None, 
task_reservation_timeout=None, features=None,
+                 access_control_allow_origin=None, decline_offer_duration=None,
+                 default_network_name=None, env_vars_prefix=None,
+                 launch_token=None, launch_token_refresh_interval=None,
+                 max_instances_per_offer=None, mesos_bridge_name=None,
+                 mesos_heartbeat_failure_threshold=None,
+                 mesos_heartbeat_interval=None, 
min_revive_offers_interval=None,
+                 offer_matching_timeout=None, on_elected_prepare_timeout=None,
+                 revive_offers_for_new_apps=None,
+                 revive_offers_repetitions=None, scale_apps_initial_delay=None,
+                 scale_apps_interval=None, store_cache=None,
+                 task_launch_confirm_timeout=None,
+                 task_lost_expunge_initial_delay=None,
+                 task_lost_expunge_interval=None
+                 ):
         self.checkpoint = checkpoint
         self.executor = executor
         self.failover_timeout = failover_timeout
@@ -99,6 +134,27 @@
         self.task_launch_timeout = task_launch_timeout
         self.task_reservation_timeout = task_reservation_timeout
         self.marathon_store_timeout = marathon_store_timeout
+        self.access_control_allow_origin = access_control_allow_origin
+        self.decline_offer_duration = decline_offer_duration
+        self.default_network_name = default_network_name
+        self.env_vars_prefix = env_vars_prefix
+        self.launch_token = launch_token
+        self.launch_token_refresh_interval = launch_token_refresh_interval
+        self.max_instances_per_offer = max_instances_per_offer
+        self.mesos_bridge_name = mesos_bridge_name
+        self.mesos_heartbeat_failure_threshold = 
mesos_heartbeat_failure_threshold
+        self.mesos_heartbeat_interval = mesos_heartbeat_interval
+        self.min_revive_offers_interval = min_revive_offers_interval
+        self.offer_matching_timeout = offer_matching_timeout
+        self.on_elected_prepare_timeout = on_elected_prepare_timeout
+        self.revive_offers_for_new_apps = revive_offers_for_new_apps
+        self.revive_offers_repetitions = revive_offers_repetitions
+        self.scale_apps_initial_delay = scale_apps_initial_delay
+        self.scale_apps_interval = scale_apps_interval
+        self.store_cache = store_cache
+        self.task_launch_confirm_timeout = task_launch_confirm_timeout
+        self.task_lost_expunge_initial_delay = task_lost_expunge_initial_delay
+        self.task_lost_expunge_interval = task_lost_expunge_interval
 
 
 class MarathonZooKeeperConfig(MarathonObject):
@@ -115,16 +171,28 @@
     :param str zk_session_timeout:
     :param str zk_state:
     :param int zk_timeout:
+    :param int zk_connection_timeout:
+    :param bool zk_compression:
+    :param int zk_compression_threshold:
+    :param int zk_max_node_size:
     """
 
     def __init__(self, zk=None, zk_future_timeout=None, zk_hosts=None, 
zk_max_versions=None, zk_path=None,
-                 zk_session_timeout=None, zk_state=None, zk_timeout=None):
+                 zk_session_timeout=None, zk_state=None, zk_timeout=None, 
zk_connection_timeout=None,
+                 zk_compression=None, zk_compression_threshold=None,
+                 zk_max_node_size=None):
         self.zk = zk
-        self.zk_future_timeout = zk_future_timeout
         self.zk_hosts = zk_hosts
         self.zk_path = zk_path
         self.zk_state = zk_state
+        self.zk_max_versions = zk_max_versions
         self.zk_timeout = zk_timeout
+        self.zk_connection_timeout = zk_connection_timeout
+        self.zk_future_timeout = zk_future_timeout
+        self.zk_session_timeout = zk_session_timeout
+        self.zk_compression = zk_compression
+        self.zk_compression_threshold = zk_compression_threshold
+        self.zk_max_node_size = zk_max_node_size
 
 
 class MarathonHttpConfig(MarathonObject):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon/models/queue.py 
new/marathon-0.11.0/marathon/models/queue.py
--- old/marathon-0.9.0/marathon/models/queue.py 2017-03-17 18:33:14.000000000 
+0100
+++ new/marathon-0.11.0/marathon/models/queue.py        2017-10-16 
20:29:15.000000000 +0200
@@ -26,7 +26,7 @@
     """
 
     def __init__(self, app=None, overdue=None, count=None, delay=None, 
since=None,
-                 processed_offers_summary=None):
+                 processed_offers_summary=None, last_unused_offers=None):
         self.app = app if isinstance(
             app, MarathonApp) else MarathonApp().from_json(app)
         self.overdue = overdue
@@ -35,6 +35,7 @@
             delay, MarathonQueueItemDelay) else 
MarathonQueueItemDelay().from_json(delay)
         self.since = since
         self.processed_offers_summary = processed_offers_summary
+        self.last_unused_offers = last_unused_offers
 
 
 class MarathonQueueItemDelay(MarathonResource):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon/models/task.py 
new/marathon-0.11.0/marathon/models/task.py
--- old/marathon-0.9.0/marathon/models/task.py  2017-02-22 22:17:07.000000000 
+0100
+++ new/marathon-0.11.0/marathon/models/task.py 2019-01-15 20:07:53.000000000 
+0100
@@ -21,12 +21,17 @@
     :param started_at: when this task was started
     :type started_at: datetime or str
     :param str version: app version with which this task was started
+    :type region: str
+    :param region: fault domain region support in DCOS EE
+    :type zone: str
+    :param zone: fault domain zone support in DCOS EE
     """
 
     DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
 
     def __init__(self, app_id=None, health_check_results=None, host=None, 
id=None, ports=None, service_ports=None,
-                 slave_id=None, staged_at=None, started_at=None, version=None, 
ip_addresses=[], state=None, local_volumes=None):
+                 slave_id=None, staged_at=None, started_at=None, version=None, 
ip_addresses=[], state=None, local_volumes=None,
+                 region=None, zone=None):
         self.app_id = app_id
         self.health_check_results = health_check_results or []
         self.health_check_results = [
@@ -50,6 +55,8 @@
                 ip_addresses, MarathonIpAddress) else 
MarathonIpAddress().from_json(ipaddr)
             for ipaddr in (ip_addresses or [])]
         self.local_volumes = local_volumes or []
+        self.region = region
+        self.zone = zone
 
 
 class MarathonIpAddress(MarathonObject):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon/util.py 
new/marathon-0.11.0/marathon/util.py
--- old/marathon-0.9.0/marathon/util.py 2017-03-24 17:33:20.000000000 +0100
+++ new/marathon-0.11.0/marathon/util.py        2018-08-08 19:24:04.000000000 
+0200
@@ -1,5 +1,6 @@
 import collections
 import datetime
+import logging
 
 try:
     import json
@@ -10,6 +11,10 @@
 from ._compat import string_types
 
 
+def get_log():
+    return logging.getLogger(__name__.split('.')[0])
+
+
 def is_stringy(obj):
     return isinstance(obj, string_types)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon.egg-info/PKG-INFO 
new/marathon-0.11.0/marathon.egg-info/PKG-INFO
--- old/marathon-0.9.0/marathon.egg-info/PKG-INFO       2017-06-21 
18:55:35.000000000 +0200
+++ new/marathon-0.11.0/marathon.egg-info/PKG-INFO      2019-01-15 
20:14:09.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: marathon
-Version: 0.9.0
+Version: 0.11.0
 Summary: Marathon Client Library
 Home-page: https://github.com/thefactory/marathon-python
 Author: Mike Babineau
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon.egg-info/SOURCES.txt 
new/marathon-0.11.0/marathon.egg-info/SOURCES.txt
--- old/marathon-0.9.0/marathon.egg-info/SOURCES.txt    2017-06-21 
18:55:35.000000000 +0200
+++ new/marathon-0.11.0/marathon.egg-info/SOURCES.txt   2019-01-15 
20:14:09.000000000 +0100
@@ -1,5 +1,6 @@
 LICENSE
 MANIFEST.in
+README.md
 setup.cfg
 setup.py
 marathon/__init__.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/marathon.egg-info/requires.txt 
new/marathon-0.11.0/marathon.egg-info/requires.txt
--- old/marathon-0.9.0/marathon.egg-info/requires.txt   2017-06-21 
18:55:35.000000000 +0200
+++ new/marathon-0.11.0/marathon.egg-info/requires.txt  2019-01-15 
20:14:09.000000000 +0100
@@ -1 +1,2 @@
-requests>=2.0.0
+requests>=2.4.0
+requests-toolbelt>=0.4.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/setup.cfg 
new/marathon-0.11.0/setup.cfg
--- old/marathon-0.9.0/setup.cfg        2017-06-21 18:55:35.000000000 +0200
+++ new/marathon-0.11.0/setup.cfg       2019-01-15 20:14:09.000000000 +0100
@@ -4,5 +4,4 @@
 [egg_info]
 tag_build = 
 tag_date = 0
-tag_svn_revision = 0
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/marathon-0.9.0/setup.py new/marathon-0.11.0/setup.py
--- old/marathon-0.9.0/setup.py 2017-06-21 18:52:13.000000000 +0200
+++ new/marathon-0.11.0/setup.py        2019-01-15 20:10:03.000000000 +0100
@@ -8,12 +8,12 @@
 
 setup(
     name='marathon',
-    version='0.9.0',
+    version='0.11.0',
     description='Marathon Client Library',
     long_description="""Python interface to the Mesos Marathon REST API.""",
     author='Mike Babineau',
     author_email='[email protected]',
-    install_requires=['requests>=2.0.0'],
+    install_requires=['requests>=2.4.0', 'requests-toolbelt>=0.4.0'],
     url='https://github.com/thefactory/marathon-python',
     packages=['marathon', 'marathon.models'],
     license='MIT',


Reply via email to