-
Notifications
You must be signed in to change notification settings - Fork 229
time: add time module #327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed (or fixed any issues), please reply here with What to do if you already signed the CLAIndividual signers
Corporate signers
ℹ️ Googlers: Go here for more info. |
@googlebot I signed it! |
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed (or fixed any issues), please reply here with What to do if you already signed the CLAIndividual signers
Corporate signers
ℹ️ Googlers: Go here for more info. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a first pass. Thanks for contributing!
@b5: Thanks for your quick reaction! I have @alandonovan: I'm supporting this PR and will close mine once this one is merged. |
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed (or fixed any issues), please reply here with What to do if you already signed the CLAIndividual signers
Corporate signers
ℹ️ Googlers: Go here for more info. |
@b5 any news on this one? I'm eagerly waiting for time support! ;-P |
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed (or fixed any issues), please reply here with What to do if you already signed the CLAIndividual signers
Corporate signers
ℹ️ Googlers: Go here for more info. |
hi all, I still have a little more cleanup to do here, but wanted to get this set of changes up for review. I've made a bunch of adjustments to the Starlark API based on review feedback. @srebhan, what do you think the signature for the |
@b5 I had |
lib/time/time.go
Outdated
func parseLocation(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { | ||
var s string | ||
if err := starlark.UnpackArgs("location", args, kwargs, "s", &s); err != nil { | ||
return nil, err | ||
} | ||
loc, err := time.LoadLocation(s) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return starlark.String(loc.String()), nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get the use of this function... You put in a location string and get that string out? Why do you need this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this validates system clock time zone locations, users can use it to both confirm the timezone in question is supported by the OS. In the future This could be expanded to return a starlark "location" type that supports timezone conversion
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we then please name the function validate_location()
or similar and return a bool!? Otherwise it is very confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Starlark's error-handling theory is not well developed. It doesn't have exceptions, and I don't think we really want to add them, but this does mean that callers need to "look before they leap", or need a mode in which they succeed but return an error value (e.g. None or perhaps a string) instead of failing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alandonovan right, but parseLocation
suggests that we somehow convert the given location to something else. Instead we simply return the same string in case of success or nil
otherwise. Furthermore, the returned error is totally redundant with checking the string.... My suggestion is to simplify this to return a bool indicating if this is a valid location. So instead of
l, err := parseLocation(..., loc)
if err != nil {...}
you can call
if isValidLocation(..., loc) {...}
lib/time/time.go
Outdated
return starlark.None, err | ||
} | ||
|
||
SleepFunc(time.Duration(dur)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to check SleepFunc
being not nil otherwise we might segfault here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I think that if users set SleepFunc
to nil and try to call SleepFunc
the program should panic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well I don't like panicking on this level. Imagine you expose setting the sleep function to the user script (for whatever reason). Now your whole program will explode without any way for the programmer to intervene. IMO we should either throw an error here or use the default sleep function in presence of SleepFunc
being nil
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @b5 that it's fine to panic here, as it's an application programming error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, but this means we never should expose setting SleepFunc
to the interpreter and thus to the user. To be honest I would make SleepFunc == nil
the default and then run time.Sleep
to circumvent all of this, but it's not my decision. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's fine to insist that the value be non-nil, and simply panic if someone violates that. Users: don't do that.
} | ||
|
||
func now(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { | ||
return Time(NowFunc()), nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to check NowFunc
for not being nil to avoid a segfault here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI NowFunc
cannot return nil
because it is actually time.Now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can be nil if users override the package variable, setting time.NowFunc = nil
. In discussion above Alan & I have agreed it's the package consumer's responsibility to not do that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@b5 thanks for the info, if I get it right, it is acceptable to let if fail then right (leave it as it is now)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep! I think it should be left as is
@b5 I've just removed it |
FYI I renamed the package to |
Sorry for radio silence: I'm on vacation at the moment but will attend to
this PR fully on Monday.
…On Sat, 20 Feb 2021 at 09:32, Nicolas Filotto ***@***.***> wrote:
FYI I renamed the package to starlarktime to remain consistent with other
modules like the json module
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#327 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABLFMP37RNWFAHJWNEUPBBDS77BWPANCNFSM4UNXYUDQ>
.
|
starlark/testdata/time.star
Outdated
assert.eq(10*60*60*1000000, d2.microseconds) | ||
assert.eq(10*60*60*1000000000, d2.nanoseconds) | ||
|
||
# duration == duration = boolean |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove = boolean
here and below
starlarktime/time.go
Outdated
return Time(x.Add(time.Duration(-y))), nil | ||
case Time: | ||
// time - time = duration | ||
if side == starlark.Left { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This condition is (I think) always true, because the left operand is always tested for HasBinary first, so the "else" case is unreachable. Simplify.
starlarktime/time.go
Outdated
return names | ||
} | ||
|
||
// threeway interprets a three-way comparison value cmp (-1, 0, +1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI: in hindsight, the API design that required threeway
was a mistake. Originally it was intended to support floating point NaNs according to IEEE 754, which requires that x < NaN, Nan < x and NaN == x are all false, so you can't represent the result of a "float op float" comparison using a three-valued result (smaller, bigger, equal): one must also know the query operator. But we changed things recently so that floats are totally ordered (NaN > +Inf), otherwise you can't sort floats, so CompareSameType could in principle be simplified to:
CompareSameType(v Value, depth int) (signum int, err error)
starlarktime/time.go
Outdated
@@ -0,0 +1,507 @@ | |||
package starlarktime |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happened to the doc comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alandonovan it has been removed since it was not in a standard format and there is no other module with this kind of documentation
117bdb0
to
6ff124f
Compare
@alandonovan Remarks applied, please check again |
6ff124f
to
a4a3b8a
Compare
Any update on this? :) |
@b5 I cannot resolve conversations, could you please check if it is possible to give me the necessary rights? |
@adonovan @alandonovan We really need this feature for https://github.com/influxdata/telegraf, so it is important for us to finish it and have it in Startlark. Can you still do the review or shall I ask someone else? and if so, who is the new project lead now please? (cc @ssoroka @srebhan) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay. I'll do what I can to help you get this committed today.
lib/time/time.go
Outdated
"parse_location": starlark.NewBuiltin("parse_location", parseLocation), | ||
"now": starlark.NewBuiltin("now", now), | ||
"time": starlark.NewBuiltin("time", newTime), | ||
"parse_time": starlark.NewBuiltin("time", parseTime), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NewBuiltin("parse_time")
lib/time/time.go
Outdated
|
||
func parseLocation(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { | ||
var s string | ||
if err := starlark.UnpackPositionalArgs("location", args, kwargs, 1, &s); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"parse_location" (for consistency)
Though I agree with earlier remarks that "parse" is the wrong verb: it's really "validate" or "canonicalize". Where's the Starlark documentation for this function? Does it ever return a value different from its argument? The Go documentation for LoadLocation suggests the answer is: yes, but only when s is "" (an alias for "UTC"), or "Local", in which case it uses local time: but this doesn't seem like a concept we want to expose to Starlark since it breaks determinism.
I would be inclined to disallow both of these, which would then allow us to make this function be: is_valid_timezone(string) bool.
In any case, we need to spell out the intended behavior of all the functions in this file.
lib/time/time.go
Outdated
case syntax.SLASH: | ||
switch y := y.(type) { | ||
case Duration: | ||
if int64(y) == 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if y == 0
lib/time/time.go
Outdated
if int64(y) == 0 { | ||
return nil, fmt.Errorf("%s division by zero", d.Type()) | ||
} | ||
return starlark.Float(float64(x.Nanoseconds()) / float64(time.Duration(y).Nanoseconds())), nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
starlark.Float(x.Nanoseconds()) / starlark.Float(time.Duration(y).Nanoseconds())
lib/time/time.go
Outdated
if !ok { | ||
return nil, fmt.Errorf("int value out of range (want signed 64-bit value)") | ||
} | ||
if int64(i) == 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if i == 0
lib/time/time.go
Outdated
if int64(i) == 0 { | ||
return nil, fmt.Errorf("%s division by zero", d.Type()) | ||
} | ||
return Duration(x.Nanoseconds() / i), nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simpler: x / Duration(i)
(This is what you used for //, and the behavior is identical.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adonovan you meant d / Duration(i)
, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, quite right.
lib/time/time.go
Outdated
func (d Duration) CompareSameType(op syntax.Token, v starlark.Value, depth int) (bool, error) { | ||
x := time.Duration(d) | ||
y := time.Duration(v.(Duration)) | ||
switch op { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return threeway(op, x, y), nil
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adonovan I'm not sure, I get what you expect here. You would to see the content of the switch block moved into a new private function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, and that function already exists below: it's threeway
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@adonovan I probably miss something obvious but the current function has only 2 parameters while you are trying to call a function with 3 parameters. At best the second parameter could be somehow x-y
but we could get an overflow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, you're right; I'm not really using my brain. What I mean was this, which is less concise that I had imagined:
cmp := 0
if x, y := d, v.(Duration); x < y {
cmp = -1
} else if x > y {
cmp = 1
}
return threeway(op, cmp)
1a8bb0c
to
17a7f7c
Compare
17a7f7c
to
d158e12
Compare
@adonovan Thx for the feedbacks, it is hard to follow it properly since I have no way to resolve the discussions but I think that I addressed your feedbacks, could you please check it again? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks for your patience!
lib/time/time.go
Outdated
// Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". | ||
func parseDuration(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) { | ||
var d Duration | ||
err := starlark.UnpackPositionalArgs("duration", args, kwargs, 1, &d) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"parse_duration"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@alandonovan indeed, fixed
@adonovan Thanks for the impressive review, can you still somehow merge ? or do you at least know who can merge? |
…am versions After a *large* community effort, we've successfully moved two packages from starlib into the "real" standard library in go-starlark: * math: google/starlark-go#357 * time: google/starlark-go#327 Both of these packages have had a great deal of vetting & improvement in the process of migrating. While this does introduce many breaking changes for both packages, both packages have better stability & performance characteristics. Moving forward, we'll try to follow the pattern of developing & testing packages here, and for those deemed worthy, move them up into go-starlark. Once a package lands there, we'll switch starlib to being a strict import-and-document-only, which effectively locks their API. Keeping package APIs locked will cut down on drift, benefitting the broader starlark ecosystem. BREAKING CHANGE: math & time modules have been overhauled. Refer to package documentation for details
…am versions After a *large* community effort, we've successfully moved two packages from starlib into the "real" standard library in go-starlark: * math: google/starlark-go#357 * time: google/starlark-go#327 In addition, both time & math imports have lost thier ".star" suffixes: load("time.star", "time") -> load("time", "time") load("math.star, "math") -> load("math", "math") Both of these packages have had a great deal of vetting & improvement in the process of migrating. While this does introduce many breaking changes for both packages, both packages have better stability & performance characteristics. Moving forward, we'll try to follow the pattern of developing & testing packages here, and for those deemed worthy, move them up into go-starlark. Once a package lands there, we'll switch starlib to being a strict import-and-document-only, which effectively locks their API. Keeping package APIs locked will cut down on drift, benefitting the broader starlark ecosystem. BREAKING CHANGE: math & time modules have been overhauled. Refer to package documentation for details
…am versions After a *large* community effort, we've successfully moved two packages from starlib into the "real" standard library in go-starlark: * math: google/starlark-go#357 * time: google/starlark-go#327 In addition, both time & math imports have lost thier ".star" suffixes: load("time.star", "time") -> load("time", "time") load("math.star, "math") -> load("math", "math") Both of these packages have had a great deal of vetting & improvement in the process of migrating. While this does introduce many breaking changes for both packages, both packages have better stability & performance characteristics. Moving forward, we'll try to follow the pattern of developing & testing packages here, and for those deemed worthy, move them up into go-starlark. Once a package lands there, we'll switch starlib to being a strict import-and-document-only, which effectively locks their API. Keeping package APIs locked will cut down on drift, benefitting the broader starlark ecosystem. BREAKING CHANGE: math & time modules have been overhauled. Refer to package documentation for details
Signed-off-by: b5 sparkle_pony_2000@qri.io
A few notes:
lib/time
based on @alandonovan's feedback from Time and duration module #326doc.go
into other formats. I can remove this to conform to other packages, but if this info can stay & be maintained, I'd be deeply appreciated. Keeping documentation to the code itself has made our lives much easier.