Hello community,
here is the log from the commit of package python-jupyter_ipywidgets for
openSUSE:Factory checked in at 2017-11-09 13:56:55
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-jupyter_ipywidgets (Old)
and /work/SRC/openSUSE:Factory/.python-jupyter_ipywidgets.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-jupyter_ipywidgets"
Thu Nov 9 13:56:55 2017 rev:7 rq:536939 version:7.0.3
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-jupyter_ipywidgets/python-jupyter_ipywidgets-doc.changes
2017-10-03 23:16:30.876923974 +0200
+++
/work/SRC/openSUSE:Factory/.python-jupyter_ipywidgets.new/python-jupyter_ipywidgets-doc.changes
2017-11-09 13:57:34.427604326 +0100
@@ -1,0 +2,6 @@
+Thu Oct 26 17:28:03 UTC 2017 - [email protected]
+
+- Update to 7.0.3
+ * No changelog
+
+-------------------------------------------------------------------
---
/work/SRC/openSUSE:Factory/python-jupyter_ipywidgets/python-jupyter_ipywidgets.changes
2017-10-03 23:16:30.960912154 +0200
+++
/work/SRC/openSUSE:Factory/.python-jupyter_ipywidgets.new/python-jupyter_ipywidgets.changes
2017-11-09 13:57:37.459493874 +0100
@@ -1,0 +2,6 @@
+Thu Oct 26 17:28:03 UTC 2017 - [email protected]
+
+- Update to 7.0.3
+ * No changelog
+
+-------------------------------------------------------------------
Old:
----
ipywidgets-7.0.1.tar.gz
New:
----
ipywidgets-7.0.3.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-jupyter_ipywidgets-doc.spec ++++++
--- /var/tmp/diff_new_pack.j1lXHg/_old 2017-11-09 13:57:38.167468082 +0100
+++ /var/tmp/diff_new_pack.j1lXHg/_new 2017-11-09 13:57:38.171467937 +0100
@@ -27,7 +27,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-jupyter_ipywidgets-doc
-Version: 7.0.1
+Version: 7.0.3
Release: 0
Summary: Documentation for python-jupyter_ipywidgets
License: BSD-3-Clause
python-jupyter_ipywidgets.spec: same change
++++++ ipywidgets-7.0.1.tar.gz -> ipywidgets-7.0.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ipywidgets-7.0.1/PKG-INFO
new/ipywidgets-7.0.3/PKG-INFO
--- old/ipywidgets-7.0.1/PKG-INFO 2017-09-16 05:29:52.000000000 +0200
+++ new/ipywidgets-7.0.3/PKG-INFO 2017-10-20 22:15:33.000000000 +0200
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: ipywidgets
-Version: 7.0.1
+Version: 7.0.3
Summary: IPython HTML widgets for Jupyter
Home-page: http://ipython.org
Author: IPython Development Team
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ipywidgets-7.0.1/ipywidgets/_version.py
new/ipywidgets-7.0.3/ipywidgets/_version.py
--- old/ipywidgets-7.0.1/ipywidgets/_version.py 2017-09-16 05:28:19.000000000
+0200
+++ new/ipywidgets-7.0.3/ipywidgets/_version.py 2017-10-20 22:15:13.000000000
+0200
@@ -1,7 +1,7 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
-version_info = (7, 0, 1, 'final', 0)
+version_info = (7, 0, 3, 'final', 0)
_specifier_ = {'alpha': 'a', 'beta': 'b', 'candidate': 'rc', 'final': ''}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ipywidgets-7.0.1/ipywidgets/embed.py
new/ipywidgets-7.0.3/ipywidgets/embed.py
--- old/ipywidgets-7.0.1/ipywidgets/embed.py 2017-09-13 04:09:34.000000000
+0200
+++ new/ipywidgets-7.0.3/ipywidgets/embed.py 2017-10-19 23:44:14.000000000
+0200
@@ -13,6 +13,7 @@
import json
from .widgets import Widget, DOMWidget
from .widgets.widget_link import Link
+from .widgets.docutils import doc_subst
from ._version import __html_manager_version__
snippet_template = u"""
@@ -89,14 +90,6 @@
the scripts.
"""
-def _doc_subst(func):
- """ Substitute format strings in class docstring """
- # Strip the snippets to avoid trailing new lines and whitespace
- stripped_snippets = {
- key: snippet.strip() for (key, snippet) in _doc_snippets.items()
- }
- func.__doc__ = func.__doc__.format(**stripped_snippets)
- return func
def _find_widget_refs_by_state(widget, state):
"""Find references to other widgets in a widget's state"""
@@ -187,7 +180,7 @@
return state
-@_doc_subst
+@doc_subst(_doc_snippets)
def embed_data(views, drop_defaults=True, state=None):
"""Gets data for embedding.
@@ -234,7 +227,7 @@
return dict(manager_state=json_data, view_specs=view_specs)
-@_doc_subst
+@doc_subst(_doc_snippets)
def embed_snippet(views,
drop_defaults=True,
state=None,
@@ -277,7 +270,7 @@
return snippet_template.format(**values)
-@_doc_subst
+@doc_subst(_doc_snippets)
def embed_minimal_html(fp, views, title=u'IPyWidget export', template=None,
**kwargs):
"""Write a minimal HTML file with widget views embedded.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ipywidgets-7.0.1/ipywidgets/widgets/docutils.py
new/ipywidgets-7.0.3/ipywidgets/widgets/docutils.py
--- old/ipywidgets-7.0.1/ipywidgets/widgets/docutils.py 1970-01-01
01:00:00.000000000 +0100
+++ new/ipywidgets-7.0.3/ipywidgets/widgets/docutils.py 2017-10-19
23:44:14.000000000 +0200
@@ -0,0 +1,13 @@
+# Copyright (c) Jupyter Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+def doc_subst(snippets):
+ """ Substitute format strings in class or function docstring """
+ def decorator(cls):
+ # Strip the snippets to avoid trailing new lines and whitespace
+ stripped_snippets = {
+ key: snippet.strip() for (key, snippet) in snippets.items()
+ }
+ cls.__doc__ = cls.__doc__.format(**stripped_snippets)
+ return cls
+ return decorator
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/ipywidgets-7.0.1/ipywidgets/widgets/tests/test_docutils.py
new/ipywidgets-7.0.3/ipywidgets/widgets/tests/test_docutils.py
--- old/ipywidgets-7.0.1/ipywidgets/widgets/tests/test_docutils.py
1970-01-01 01:00:00.000000000 +0100
+++ new/ipywidgets-7.0.3/ipywidgets/widgets/tests/test_docutils.py
2017-10-19 23:44:14.000000000 +0200
@@ -0,0 +1,27 @@
+# Copyright (c) Jupyter Development Team.
+# Distributed under the terms of the Modified BSD License.
+
+from unittest import TestCase
+
+from ipywidgets.widgets.docutils import doc_subst
+
+
+class TestDocSubst(TestCase):
+
+ def test_substitution(self):
+ snippets = {'key': '62'}
+
+ @doc_subst(snippets)
+ def f():
+ """ Docstring with value {key} """
+
+ assert f.__doc__ == " Docstring with value 62 "
+
+ def test_unused_keys(self):
+ snippets = {'key': '62', 'other-key': 'unused'}
+
+ @doc_subst(snippets)
+ def f():
+ """ Docstring with value {key} """
+
+ assert f.__doc__ == " Docstring with value 62 "
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/ipywidgets-7.0.1/ipywidgets/widgets/tests/test_set_state.py
new/ipywidgets-7.0.3/ipywidgets/widgets/tests/test_set_state.py
--- old/ipywidgets-7.0.1/ipywidgets/widgets/tests/test_set_state.py
2017-09-05 20:46:54.000000000 +0200
+++ new/ipywidgets-7.0.3/ipywidgets/widgets/tests/test_set_state.py
2017-10-20 21:43:53.000000000 +0200
@@ -5,7 +5,7 @@
import nose.tools as nt
-from traitlets import Bool, Tuple, List, Instance
+from traitlets import Bool, Tuple, List, Instance, CFloat, CInt, Float, Int,
TraitError
from .utils import setup, teardown
@@ -22,6 +22,14 @@
c = List(Bool()).tag(sync=True)
+# A widget with various kinds of number traits
+class NumberWidget(Widget):
+ f = Float().tag(sync=True)
+ cf = CFloat().tag(sync=True)
+ i = Int().tag(sync=True)
+ ci = CInt().tag(sync=True)
+
+
# A widget where the data might be changed on reception:
def transform_fromjson(data, widget):
@@ -123,3 +131,83 @@
# Sanity:
nt.assert_equal(len(buffers), 1)
nt.assert_equal(buffers[0], data[:20].tobytes())
+
+
+def test_set_state_numbers_int():
+ # JS does not differentiate between float/int.
+ # Instead, it formats exact floats as ints in JSON (1.0 -> '1').
+
+ w = NumberWidget()
+ # Set everything with ints
+ w.set_state(dict(
+ f = 1,
+ cf = 2,
+ i = 3,
+ ci = 4,
+ ))
+ # Ensure no update message gets produced
+ nt.assert_equal(len(w.comm.messages), 0)
+
+
+def test_set_state_numbers_float():
+ w = NumberWidget()
+ # Set floats to int-like floats
+ w.set_state(dict(
+ f = 1.0,
+ cf = 2.0,
+ ci = 4.0
+ ))
+ # Ensure no update message gets produced
+ nt.assert_equal(len(w.comm.messages), 0)
+
+
+def test_set_state_float_to_float():
+ w = NumberWidget()
+ # Set floats to float
+ w.set_state(dict(
+ f = 1.2,
+ cf = 2.6,
+ ))
+ # Ensure no update message gets produced
+ nt.assert_equal(len(w.comm.messages), 0)
+
+
+def test_set_state_cint_to_float():
+ w = NumberWidget()
+
+ # Set CInt to float
+ w.set_state(dict(
+ ci = 5.6
+ ))
+ # Ensure an update message gets produced
+ nt.assert_equal(len(w.comm.messages), 1)
+ msg = w.comm.messages[0]
+ data = msg[1]['data']
+ assert data['method'] == 'update'
+ assert data['state'] == {'ci': 5}
+
+
+# This test is disabled, meaning ipywidgets REQUIRES
+# any JSON received to format int-like numbers as ints
+def _x_test_set_state_int_to_int_like():
+ # Note: Setting i to an int-like float will produce an
+ # error, so if JSON producer were to always create
+ # float formatted numbers, this would fail!
+
+ w = NumberWidget()
+ # Set floats to int-like floats
+ w.set_state(dict(
+ i = 3.0
+ ))
+ # Ensure no update message gets produced
+ nt.assert_equal(len(w.comm.messages), 0)
+
+
+def test_set_state_int_to_float():
+ w = NumberWidget()
+
+ # Set Int to float
+ with nt.assert_raises(TraitError):
+ w.set_state(dict(
+ i = 3.5
+ ))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/ipywidgets-7.0.1/ipywidgets/widgets/tests/test_widget_output.py
new/ipywidgets-7.0.3/ipywidgets/widgets/tests/test_widget_output.py
--- old/ipywidgets-7.0.1/ipywidgets/widgets/tests/test_widget_output.py
1970-01-01 01:00:00.000000000 +0100
+++ new/ipywidgets-7.0.3/ipywidgets/widgets/tests/test_widget_output.py
2017-10-19 21:01:03.000000000 +0200
@@ -0,0 +1,80 @@
+import sys
+
+from IPython.display import Markdown, Image
+from ipywidgets import Output
+
+
+def _make_stream_output(text, name):
+ return {
+ 'output_type': 'stream',
+ 'name': name,
+ 'text': text
+ }
+
+
+def test_append_stdout():
+ output = Output()
+
+ # Try appending a message to stdout.
+ output.append_stdout("snakes!")
+ expected = (_make_stream_output("snakes!", "stdout"),)
+ assert output.outputs == expected, repr(output.outputs)
+
+ # Try appending a second message.
+ output.append_stdout("more snakes!")
+ expected += (_make_stream_output("more snakes!", "stdout"),)
+ assert output.outputs == expected, repr(output.outputs)
+
+
+def test_append_stderr():
+ output = Output()
+
+ # Try appending a message to stderr.
+ output.append_stderr("snakes!")
+ expected = (_make_stream_output("snakes!", "stderr"),)
+ assert output.outputs == expected, repr(output.outputs)
+
+ # Try appending a second message.
+ output.append_stderr("more snakes!")
+ expected += (_make_stream_output("more snakes!", "stderr"),)
+ assert output.outputs == expected, repr(output.outputs)
+
+
+def test_append_display_data():
+ output = Output()
+
+ # Try appending a Markdown object.
+ output.append_display_data(Markdown("# snakes!"))
+ expected = (
+ {
+ 'output_type': 'display_data',
+ 'data': {
+ 'text/plain': '<IPython.core.display.Markdown object>',
+ 'text/markdown': '# snakes!'
+ },
+ 'metadata': {}
+ },
+ )
+ assert output.outputs == expected, repr(output.outputs)
+
+ # Now try appending an Image.
+ image_data = b"foobar"
+ image_data_b64 = image_data if sys.version_info[0] < 3 else 'Zm9vYmFy\n'
+
+ output.append_display_data(Image(image_data, width=123, height=456))
+ expected += (
+ {
+ 'output_type': 'display_data',
+ 'data': {
+ 'image/png': image_data_b64,
+ 'text/plain': '<IPython.core.display.Image object>'
+ },
+ 'metadata': {
+ 'image/png': {
+ 'width': 123,
+ 'height': 456
+ }
+ }
+ },
+ )
+ assert output.outputs == expected, repr(output.outputs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ipywidgets-7.0.1/ipywidgets/widgets/widget.py
new/ipywidgets-7.0.3/ipywidgets/widgets/widget.py
--- old/ipywidgets-7.0.1/ipywidgets/widgets/widget.py 2017-09-12
21:06:44.000000000 +0200
+++ new/ipywidgets-7.0.3/ipywidgets/widgets/widget.py 2017-10-20
21:43:53.000000000 +0200
@@ -17,7 +17,7 @@
Undefined)
from ipython_genutils.py3compat import string_types, PY3
from IPython.display import display
-from json import dumps as jsondumps
+from json import loads as jsonloads, dumps as jsondumps
from base64 import standard_b64decode, standard_b64encode
@@ -158,14 +158,6 @@
return False
return True
-def _json_equal(a, b):
- """Compare the JSON strings generated by two objects."""
- # Comparing the JSON strings automatically takes into account the automatic
- # Python conversions that happen, such as tuple to list, when encoding to
- # JSON. We try to make the strings deterministic and small with the options
- # we use.
- return (jsondumps(a, separators=(',',':'), sort_keys=True, allow_nan=False)
- == jsondumps(b, separators=(',',':'), sort_keys=True,
allow_nan=False))
class LoggingHasTraits(HasTraits):
"""A parent class for HasTraits that log.
@@ -647,8 +639,10 @@
# model_state, buffer_paths, buffers
split_value = _remove_buffers({ key: to_json(value, self)})
split_lock = _remove_buffers({ key: self._property_lock[key]})
- # Compare state and buffer_paths
- if (_json_equal(split_value[0], split_lock[0])
+ # A roundtrip conversion through json in the comparison takes care
of
+ # idiosyncracies of how python data structures map to json, for
example
+ # tuples get converted to lists.
+ if (jsonloads(jsondumps(split_value[0])) == split_lock[0]
and split_value[1] == split_lock[1]
and _buffer_list_equal(split_value[2], split_lock[2])):
return False
@@ -743,7 +737,7 @@
continue
elif (isinstance(trait, (Container, Dict)) and
trait.default_value == Undefined and
- len(value) == 0):
+ (value is None or len(value) == 0)):
# Empty container, and dynamic default will be empty
continue
yield key
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ipywidgets-7.0.1/ipywidgets/widgets/widget_box.py
new/ipywidgets-7.0.3/ipywidgets/widgets/widget_box.py
--- old/ipywidgets-7.0.1/ipywidgets/widgets/widget_box.py 2017-09-13
04:09:34.000000000 +0200
+++ new/ipywidgets-7.0.3/ipywidgets/widgets/widget_box.py 2017-10-19
23:44:14.000000000 +0200
@@ -11,6 +11,7 @@
from .widget import register, widget_serialization
from .domwidget import DOMWidget
from .widget_core import CoreWidget
+from .docutils import doc_subst
from traitlets import Unicode, Tuple, CaselessStrEnum
@@ -26,18 +27,8 @@
"""
-def _doc_subst(cls):
- """ Substitute format strings in class docstring """
- # Strip the snippets to avoid trailing new lines and whitespace
- stripped_snippets = {
- key: snippet.strip() for (key, snippet) in _doc_snippets.items()
- }
- cls.__doc__ = cls.__doc__.format(**stripped_snippets)
- return cls
-
-
@register
-@_doc_subst
+@doc_subst(_doc_snippets)
class Box(DOMWidget, CoreWidget):
""" Displays multiple widgets in a group.
@@ -78,7 +69,7 @@
@register
-@_doc_subst
+@doc_subst(_doc_snippets)
class VBox(Box):
""" Displays multiple widgets vertically using the flexible box model.
@@ -98,7 +89,7 @@
@register
-@_doc_subst
+@doc_subst(_doc_snippets)
class HBox(Box):
""" Displays multiple widgets horizontally using the flexible box model.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ipywidgets-7.0.1/ipywidgets/widgets/widget_output.py
new/ipywidgets-7.0.3/ipywidgets/widgets/widget_output.py
--- old/ipywidgets-7.0.1/ipywidgets/widgets/widget_output.py 2017-09-05
20:46:54.000000000 +0200
+++ new/ipywidgets-7.0.3/ipywidgets/widgets/widget_output.py 2017-10-19
21:01:03.000000000 +0200
@@ -12,6 +12,7 @@
import sys
from traitlets import Unicode, Tuple
+from IPython.core.interactiveshell import InteractiveShell
from IPython.display import clear_output
from IPython import get_ipython
@@ -68,3 +69,36 @@
"""Flush stdout and stderr buffers."""
sys.stdout.flush()
sys.stderr.flush()
+
+ def _append_stream_output(self, text, stream_name):
+ """Append a stream output."""
+ self.outputs += (
+ {'output_type': 'stream', 'name': stream_name, 'text': text},
+ )
+
+ def append_stdout(self, text):
+ """Append text to the stdout stream."""
+ self._append_stream_output(text, stream_name='stdout')
+
+ def append_stderr(self, text):
+ """Append text to the stderr stream."""
+ self._append_stream_output(text, stream_name='stderr')
+
+ def append_display_data(self, display_object):
+ """Append a display object as an output.
+
+ Parameters
+ ----------
+ display_object : IPython.core.display.DisplayObject
+ The object to display (e.g., an instance of
+ `IPython.display.Markdown` or `IPython.display.Image`).
+ """
+ fmt = InteractiveShell.instance().display_formatter.format
+ data, metadata = fmt(display_object)
+ self.outputs += (
+ {
+ 'output_type': 'display_data',
+ 'data': data,
+ 'metadata': metadata
+ },
+ )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/ipywidgets-7.0.1/ipywidgets/widgets/widget_selection.py
new/ipywidgets-7.0.3/ipywidgets/widgets/widget_selection.py
--- old/ipywidgets-7.0.1/ipywidgets/widgets/widget_selection.py 2017-09-14
21:36:04.000000000 +0200
+++ new/ipywidgets-7.0.3/ipywidgets/widgets/widget_selection.py 2017-10-19
23:44:14.000000000 +0200
@@ -19,6 +19,7 @@
from .widget_style import Style
from .trait_types import InstanceDict
from .widget import register, widget_serialization
+from .docutils import doc_subst
from traitlets import (Unicode, Bool, Int, Any, Dict, TraitError,
CaselessStrEnum,
Tuple, List, Union, observe, validate)
from ipython_genutils.py3compat import unicode_type
@@ -106,16 +107,6 @@
"""
-def _doc_subst(cls):
- """ Substitute format strings in class docstring """
- # Strip the snippets to avoid trailing new lines and whitespace
- stripped_snippets = {
- key: snippet.strip() for (key, snippet) in _doc_snippets.items()
- }
- cls.__doc__ = cls.__doc__.format(**stripped_snippets)
- return cls
-
-
def _make_options(x):
"""Standardize the options tuple format.
@@ -398,7 +389,7 @@
button_width = Unicode(help="The width of each button.").tag(sync=True)
@register
-@_doc_subst
+@doc_subst(_doc_snippets)
class ToggleButtons(_Selection):
"""Group of toggle buttons that represent an enumeration.
@@ -437,7 +428,7 @@
@register
-@_doc_subst
+@doc_subst(_doc_snippets)
class Dropdown(_Selection):
"""Allows you to select a single item from a dropdown.
@@ -450,7 +441,7 @@
@register
-@_doc_subst
+@doc_subst(_doc_snippets)
class RadioButtons(_Selection):
"""Group of radio buttons that represent an enumeration.
@@ -465,7 +456,7 @@
@register
-@_doc_subst
+@doc_subst(_doc_snippets)
class Select(_Selection):
"""
Listbox that only allows one item to be selected at any given time.
@@ -482,7 +473,7 @@
rows = Int(5, help="The number of rows to display.").tag(sync=True)
@register
-@_doc_subst
+@doc_subst(_doc_snippets)
class SelectMultiple(_MultipleSelection):
"""
Listbox that allows many items to be selected at any given time.
@@ -541,7 +532,7 @@
return proposal.value
@register
-@_doc_subst
+@doc_subst(_doc_snippets)
class SelectionSlider(_SelectionNonempty):
"""
Slider to select a single item from a list or dictionary.
@@ -564,7 +555,7 @@
help="Update the value of the widget as the user is holding the
slider.").tag(sync=True)
@register
-@_doc_subst
+@doc_subst(_doc_snippets)
class SelectionRangeSlider(_MultipleSelectionNonempty):
"""
Slider to select multiple contiguous items from a list.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/ipywidgets-7.0.1/package.json
new/ipywidgets-7.0.3/package.json
--- old/ipywidgets-7.0.1/package.json 2017-09-05 20:46:54.000000000 +0200
+++ new/ipywidgets-7.0.3/package.json 2017-10-19 00:51:03.000000000 +0200
@@ -6,6 +6,7 @@
"build:examples": "lerna run build --scope \"@jupyter-widgets/example-*\"
--include-filtered-dependencies",
"build": "lerna run build --ignore \"@jupyter-widgets/example-*\"",
"update:dependency": "node scripts/update-dependency.js",
+ "integrity": "node scripts/package-integrity.js",
"updated": "lerna updated",
"publish": "npm run clean && npm run build && lerna publish -m \"Publish
npm packages\""
},