示例#1
0
    def _comp_init_app_component(self, property_values):
        # Pop special attribute
        property_values.pop('flx_is_app', None)
        # Pop and apply id if given
        custom_id = property_values.pop('flx_id', None)
        # Pop session or derive from active component
        self._session = None
        session = property_values.pop('flx_session', None)
        if session is not None:
            self._session = session
        else:
            active = loop.get_active_components()  # Note that self is active too
            active = active[-2] if len(active) > 1 else None
            if active is not None:
                self._session = active._session
            else:
                if not this_is_js():
                    self._session = manager.get_default_session()

        # Register this component with the session (sets _id and _uid)
        if self._session is None:
            raise RuntimeError('%s needs a session!' % (custom_id or self._id))
        self._session._register_component(self, custom_id)
        self._root = self._session.app

        # Return whether this instance was instantiated locally
        return custom_id is None
示例#2
0
    def _comp_init_property_values(self, property_values):

        # Init more
        local_inst = self._comp_init_app_component(
            property_values)  # pops items

        # Call original method, only set props if this is instantiated "by the local"
        props2set = {} if local_inst else property_values
        super()._comp_init_property_values(props2set)

        if this_is_js():
            # This is a proxy PyComponent in JavaScript
            assert len(property_values.keys()) == 0
        else:
            # This is a proxy JsComponent in Python
            # Instantiate JavaScript version of this class
            if local_inst is True:  # i.e. only if Python "instantiated" it
                property_values['flx_has_proxy'] = True
                active_components = [
                    c for c in loop.get_active_components()[:-1]
                    if isinstance(c, (PyComponent, JsComponent))
                ]
                self._session.send_command('INSTANTIATE', self.__jsmodule__,
                                           self.__class__.__name__, self._id,
                                           self._flx_init_args,
                                           property_values, active_components)
            del self._flx_init_args
示例#3
0
def time2str(t, utc_offset=None):
    """Convert a time int into a textual representation. If utc_offset is None, the
    representation is in local time. Otherwise the given offset (in hours) is
    used. Use utc_offset=0 for UTC. In all cases the zone is explicit in the result.
    """
    t = to_time_int(t)
    if this_is_js():  # pragma: no cover
        if utc_offset is None:
            utc_offset = -(Date(t * 1000).getTimezoneOffset() // 60)
        t += utc_offset * 3600
        s = Date(t * 1000).toISOString()
        s = s.split(".")[0]
        if utc_offset == 0:
            s += "Z"
        else:
            s += f"{utc_offset:+03.0f}"
    else:  # py
        import datetime

        if utc_offset is None:
            utc_offset = (
                datetime.datetime.fromtimestamp(t) -
                datetime.datetime.utcfromtimestamp(t)).total_seconds() // 3600
        tz = datetime.timezone(datetime.timedelta(hours=utc_offset))
        dt = datetime.datetime.fromtimestamp(t, tz)
        if utc_offset == 0:
            s = dt.strftime("%Y-%m-%dT%H:%M:%SZ")
        else:
            s = dt.strftime("%Y-%m-%dT%H:%M:%S%z")
    return s
示例#4
0
    def _comp_init_property_values(self, property_values):

        # Init more
        local_inst = self._comp_init_app_component(property_values)  # pops items

        # Call original method, only set props if this is instantiated "by the local",
        # except implicit setters (properties who's values are callables).
        props2set = {} if local_inst else property_values
        for name in list(property_values.keys()):
            if callable(property_values[name]):
                props2set[name] = property_values.pop(name)
        super()._comp_init_property_values(props2set)

        if this_is_js():
            # This is a proxy PyComponent in JavaScript
            assert len(property_values.keys()) == 0
        else:
            # This is a proxy JsComponent in Python
            # Instantiate JavaScript version of this class
            if local_inst is True:  # i.e. only if Python "instantiated" it
                property_values['flx_has_proxy'] = True
                active_components = [c for c in loop.get_active_components()[:-1]
                                     if isinstance(c, (PyComponent, JsComponent))]
                self._session.send_command('INSTANTIATE', self.__jsmodule__,
                                           self.__class__.__name__, self._id,
                                           self._flx_init_args, property_values,
                                           active_components)
            del self._flx_init_args
示例#5
0
    def _comp_init_app_component(self, property_values):
        # Pop special attribute
        property_values.pop('flx_is_app', None)
        # Pop and apply id if given
        custom_id = property_values.pop('flx_id', None)
        # Pop session or derive from active component
        self._session = None
        session = property_values.pop('flx_session', None)
        if session is not None:
            self._session = session
        else:
            active = loop.get_active_components()  # Note that self is active too
            active = active[-2] if len(active) > 1 else None
            if active is not None:
                self._session = active._session
            else:
                if not this_is_js():
                    self._session = manager.get_default_session()

        # Register this component with the session (sets _id and _uid)
        if self._session is None:
            raise RuntimeError('%s needs a session!' % (custom_id or self._id))
        self._session._register_component(self, custom_id)
        self._root = self._session.app

        # Return whether this instance was instantiated locally
        return custom_id is None
示例#6
0
    def _comp_init_property_values(self, property_values):
        # This is a good time to register with the session, and
        # instantiate the proxy class. Property values have been set at this
        # point, but init() has not yet been called.
        # Property values must be poped when consumed so that the remainer is used for
        # instantiation of the Widget

        # Keep track of what events are registered at the proxy
        self.__event_types_at_proxy = []

        # Init more
        self._comp_init_app_component(property_values)  # pops items

        # Pop whether this local instance has a proxy at the other side
        self._has_proxy = property_values.pop('flx_has_proxy', False)

        # Call original method
        super()._comp_init_property_values(property_values)

        if this_is_js():
            # This is a local JsComponent in JavaScript
            self._event_listeners = []
        else:
            # This is a local PyComponent in Python
            # A PyComponent always has a corresponding proxy in JS
            self._ensure_proxy_instance(False)
示例#7
0
def now():
    """Get the current time in seconds, as a float."""
    if this_is_js():
        return Date().getTime() / 1000
    else:
        import time

        return time.time()
示例#8
0
 def _proxy_emitter(self, name, *args, **kwargs):
     """ To handle use of placeholder emitters.
     """
     # todo: I am not sure yet whether to allow or disallow it. We disallow now;
     # we can always INVOKE the emitter at the other side if that proves needed
     if this_is_js():
         logger.error('Cannot use emitters of a PyComponent in JS.')
     else:
         logger.error('Cannot use emitters of a JsComponent in Py.')
示例#9
0
 def _proxy_emitter(self, name, *args, **kwargs):
     """ To handle use of placeholder emitters.
     """
     # todo: I am not sure yet whether to allow or disallow it. We disallow now;
     # we can always INVOKE the emitter at the other side if that proves needed
     if this_is_js():
         logger.error('Cannot use emitters of a PyComponent in JS.')
     else:
         logger.error('Cannot use emitters of a JsComponent in Py.')
示例#10
0
def get_year_month_day(t):
    if this_is_js():
        d = Date(t * 1000)
        return d.getFullYear(), d.getMonth() + 1, d.getDate()
    else:
        import datetime

        dt = datetime.datetime.fromtimestamp(t)
        return dt.year, dt.month, dt.day
示例#11
0
def get_tags_and_parts_from_string(s=""):
    """Given a string, return a sorted list of tags, and a list of text parts
    that can be concatenated into the (nearly) original string.

    A bit of normalization is done as well:
    * the tags are made lowercase.
    * Leading and standalone # symbols are cleared.
    * Add a space between tags that are #glued#together.
    * Trim trailing whitespace.

    A valid tag starts with '#' followed by any alphanumerical characters,
    including dash, underscore, forward slash, and anything above 127.
    """

    parts = []
    tags = {}
    tag_start = -1
    tag_end = 0

    for i in range(len(s) + 1):
        cc = ord(s[i]) if i < len(s) else 35
        if tag_start < 0:
            if cc == 35:  # hash symbol (#)
                tag_start = i
                text = s[tag_end:i]
                if len(text) > 0:
                    if len(parts) > 0 and parts[-1][0] != "#":
                        parts[-1] = parts[-1] + text
                    else:
                        parts.append(text)
        else:
            if not is_valid_tag_charcode(cc):
                text = s[tag_start:i]
                if len(text) > 1:  # dont count the # symbol
                    tag = text.lower()
                    parts.append(tag)
                    tags[tag] = tag
                if cc == 35:
                    parts.append(" ")  # add a space #between#tags
                    tag_start = i
                else:
                    tag_start = -1
                    tag_end = i
    if len(parts) > 0:
        last = parts[-1].rstrip()
        if len(last) > 0:
            parts[-1] = last
        else:
            parts.pop(-1)
    tags = tags.values()
    if not this_is_js():
        tags = list(tags)
    tags.sort()
    return tags, parts
示例#12
0
 def dispose(self):
     if this_is_js():
         # The server is leading ...
         raise RuntimeError('Cannot dispose a PyComponent from JS.')
     else:
         # Disposing a JsComponent from JS is like invoking an action;
         # we don't actually dispose ourselves just yet.
         if self._session.status > 0:
             self._session.send_command('INVOKE', self._id, 'dispose', [])
         else:
             super().dispose()
示例#13
0
 def dispose(self):
     if this_is_js():
         # The server is leading ...
         raise RuntimeError('Cannot dispose a PyComponent from JS.')
     else:
         # Disposing a JsComponent from JS is like invoking an action;
         # we don't actually dispose ourselves just yet.
         if self._session.status > 0:
             self._session.send_command('INVOKE', self._id, 'dispose', [])
         else:
             super().dispose()
示例#14
0
def to_time_int(t):
    """Get a time (in int seconds since epoch), given float/str input.
    String inputs can be:

    * 'now': get current time.
    * E.g. '2018-04-24 11:23:00' for a local time (except in Safari :/).
    * E.g. '2018-04-24 11:23:00Z' for a time in UTC.
    * E.g. '2018-04-24 11:23:00+0200' for AMS summertime in this case.

    In the above, one can use a 'T' instead of a space between data and time
    to comply with ISO 8601.
    """
    if this_is_js():
        if isinstance(t, Date):
            t = t.getTime() / 1000
    if isinstance(t, str):
        t = t.strip()
        if this_is_js():  # pragma: no cover
            if t.lower() == "now":
                t = Date().getTime() / 1000
            else:
                if t.count(" ") == 1 and t[10] == " ":
                    t = t.replace(" ", "T")  # Otherwise Safari wont take it
                t = Date(t).getTime() / 1000  # Let browser handle date parsing
        else:  # py
            import datetime

            t = t.replace("T", " ")
            if t.lower() == "now":
                t = datetime.datetime.now().timestamp()
            elif t.endswith("Z") or t[-5] in "-+":  # ISO 8601
                t = (t[:-1] + "+0000") if t.endswith("Z") else t
                t = datetime.datetime.strptime(
                    t, "%Y-%m-%d %H:%M:%S%z").timestamp()
            else:
                t = datetime.datetime.strptime(
                    t, "%Y-%m-%d %H:%M:%S").timestamp()
    if not isinstance(t, (int, float)):
        raise RuntimeError(f"Time must be a number, not {t!r}")
    return int(t)
示例#15
0
    def __init__(self, *init_args, **kwargs):
        # Need to overload this to handle init_args

        if this_is_js():
            # This is a proxy PyComponent in JavaScript.
            # Always instantiated via an INSTANTIATE command from Python.
            assert len(init_args) == 0
            if 'flx_id' not in kwargs:
                raise RuntimeError('Cannot instantiate a PyComponent from JS.')
            super().__init__(**kwargs)
        else:
            # This is a proxy JsComponent in Python.
            # Can be instantiated in Python,
            self._flx_init_args = init_args
            super().__init__(**kwargs)
示例#16
0
 def _emit_at_proxy(self, ev):
     """ Action used by the local component to push an event to the proxy
     component. If the event represents a property-update, the mutation
     is applied, otherwise the event is emitted here.
     """
     if not this_is_js():
         ev = Dict(ev)
     if ev.type in self.__properties__ and hasattr(ev, 'mutation'):
         # Mutate the property - this will cause an emit
         if ev.mutation == 'set':
             super()._mutate(ev.type, ev.new_value)
         else:
             super()._mutate(ev.type, ev.objects, ev.mutation, ev.index)
     else:
         self.emit(ev.type, ev)
示例#17
0
    def __init__(self, *init_args, **kwargs):
        # Need to overload this to handle init_args

        if this_is_js():
            # This is a proxy PyComponent in JavaScript.
            # Always instantiated via an INSTANTIATE command from Python.
            assert len(init_args) == 0
            if 'flx_id' not in kwargs:
                raise RuntimeError('Cannot instantiate a PyComponent from JS.')
            super().__init__(**kwargs)
        else:
            # This is a proxy JsComponent in Python.
            # Can be instantiated in Python,
            self._flx_init_args = init_args
            super().__init__(**kwargs)
示例#18
0
 def _emit_at_proxy(self, ev):
     """ Action used by the local component to push an event to the proxy
     component. If the event represents a property-update, the mutation
     is applied, otherwise the event is emitted here.
     """
     if not this_is_js():
         ev = Dict(ev)
     if ev.type in self.__properties__ and hasattr(ev, 'mutation'):
         # Mutate the property - this will cause an emit
         if ev.mutation == 'set':
             super()._mutate(ev.type, ev.new_value)
         else:
             super()._mutate(ev.type, ev.objects, ev.mutation, ev.index)
     else:
         self.emit(ev.type, ev)
示例#19
0
def generate_uid():
    """Generate a unique id in the form of an 8-char string. The value is
    used to uniquely identify the record of one user. Assuming a user
    who has been creating 100 records a day, for 20 years (about 1M records),
    the chance of a collision for a new record is about 1 in 50 milion.
    """
    chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    n = 8
    nchars = len(chars)  # 52, so 52**8 => 53459728531456 possibilities
    if this_is_js():
        ar = window.Uint32Array(n)
        window.crypto.getRandomValues(ar)
        return "".join([chars[ar[i] % nchars] for i in range(n)])
    else:
        return "".join([chars[int(random() * nchars)] for i in range(n)])
示例#20
0
    def _comp_init_property_values(self, property_values):
        # This is a good time to register with the session, and
        # instantiate the proxy class. Property values have been set at this
        # point, but init() has not yet been called.

        # Keep track of what events are registered at the proxy
        self.__event_types_at_proxy = []

        # Init more
        self._comp_init_app_component(property_values)  # pops items

        # Pop whether this local instance has a proxy at the other side
        self._has_proxy = property_values.pop('flx_has_proxy', False)

        # Call original method
        super()._comp_init_property_values(property_values)

        if this_is_js():
            # This is a local JsComponent in JavaScript
            self._event_listeners = []
        else:
            # This is a local PyComponent in Python
            # A PyComponent always has a corresponding proxy in JS
            self._ensure_proxy_instance(False)
示例#21
0
        |________|
        |________|


* Assume/assert that A1 < A2 and B1 < B2
* No ovelap   : A2 <= B1 or  A1 >= B2
* Some overlap: A2 > B1 and A1 < B2
* A fully in B: A1 >= B1 and A2 <= B2
* B fully in A: A1 <= B1 and A2 >= B2

"""

from pscript import this_is_js
from pscript.stubs import Math, Date, JSON, window, console, RawJS

if this_is_js():  # pragma: no cover
    tools = window.tools
    utils = window.utils
    dt = window.dt  # noqa
    random = Math.random

    def to_int(x):
        RawJS("""
        x = Number(x)
        if (!isFinite(x)) {
            var e = new  Error("TypeError: Cannot convert to int");
            e.name = "TypeError";
            throw e;
        }
        """)
        return Math.floor(x)
示例#22
0
    def _create_one_year_of_data(self, y):
        PSCRIPT_OVERLOAD = False  # noqa

        now = dt.now()
        nowyear, nowmonth, nowday = dt.get_year_month_day(dt.now())
        sy = str(y)
        rr = []

        rpd = list(range(3, 9))  # number of records per day

        for m in range(1, 13):
            sm = f"{m:02}"

            # For each month, we select tags from the tag groups,
            # we may not have all, and we may have duplicates.
            tags = []
            for i in range(1):
                tag_group = self._tag_groups1[int(random() *
                                                  len(self._tag_groups1))]
                for tag in tag_group:
                    tags.append(tag)
            for i in range(2):
                tag_group = self._tag_groups2[int(random() *
                                                  len(self._tag_groups2))]
                for tag in tag_group:
                    tags.append(tag)

            for d in range(1, 32):
                sd = f"{d:02}"

                # Don't make records in the current future
                if y > nowyear:
                    continue
                elif y == nowyear and m > nowmonth:
                    continue
                elif y == nowyear and m == nowmonth and d > nowday:
                    continue

                # Is this date ok?
                if this_is_js():  # pragma: no cover
                    weekday = Date(f"{sy}-{sm}-{sd}").getDay()  # 0 is Sunday
                    # Put some predictable stuff on today, whatever day it is.
                    if y == nowyear and m == nowmonth and d == nowday:
                        for start, stop, tag in [
                            ("08:51", "09:11", "#admin"),
                            ("09:11", "10:27", "#client1 #meeting"),
                            ("10:29", "11:52", "#client1 #code"),
                            ("12:51", "13:32", "#client1 #code"),
                            ("13:32", "14:28", "#client2 #meeting"),
                            ("14:34", "16:11", "#client2 #design"),
                        ]:
                            t1 = dt.to_time_int(f"{sy}-{sm}-{sd}T{start}:00")
                            t2 = dt.to_time_int(f"{sy}-{sm}-{sd}T{stop}:00")
                            if t2 > now:
                                continue
                            works = [
                                "work", "stuff", "things", "administration"
                            ]
                            ds = "Did some " + works[int(
                                random() * len(works))]
                            ds += " " + tag
                            record = self.records.create(t1, t2, ds)
                            record.st = now
                            rr.append(record)
                        continue
                    elif weekday not in (1, 2, 3, 4, 5):
                        continue  # no NaN (invalid date) or weekends
                else:
                    if d > 28:
                        continue  # on Python, during tests

                t1 = dt.to_time_int(f"{sy}-{sm}-{sd}T08:00:00")

                for h in range(rpd[int(random() * len(rpd))]):
                    tag = tags[int(random() * len(tags))]
                    t1 += [0, 10 * 60,
                           20 * 60][int(random() * 3)]  # pause in secs
                    t2 = t1 + 60 * (60 + int(random() * 120))  # 1-3 hours
                    if t2 > now - 60:
                        break
                    works = ["work", "stuff", "things", "administration"]
                    ds = "Did some " + works[int(random() * len(works))]
                    ds += " " + tag
                    record = self.records.create(t1, t2, ds)
                    record.st = now
                    t1 = t2  # next
                    rr.append(record)

        # Store records
        self.records._put_received(*rr)
示例#23
0
    def keep_checking_size_of(self, ob, check=True):
        """ This is a service that the session provides.
        """
        # Gets called by the Widget class for toplevel widgets. That
        # is, toplevel to Flexx: they might not be toplevel for the
        # browser. This method will make sure that they know their size
        # in any case, at least once each second.
        if check:
            self.instances_to_check_size[ob.id] = ob
        else:
            self.instances_to_check_size.pop(ob.id, None)

    def _check_size_of_objects(self):
        for ob in self.instances_to_check_size.values():
            if ob._disposed is False:
                ob.check_real_size()


# In Python, we need some extras for the serializer to work
if this_is_js():
    # Include bsdf.js
    window.flexx = Flexx()
    bsdf = RawJS("flexx.require('bsdf')")
    serializer = bsdf.BsdfSerializer()
    window.flexx.serializer = serializer
else:
    # Import vendored bsdf lite module
    from . import bsdf_lite as bsdf
    serializer = bsdf.BsdfLiteSerializer()
    serializer.__module__ = __name__
示例#24
0
    def keep_checking_size_of(self, ob, check=True):
        """ This is a service that the session provides.
        """
        # Gets called by the Widget class for toplevel widgets. That
        # is, toplevel to Flexx: they might not be toplevel for the
        # browser. This method will make sure that they know their size
        # in any case, at least once each second.
        if check:
            self.instances_to_check_size[ob.id] = ob
        else:
            self.instances_to_check_size.pop(ob.id, None)

    def _check_size_of_objects(self):
        for ob in self.instances_to_check_size.values():
            if ob._disposed is False:
                ob.check_real_size()


# In Python, we need some extras for the serializer to work
if this_is_js():
    # Include bsdf.js
    window.flexx = Flexx()
    bsdf = RawJS("flexx.require('bsdf')")
    serializer = bsdf.BsdfSerializer()
    window.flexx.serializer = serializer
else:
    # Import vendored bsdf lite module
    from . import bsdf_lite as bsdf
    serializer = bsdf.BsdfLiteSerializer()
    serializer.__module__ = __name__