-
Notifications
You must be signed in to change notification settings - Fork 6
Make it easy to create a class that behaves like a Session #832
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
Comments
@gdementen OK to "try" to implement this for the next release (0.33)? |
I had in mind to do a quicker-than-usual release to fix the issues we found during the training (matplotlib import in the viewer, small tutorial/doc changes and the load data >2d without axes names problem), probably as 0.32.1 and then move on to liam2. So I am basically ok with the 0.33 milestone but that will depend when you want to release it. |
If we plan to do a 0.32.1 release, I think there is no reason to make 0.33 release soon. |
Or... If you want to work on it before I am able to (probably somewhere in January), I give you the experimental code I have so far and you do it. So far, I have always linked this "static session" thing to the lazy session feature (see #727), but maybe we could dissociate the two. In that case it's pretty easy. The lazy part is a lot more tricky (when I say tricky, it's not necessarily hard to implement, but rather hard to figure out which behaviour is best for users). |
Related to issue #727 |
See comment #840 (comment) for an example of how the |
This is at least how I saw things. There are probably other options. I just don't think restricting values based on values defined at the class level is a good idea. It is just too weird in the Python world, while there are alternatives which are more usual (restrict on types defined at the class level) or restrict on values defined at the instance level (i.e. values defined in |
In the Demo model, they have a The only thing that bothered me with the proposed "specifications" of the I wonder if there an easy way to also "freeze" the axes of an Array variables defined in the |
… preliminary code written by gdementen)
We can discuss this when I get back in January, if you want.
…On Fri, Dec 20, 2019 at 2:41 PM Alix Damman ***@***.***> wrote:
In the Demo model, they have a Parameters class in which they define all
axes, groups and scalars of the model. The other classes contains only
arrays but inherits from the Session class to mainly take benefit of its
I/O methods. I tried to somewhat "reproduce" what is done in that model
(consider all axes and groups defined in a class as frozen) plus to include
the idea of ArrayDef but I see now that implementing a class just based
on one model is wrong.
The only thing that bothered me with the proposed "specifications" of the
StaticSession is that all axes used in statements like array_var =
ArrayDef(axes) must be defined before the definition of the class and
they cannot depend on any variable with value defined at runtime -->
imagine a TIME axis defined as TIME =
Axis(f'time={first_proj_year}..{last_proj_year}') where first_proj_year
and last_proj_year are defined at runtime.
I wonder if there an easy way to also "freeze" the axes of an Array
variables defined in the __init__ ? method?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#832?email_source=notifications&email_token=AAGLEXHOOFIPWSYKAPMG2Z3QZTDRVA5CNFSM4JS46LZKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEHM6K2Q#issuecomment-567928170>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAGLEXAQJQKHHYU5LO7HGM3QZTDRVANCNFSM4JS46LZA>
.
|
…liminary code written by gdementen)
…on preliminary code written by gdementen)
I wonder if we couldn't try to use the |
What you are saying is that you want something like: class MyDemo(ConstrainedSession):
pop: ArrayDef("age=0..120; gender=female,male; time=1991..2020") ? It sounds like it is not possible with the But:
So, what we may do is to introduce a subclass class ArrayDef(Array):
def __inti__(data=None, axes=None, dtype=None, meta=None):
if axes is not None and not isinstance(axes, AxisCollection):
axes = AxisCollection(axes)
if data is None:
data = np.empty(axes.shape, dtype)
Array.__init__(self, data, axes, dtype, meta) and then: from pydantic import BaseModel
class ConstrainedSession(Session, BaseModel):
...
@pydantic.validator('*')
def validate_variables(cls, v, field):
key = field.name
# --- array with constant axes
if isinstance(field.type_, ArrayDef):
# no axes given in class definition
if not field.value:
# first initialization
if key is not in self.keys()
return v
else:
# compare with current value
try:
self[key].axes.check_compatible(v.axes)
except ValueError as error:
msg = str(error).replace("incompatible axes:", f"incompatible axes for array '{key}':")\
.replace("vs", "was declared as")
raise ValueError(msg)
return v
# axes given in class definition
else:
try:
field.value.axes.check_compatible(v.axes)
except ValueError as error:
msg = str(error).replace("incompatible axes:", f"incompatible axes for array '{key}':")\
.replace("vs", "was declared as")
raise ValueError(msg)
return v and then: class MyDemo(ConstrainedSession):
# axes given in class definition
pop = ArrayDef("age=0..120; gender=female,male; time=1991..2020")
# axes given at instantiation
births: ArrayDef
demo = MyDemo(pop=zeros("age=0..120; gender=female,male; time=1991..2020"),
births=zeros("age=0..120; gender=female,male; time=1991..2020")) |
Indeed. Or, in fact, I would even prefer this (the spelling does not matter that much but the structure does): class MyDemo(ConstrainedSession):
gender = Axis("gender=female,male")
time: Axis
pop: ArrayDef([gender, time])
def init_demo():
time = Axis('time=1991..2020')
return MyDemo(time=time, pop=zeros([MyDemo.gender, time])
I knew about typing but I had hopes for pydantic... Too bad.
Indeed. And I would prefer that too (that's the whole point of my comments), but then what you show do not respect that, so I am confused 😕 ...
Making ArrayDef a subclass of Array should be enough. You do not actually need any data. To trick PyCharm/static analyzers, we do not need the object to be functional. We will not use them anyway.
This is not needed either AFAICT.
Here you use |
I fear an option nobody will use. The option could come later if we have demand for it.
I fear an option nobody will use. The option could come later if we have demand for it OR we could provide a built-in subclass (e.g. Parameters) with that option enabled.
They will not read that section, but a dynamic warning would be annoying, so I would only warn in the doc and wait for users to discover it (or we might show one such example of Constrainted-> normal session in the tutorial section about ConstraintedSession)
I don't really know. I don't like option c) because this severely limits what you can do, but I am unsure about the other options.
|
No, that's not what I have in mind. I only wanted to be able to import the I have started to read the official technical documentation of the SDMX-IM. The document is messy. There discrepancies between the class diagrams and the definitions sections. Testing the code is gonna be fun... |
Providing a built-in subclass
OK
OK to exclude option c) which is indeed too restrictive. |
In fact, even option c might make sense as long as we have both 1) a way to easily convert a ConstrainedSession to a normal Session and 2) we support binary ops between a ConstrainedSession and a normal Session without error even if they differ (either returning a ConstrainedSession or Session). In other words, one more option (I am not saying it is the best option -- I don't know) is to behave differently depending on if we are doing ConstrainedSession + Session or ConstrainedSession + ConstrainedSession. We could be more restrictive in the second case. In short, I still don't know what to do... Sorry, I really don't have a clear mind these days... I guess you will have to pick one an see how it goes in practice. I usually don't like working like that but... |
What I have implemented now (but didn't push yet) is: def opmethod(self, other):
(...)
res.append((name, res_item))
try:
# XXX: print a warning?
ses = self.__class__(res)
except Exception:
ses = Session(res)
return ses in both _bynaryop and _unaryop. |
Me neither... |
Seems good enough for now. We can always refine this later. |
class MyDemo(ConstrainedSession):
gender = Axis("gender=female,male")
time: Axis
pop: ArrayDef([gender, time])
def init_demo():
time = Axis('time=1991..2020')
return MyDemo(time=time, pop=zeros([MyDemo.gender, time])
I was speaking too fast. I finally found some time to take a deeper look inside the pydantic library. AGE = Axis("age=0..120")
GENDER = Axis("gender=female,male")
class MyDemo(ConstrainedSession):
pop: ArrayDef((AGE, GENDER))
def init_demo():
return MyDemo(pop=zeros((AGE, GENDER)) is actually possible with pydantic. Maybe implementing something like |
🎉Yipie!🎉 Now pydantic looks a lot more interesting to me. How does PyCharm behave with such annotations? |
Quiet well actually but I have to say that I recently installed the 2020.1 version of PyCharm. |
…on preliminary code written by gdementen)
…on preliminary code written by gdementen)
…s and CheckedArray classes (based on preliminary code written by gdementen)
…s and CheckedArray classes (based on preliminary code written by gdementen)
…s and CheckedArray classes (based on preliminary code written by gdementen)
…s and ConsArray classes (based on preliminary code written by gdementen)
…s and ArrayConstraint classes (based on preliminary code written by gdementen)
…s and CheckedArray classes (based on preliminary code written by gdementen)
…s and CheckedArray classes (based on preliminary code written by gdementen)
…s and CheckedArray classes (based on preliminary code written by gdementen)
…s and CheckedArray classes (based on preliminary code written by gdementen)
The main idea of the present issue is to benefit from both auto-completion of PyCharm (by defining user classes) and all (nice) features offered by the Session class.
This implies to develop a mechanism to:
self._objects
attribute of Session.Another (big) advantage of using user-defined classes is to reduce significantly the number of global variables and function parameters in the models that are developed in house.
The text was updated successfully, but these errors were encountered: