Skip to content
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

Issue273 default values for configuration settings #324

Merged
merged 22 commits into from
Sep 30, 2019

Conversation

juhoinkinen
Copy link
Member

Implemented one initial approach for discussion.

In this good is that default parameters can be included only in the relevant base classes for a backend (e.g. chunksize in ChunkingBackend). The Fasttext and VW params could be included to DEFAULT_PARAMS too (with a bit of work for passing only the backend specific params to the backends).

Not-so-good is maybe the location of this, should it be in project.py instead?

Another completely different approach could be to use to use ConfigParser's defaults implementation.

@codecov
Copy link

codecov bot commented Aug 29, 2019

Codecov Report

Merging #324 into master will decrease coverage by 0.01%.
The diff coverage is 98.98%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #324      +/-   ##
==========================================
- Coverage   99.57%   99.55%   -0.02%     
==========================================
  Files          56       56              
  Lines        3040     3149     +109     
==========================================
+ Hits         3027     3135     +108     
- Misses         13       14       +1
Impacted Files Coverage Δ
tests/test_backend_http.py 100% <ø> (ø) ⬆️
annif/project.py 100% <100%> (ø) ⬆️
annif/backend/fasttext.py 98.76% <100%> (+0.09%) ⬆️
annif/backend/vw_ensemble.py 100% <100%> (ø) ⬆️
annif/backend/dummy.py 100% <100%> (ø) ⬆️
tests/test_backend_tfidf.py 100% <100%> (ø) ⬆️
tests/test_backend_vw_multi.py 100% <100%> (ø) ⬆️
annif/backend/vw_multi.py 100% <100%> (ø) ⬆️
tests/test_backend_vw_ensemble.py 100% <100%> (ø) ⬆️
tests/test_backend.py 100% <100%> (ø) ⬆️
... and 8 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 81994c4...d22cd2d. Read the comment docs.

@lgtm-com
Copy link

lgtm-com bot commented Aug 29, 2019

This pull request introduces 1 alert when merging 4ef0b5a into 2fb6108 - view on LGTM.com

new alerts:

  • 1 for Conflicting attributes in base classes

@lgtm-com
Copy link

lgtm-com bot commented Aug 30, 2019

This pull request introduces 1 alert when merging f8825ed into 2fb6108 - view on LGTM.com

new alerts:

  • 1 for Conflicting attributes in base classes

@osma
Copy link
Member

osma commented Sep 2, 2019

I like the way backend classes (including mixins like ChunkingBackend) declare their own default parameters, but the method for looking them up by accessing the class object seems a bit overcomplicated. I'd prefer to use standard inheritance for this.

How about letting backend classes declare a property that, when accessed, returns the list of default parameter values. The implementation of the property method can then decide whether the defaults are inherited from superclasses or not. The simple case (inherited from AnnifBackend) would just return DEFAULT_PARAMS. Something like:

class AnnifBackend:

    DEFAULT_PARAMS = {'limit': 100}

    @property
    def default_params(self):
        return self.DEFAULT_PARAMS


class ChunkingBackend:

    DEFAULT_PARAMS = {'chunksize': 2}


class FastTextBackend(ChunkingBackend, AnnifBackend):

    DEFAULT_PARAMS = {'loss', 'hs'}  # and others
    
    @property
    def default_params(self):
        # Start with AnnifBackend defaults
        params = AnnifBackend.default_params(self).copy()
        # override with ChunkingBackend defaults
        params.update(ChunkingBackend.default_params(self))
        # override with our own defaults
        params.update(self.DEFAULT_PARAMS)
        return params

Okay, maybe this isn't the simplest method either, but at least backends have full control over which default parameters they wish to inherit from upper classes.

Note that FastTextBackend already has a FASTTEXT_PARAMS field that specifies the types of parameters it supports. VWMultiBackend and VWEnsembleBackend go even further with VW_PARAMS that also specifies some default values. Their implementation of the default_params property could make use of this information.

@osma
Copy link
Member

osma commented Sep 2, 2019

On second thought, maybe @property is not helpful here. default_params could just be a plain method.

@juhoinkinen juhoinkinen added this to the 0.43 milestone Sep 3, 2019
@lgtm-com
Copy link

lgtm-com bot commented Sep 4, 2019

This pull request introduces 1 alert when merging bf58247 into 6ac8431 - view on LGTM.com

new alerts:

  • 1 for Conflicting attributes in base classes

@juhoinkinen juhoinkinen marked this pull request as ready for review September 18, 2019 09:41
def default_params(self):
return self.DEFAULT_PARAMS

def fill_params_with_defaults(self, params):
Copy link
Member Author

@juhoinkinen juhoinkinen Sep 18, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would the params field actually be better to be implemented as a property, and then this would be decorated with @params.setter?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of params being a property. It could be implemented in such a way that it transparently fills in default parameters before returning a dict. And it could have a setter used to set manual parameters (which would be stored in an internal field, say _params). Actually, the filling in could also be done within the setter - then it would only happen once instead of on every access. Accessing the params property would then just return self._params or perhaps a copy() to be safe.

@osma osma mentioned this pull request Sep 24, 2019
@lgtm-com
Copy link

lgtm-com bot commented Sep 25, 2019

This pull request introduces 1 alert when merging 420d3d1 into e449223 - view on LGTM.com

new alerts:

  • 1 for __init__ method calls overridden method

@lgtm-com
Copy link

lgtm-com bot commented Sep 26, 2019

This pull request introduces 1 alert when merging 91136a6 into e449223 - view on LGTM.com

new alerts:

  • 1 for __init__ method calls overridden method

@juhoinkinen
Copy link
Member Author

This pull request introduces 1 alert when merging 91136a6 into e449223 - view on LGTM.com

new alerts:

* 1 for __init__ method calls overridden method

According to this thread the alert could be ignored.

@osma
Copy link
Member

osma commented Sep 30, 2019

Regarding the LGTM alert __init__ method calls overridden method, I think it could be solved like this:

  1. init method doesn't touch self.params, it just sets self.config_params = config_params
  2. params becomes a @property method like this:
    @property
    def params(self):
        params = {}
        params.update(self.default_params())
        params.update(self.config_params)
        return params

With the above implementation of params, there should be no need to call .copy() anywhere.

The benefit of starting from an empty dict and using update, instead of taking a .copy(), is that the default_params() methods in backend subclasses may return anything dict-like, it doesn't have to be an actual dict.

annif/backend/dummy.py Outdated Show resolved Hide resolved
Copy link
Member

@osma osma left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine to merge

@juhoinkinen juhoinkinen merged commit 244db95 into master Sep 30, 2019
@juhoinkinen juhoinkinen deleted the issue273-default-values-for-configuration-settings branch September 30, 2019 13:48
@juhoinkinen
Copy link
Member Author

Edited Wiki pages to shortly mention the parameter defaulting:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants