From 6f6b17b2f8519c2ea073cfb00c1698fa4b877da9 Mon Sep 17 00:00:00 2001 From: Mark Calvert Date: Thu, 25 Jan 2024 08:41:35 +1300 Subject: [PATCH] Refactored OpenFisca rules as code to download tagged versions of the Country Template instead of manually managing Country Template package and rules --- .github/workflows/deploy.yml | 33 +++++ images/rules-as-code/Dockerfile | 34 ++--- images/rules-as-code/bootstrap.sh | 23 +++ .../rules-as-code/openfisca_rules/__init__.py | 41 ------ .../rules-as-code/openfisca_rules/entities.py | 64 --------- .../parameters/benefits/basic_income.yaml | 10 -- .../benefits/housing_allowance.yaml | 13 -- .../parameters/benefits/index.yaml | 9 -- .../benefits/parenting_allowance/amount.yaml | 10 -- .../parenting_allowance/income_threshold.yaml | 10 -- .../parameters/general/age_of_majority.yaml | 9 -- .../parameters/general/age_of_retirement.yaml | 10 -- .../parameters/taxes/housing_tax.yaml | 15 -- .../parameters/taxes/income_tax_rate.yaml | 15 -- .../taxes/social_security_contribution.yaml | 40 ------ .../openfisca_rules/reforms/__init__.py | 7 - .../reforms/add_dynamic_variable.py | 52 ------- .../openfisca_rules/reforms/add_new_tax.py | 58 -------- .../flat_social_security_contribution.py | 34 ----- .../modify_social_security_taxation.py | 57 -------- .../reforms/removal_basic_income.py | 23 --- .../situation_examples/__init__.py | 18 --- .../situation_examples/couple.json | 37 ----- .../situation_examples/housing.json | 23 --- .../situation_examples/single.json | 17 --- .../openfisca_rules/tests/age.yaml | 39 ----- .../openfisca_rules/tests/basic_income.yaml | 50 ------- .../tests/disposable_income.yaml | 65 --------- .../tests/housing_allowance.yaml | 16 --- .../openfisca_rules/tests/housing_tax.yaml | 32 ----- .../openfisca_rules/tests/income_tax.yaml | 9 -- .../tests/reforms/add_dynamic_variable.yaml | 12 -- .../tests/reforms/add_new_tax.yaml | 26 ---- .../modify_social_security_taxation.yaml | 30 ---- .../tests/situations/income_tax.yaml | 31 ---- .../tests/situations/parenting_allowance.yaml | 33 ----- .../tests/social_security_contribution.yaml | 45 ------ .../openfisca_rules/variables/__init__.py | 7 - .../openfisca_rules/variables/benefits.py | 134 ------------------ .../openfisca_rules/variables/demographics.py | 50 ------- .../openfisca_rules/variables/housing.py | 58 -------- .../openfisca_rules/variables/income.py | 42 ------ .../openfisca_rules/variables/stats.py | 50 ------- .../openfisca_rules/variables/taxes.py | 83 ----------- images/rules-as-code/setup.cfg | 38 ----- images/rules-as-code/setup.py | 45 ------ 46 files changed, 73 insertions(+), 1484 deletions(-) create mode 100644 images/rules-as-code/bootstrap.sh delete mode 100644 images/rules-as-code/openfisca_rules/__init__.py delete mode 100644 images/rules-as-code/openfisca_rules/entities.py delete mode 100644 images/rules-as-code/openfisca_rules/parameters/benefits/basic_income.yaml delete mode 100644 images/rules-as-code/openfisca_rules/parameters/benefits/housing_allowance.yaml delete mode 100644 images/rules-as-code/openfisca_rules/parameters/benefits/index.yaml delete mode 100644 images/rules-as-code/openfisca_rules/parameters/benefits/parenting_allowance/amount.yaml delete mode 100644 images/rules-as-code/openfisca_rules/parameters/benefits/parenting_allowance/income_threshold.yaml delete mode 100644 images/rules-as-code/openfisca_rules/parameters/general/age_of_majority.yaml delete mode 100644 images/rules-as-code/openfisca_rules/parameters/general/age_of_retirement.yaml delete mode 100644 images/rules-as-code/openfisca_rules/parameters/taxes/housing_tax.yaml delete mode 100644 images/rules-as-code/openfisca_rules/parameters/taxes/income_tax_rate.yaml delete mode 100644 images/rules-as-code/openfisca_rules/parameters/taxes/social_security_contribution.yaml delete mode 100644 images/rules-as-code/openfisca_rules/reforms/__init__.py delete mode 100644 images/rules-as-code/openfisca_rules/reforms/add_dynamic_variable.py delete mode 100644 images/rules-as-code/openfisca_rules/reforms/add_new_tax.py delete mode 100644 images/rules-as-code/openfisca_rules/reforms/flat_social_security_contribution.py delete mode 100644 images/rules-as-code/openfisca_rules/reforms/modify_social_security_taxation.py delete mode 100644 images/rules-as-code/openfisca_rules/reforms/removal_basic_income.py delete mode 100644 images/rules-as-code/openfisca_rules/situation_examples/__init__.py delete mode 100644 images/rules-as-code/openfisca_rules/situation_examples/couple.json delete mode 100644 images/rules-as-code/openfisca_rules/situation_examples/housing.json delete mode 100644 images/rules-as-code/openfisca_rules/situation_examples/single.json delete mode 100644 images/rules-as-code/openfisca_rules/tests/age.yaml delete mode 100644 images/rules-as-code/openfisca_rules/tests/basic_income.yaml delete mode 100644 images/rules-as-code/openfisca_rules/tests/disposable_income.yaml delete mode 100644 images/rules-as-code/openfisca_rules/tests/housing_allowance.yaml delete mode 100644 images/rules-as-code/openfisca_rules/tests/housing_tax.yaml delete mode 100644 images/rules-as-code/openfisca_rules/tests/income_tax.yaml delete mode 100644 images/rules-as-code/openfisca_rules/tests/reforms/add_dynamic_variable.yaml delete mode 100644 images/rules-as-code/openfisca_rules/tests/reforms/add_new_tax.yaml delete mode 100644 images/rules-as-code/openfisca_rules/tests/reforms/modify_social_security_taxation.yaml delete mode 100644 images/rules-as-code/openfisca_rules/tests/situations/income_tax.yaml delete mode 100644 images/rules-as-code/openfisca_rules/tests/situations/parenting_allowance.yaml delete mode 100644 images/rules-as-code/openfisca_rules/tests/social_security_contribution.yaml delete mode 100644 images/rules-as-code/openfisca_rules/variables/__init__.py delete mode 100644 images/rules-as-code/openfisca_rules/variables/benefits.py delete mode 100644 images/rules-as-code/openfisca_rules/variables/demographics.py delete mode 100644 images/rules-as-code/openfisca_rules/variables/housing.py delete mode 100644 images/rules-as-code/openfisca_rules/variables/income.py delete mode 100644 images/rules-as-code/openfisca_rules/variables/stats.py delete mode 100644 images/rules-as-code/openfisca_rules/variables/taxes.py delete mode 100644 images/rules-as-code/setup.cfg delete mode 100644 images/rules-as-code/setup.py diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b8cb230..1f07476 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -1,6 +1,39 @@ name: Deploy images + on: - push + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + jobs: delploy: runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker image + id: meta_openfisca + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: ./images/rules-as-code + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta_openfisca.outputs.tags }} diff --git a/images/rules-as-code/Dockerfile b/images/rules-as-code/Dockerfile index d7f5fbf..a83aec0 100644 --- a/images/rules-as-code/Dockerfile +++ b/images/rules-as-code/Dockerfile @@ -1,26 +1,26 @@ -FROM uselagoon/python-3.9:latest as build +FROM uselagoon/python-3.11:latest -WORKDIR /app/ - -RUN apk add gcc libc-dev g++ linux-headers yaml-dev -RUN pip wheel --wheel-dir=/app/wheel numpy==1.20.* numexpr==2.8.* psutil PyYAML - - -FROM uselagoon/python-3.9:latest +ENV COUNTRY_TEMPLATE_VERSION=6.0.1 +ENV OPENFISCA_CORE_VERSION=41.4.1 +ENV COUNTRY_NAME=rules EXPOSE 3000 +WORKDIR /app -ARG PROJECT_NAME=rule -COPY openfisca_$PROJECT_NAME /app/openfisca_$PROJECT_NAME -COPY README.md setup.cfg setup.py /app/ +# Install OpenFisca-Core dependencies +RUN apk add build-base linux-headers yaml-dev -WORKDIR /app/ +# Install OpenFisca-Core +RUN pip install OpenFisca-Core[web-api]==$OPENFISCA_CORE_VERSION -COPY --from=build /app/ /app/ -COPY README.md /app/openfisca_$PROJECT_NAME -RUN apk add gcc libc-dev g++ linux-headers yaml-dev libffi-dev -RUN pip install --no-index --find-links=/app/wheel numpy numexpr psutil PyYAML -RUN pip install -e /app +# Install country-template +ADD https://github.com/openfisca/country-template/archive/refs/tags/$COUNTRY_TEMPLATE_VERSION.tar.gz /app +RUN tar -xzf /app/$COUNTRY_TEMPLATE_VERSION.tar.gz -C /app && \ + rm /app/$COUNTRY_TEMPLATE_VERSION.tar.gz && \ + mv /app/country-template-$COUNTRY_TEMPLATE_VERSION /app/country-template +# Copy bootstrap.sh to country-template and run it +COPY bootstrap.sh /app +RUN . /app/bootstrap.sh ENTRYPOINT ["openfisca", "serve", "--bind", "0.0.0.0:3000"] diff --git a/images/rules-as-code/bootstrap.sh b/images/rules-as-code/bootstrap.sh new file mode 100644 index 0000000..9036cc5 --- /dev/null +++ b/images/rules-as-code/bootstrap.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -e + +lowercase_country_name=$(echo $COUNTRY_NAME | tr '[:upper:]' '[:lower:]') + +mv country-template openfisca-$lowercase_country_name +cd openfisca-$lowercase_country_name +all_module_files=`find openfisca_country_template -type f ! -name "*.DS_Store"` + +set -x + +# Use intermediate backup files (`-i`) with a weird syntax due to lack of portable 'no backup' option. See https://stackoverflow.com/q/5694228/594053. +sed -i.template "s|country_template|$lowercase_country_name|g" setup.py setup.cfg Makefile MANIFEST.in $all_module_files +sed -i.template "s|Country-Template|$COUNTRY_NAME|g" setup.py $all_module_files +find . -name "*.template" -type f -delete + +set +x + +mv openfisca_country_template openfisca_$lowercase_country_name + +# Install OpenFisca country template +pip install -e . \ No newline at end of file diff --git a/images/rules-as-code/openfisca_rules/__init__.py b/images/rules-as-code/openfisca_rules/__init__.py deleted file mode 100644 index a1ca8a9..0000000 --- a/images/rules-as-code/openfisca_rules/__init__.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -This file defines our country's tax and benefit system. - -A tax and benefit system is the higher-level instance in OpenFisca. -Its goal is to model the legislation of a country. -Basically a tax and benefit system contains simulation variables (source code) and legislation parameters (data). - -See https://openfisca.org/doc/key-concepts/tax_and_benefit_system.html -""" - -import os - -from openfisca_core.taxbenefitsystems import TaxBenefitSystem - -from openfisca_country_template import entities -from openfisca_country_template.situation_examples import couple - - -COUNTRY_DIR = os.path.dirname(os.path.abspath(__file__)) - - -# Our country tax and benefit class inherits from the general TaxBenefitSystem class. -# The name CountryTaxBenefitSystem must not be changed, as all tools of the OpenFisca ecosystem expect a CountryTaxBenefitSystem class to be exposed in the __init__ module of a country package. -class CountryTaxBenefitSystem(TaxBenefitSystem): - def __init__(self): - # We initialize our tax and benefit system with the general constructor - super().__init__(entities.entities) - - # We add to our tax and benefit system all the variables - self.add_variables_from_directory(os.path.join(COUNTRY_DIR, "variables")) - - # We add to our tax and benefit system all the legislation parameters defined in the parameters files - param_path = os.path.join(COUNTRY_DIR, "parameters") - self.load_parameters(param_path) - - # We define which variable, parameter and simulation example will be used in the OpenAPI specification - self.open_api_config = { - "variable_example": "disposable_income", - "parameter_example": "taxes.income_tax_rate", - "simulation_example": couple, - } diff --git a/images/rules-as-code/openfisca_rules/entities.py b/images/rules-as-code/openfisca_rules/entities.py deleted file mode 100644 index 297bed6..0000000 --- a/images/rules-as-code/openfisca_rules/entities.py +++ /dev/null @@ -1,64 +0,0 @@ -""" -This file defines the entities needed by our legislation. - -Taxes and benefits can be calculated for different entities: persons, household, companies, etc. - -See https://openfisca.org/doc/key-concepts/person,_entities,_role.html -""" - -from openfisca_core.entities import build_entity - -Household = build_entity( - key = "household", - plural = "households", - label = "All the people in a family or group who live together in the same place.", - doc = """ - Household is an example of a group entity. - A group entity contains one or more individual·s. - Each individual in a group entity has a role (e.g. parent or children). Some roles can only be held by a limited number of individuals (e.g. a 'first_parent' can only be held by one individual), while others can have an unlimited number of individuals (e.g. 'children'). - - Example: - Housing variables (e.g. housing_tax') are usually defined for a group entity such as 'Household'. - - Usage: - Check the number of individuals of a specific role (e.g. check if there is a 'second_parent' with household.nb_persons(Household.SECOND_PARENT)). - Calculate a variable applied to each individual of the group entity (e.g. calculate the 'salary' of each member of the 'Household' with salaries = household.members("salary", period = MONTH); sum_salaries = household.sum(salaries)). - - For more information, see: https://openfisca.org/doc/coding-the-legislation/50_entities.html - """, - roles = [ - { - "key": "parent", - "plural": "parents", - "label": "Parents", - "max": 2, - "subroles": ["first_parent", "second_parent"], - "doc": "The one or two adults in charge of the household.", - }, - { - "key": "child", - "plural": "children", - "label": "Child", - "doc": "Other individuals living in the household.", - }, - ], - ) - -Person = build_entity( - key = "person", - plural = "persons", - label = "An individual. The minimal legal entity on which a legislation might be applied.", - doc = """ - - Variables like 'salary' and 'income_tax' are usually defined for the entity 'Person'. - - Usage: - Calculate a variable applied to a 'Person' (e.g. access the 'salary' of a specific month with person("salary", "2017-05")). - Check the role of a 'Person' in a group entity (e.g. check if a the 'Person' is a 'first_parent' in a 'Household' entity with person.has_role(Household.FIRST_PARENT)). - - For more information, see: https://openfisca.org/doc/coding-the-legislation/50_entities.html - """, - is_person = True, - ) - -entities = [Household, Person] diff --git a/images/rules-as-code/openfisca_rules/parameters/benefits/basic_income.yaml b/images/rules-as-code/openfisca_rules/parameters/benefits/basic_income.yaml deleted file mode 100644 index 901d65f..0000000 --- a/images/rules-as-code/openfisca_rules/parameters/benefits/basic_income.yaml +++ /dev/null @@ -1,10 +0,0 @@ -description: Amount of the basic income -metadata: - reference: https://law.gov.example/basic-income/amount - unit: currency-EUR -values: - # This parameter is only defined since the 1st of Dec 2015. - 2015-12-01: - value: 600.0 - metadata: - reference: https://law.gov.example/basic-income/amount/2015-12 diff --git a/images/rules-as-code/openfisca_rules/parameters/benefits/housing_allowance.yaml b/images/rules-as-code/openfisca_rules/parameters/benefits/housing_allowance.yaml deleted file mode 100644 index 88af989..0000000 --- a/images/rules-as-code/openfisca_rules/parameters/benefits/housing_allowance.yaml +++ /dev/null @@ -1,13 +0,0 @@ -description: Housing allowance amount (as a fraction of the rent) -metadata: - unit: /1 - reference: https://law.gov.example/housing-allowance-rate -documentation: | - A fraction of the rent. - From the 1st of Dec 2016, the housing allowance no longer exists. -values: - # This parameter is only defined from the 1st of Jan 2010 to the 3Oth of Nov 2016. - 2010-01-01: - value: 0.25 - 2016-12-01: - value: null diff --git a/images/rules-as-code/openfisca_rules/parameters/benefits/index.yaml b/images/rules-as-code/openfisca_rules/parameters/benefits/index.yaml deleted file mode 100644 index 7e58f58..0000000 --- a/images/rules-as-code/openfisca_rules/parameters/benefits/index.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# This (optional) file defines metadata for the node parameters.benefits in the parameter tree. - -description: Social benefits -documentation: | - Government support for the citizens and residents of society. - They may be provided to people of any income level, as with social security, - but usually it is intended to ensure that everyone can meet their basic human needs - such as food and shelter. - (See https://en.wikipedia.org/wiki/Welfare) diff --git a/images/rules-as-code/openfisca_rules/parameters/benefits/parenting_allowance/amount.yaml b/images/rules-as-code/openfisca_rules/parameters/benefits/parenting_allowance/amount.yaml deleted file mode 100644 index 58a9b12..0000000 --- a/images/rules-as-code/openfisca_rules/parameters/benefits/parenting_allowance/amount.yaml +++ /dev/null @@ -1,10 +0,0 @@ -description: Parenting allowance amount -metadata: - reference: https://law.gov.example/parenting_allowance/amount - unit: currency-EUR -values: - # This parameter is only defined since the 1st of Dec 2015. - 2015-12-01: - value: 600.0 - metadata: - reference: https://law.gov.example/parenting-allowance/amount/2015-12 diff --git a/images/rules-as-code/openfisca_rules/parameters/benefits/parenting_allowance/income_threshold.yaml b/images/rules-as-code/openfisca_rules/parameters/benefits/parenting_allowance/income_threshold.yaml deleted file mode 100644 index cefcc2c..0000000 --- a/images/rules-as-code/openfisca_rules/parameters/benefits/parenting_allowance/income_threshold.yaml +++ /dev/null @@ -1,10 +0,0 @@ -description: Parenting allowance income threshold -metadata: - reference: https://law.gov.example/parenting_allowance/income_threshold - unit: currency-EUR -values: - # This parameter is only defined since the 1st of Dec 2015. - 2015-12-01: - value: 500.0 - metadata: - reference: https://law.gov.example/parenting-allowance/income-threshold/2015-12 diff --git a/images/rules-as-code/openfisca_rules/parameters/general/age_of_majority.yaml b/images/rules-as-code/openfisca_rules/parameters/general/age_of_majority.yaml deleted file mode 100644 index 4bd5222..0000000 --- a/images/rules-as-code/openfisca_rules/parameters/general/age_of_majority.yaml +++ /dev/null @@ -1,9 +0,0 @@ -description: Age of majority (in years) -metadata: - unit: year -values: - # This parameter has last changed on the 1st of Jan 1971. - 1945-01-01: - value: 21.0 - 1971-01-01: - value: 18.0 diff --git a/images/rules-as-code/openfisca_rules/parameters/general/age_of_retirement.yaml b/images/rules-as-code/openfisca_rules/parameters/general/age_of_retirement.yaml deleted file mode 100644 index bdce696..0000000 --- a/images/rules-as-code/openfisca_rules/parameters/general/age_of_retirement.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# A parameter can contain utf-8 characters. -description: Age of retirement (in years). In French âge de la retraite (en années). -metadata: - reference: https://fr.wikipedia.org/wiki/Retraite_(économie) - unit: year -values: - 2017-01-01: - value: 62.0 - 1951-07-01: - value: 60.33 diff --git a/images/rules-as-code/openfisca_rules/parameters/taxes/housing_tax.yaml b/images/rules-as-code/openfisca_rules/parameters/taxes/housing_tax.yaml deleted file mode 100644 index c0439cc..0000000 --- a/images/rules-as-code/openfisca_rules/parameters/taxes/housing_tax.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# One Yaml file can contain nested parameters -description: Housing tax -rate: - description: Housing tax due per square meter. - metadata: - unit: currency-EUR/m2 - values: - 2010-01-01: 10 -minimal_amount: - description: Minimal amount due for the housing tax - metadata: - unit: currency-EUR - values: - 2010-01-01: 200 -documentation: The housing tax, introduced in 2010, is proportional to the surface area of the habitation, with a minimal amount. diff --git a/images/rules-as-code/openfisca_rules/parameters/taxes/income_tax_rate.yaml b/images/rules-as-code/openfisca_rules/parameters/taxes/income_tax_rate.yaml deleted file mode 100644 index c507b0c..0000000 --- a/images/rules-as-code/openfisca_rules/parameters/taxes/income_tax_rate.yaml +++ /dev/null @@ -1,15 +0,0 @@ -description: Income tax rate -metadata: - unit: /1 -values: - 2012-01-01: - value: 0.16 - 2013-01-01: - value: 0.13 - 2014-01-01: - value: 0.14 - 2015-01-01: - value: 0.15 - # We expect this parameter to change on the 1st of Jan 2016 - # Placeholders have no impact on calculations. They are just metadata to indicate that we expect a parameter to change at a certain date. - 2016-01-01: expected diff --git a/images/rules-as-code/openfisca_rules/parameters/taxes/social_security_contribution.yaml b/images/rules-as-code/openfisca_rules/parameters/taxes/social_security_contribution.yaml deleted file mode 100644 index b834be9..0000000 --- a/images/rules-as-code/openfisca_rules/parameters/taxes/social_security_contribution.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# The social_security_contribution is calculated with a marginal scale. Marginal scales are represented with a specific structure. -description: Social security contribution tax scale -metadata: - threshold_unit: currency-EUR - rate_unit: /1 -brackets: -- rate: - 2013-01-01: - value: 0.03 - 2015-01-01: - value: 0.04 - 2017-01-01: - value: 0.02 - threshold: - 2013-01-01: - value: 0.0 -- rate: - 2013-01-01: - value: 0.1 - 2015-01-01: - value: 0.12 - 2017-01-01: - value: 0.06 - threshold: - 2013-01-01: - value: 12000.0 - 2014-01-01: - value: 12100.0 - 2015-01-01: - value: 12200.0 - 2016-01-01: - value: 12300.0 - 2017-01-01: - value: 6000.0 -- rate: - 2017-01-01: - value: 0.12 - threshold: - 2017-01-01: - value: 12400.0 diff --git a/images/rules-as-code/openfisca_rules/reforms/__init__.py b/images/rules-as-code/openfisca_rules/reforms/__init__.py deleted file mode 100644 index bde04d0..0000000 --- a/images/rules-as-code/openfisca_rules/reforms/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -This sub-package is used to define reforms. - -A reform is a set of modifications to be applied to a reference tax and benefit system to carry out experiments. - -See https://openfisca.org/doc/key-concepts/reforms.html -""" diff --git a/images/rules-as-code/openfisca_rules/reforms/add_dynamic_variable.py b/images/rules-as-code/openfisca_rules/reforms/add_dynamic_variable.py deleted file mode 100644 index 8471866..0000000 --- a/images/rules-as-code/openfisca_rules/reforms/add_dynamic_variable.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -This file defines a reform to add a dynamic variable, based on input data. - -A reform is a set of modifications to be applied to a reference tax and benefit system to carry out experiments. - -See https://openfisca.org/doc/key-concepts/reforms.html -""" - -# Import from openfisca-core the Python objects used to code the legislation in OpenFisca -from openfisca_core.periods import MONTH -from openfisca_core.reforms import Reform -from openfisca_core.variables import Variable - -# Import the Entities specifically defined for this tax and benefit system -from openfisca_country_template.entities import Person - - -def create_dynamic_variable(name, **variable): - """Create new variable dynamically.""" - NewVariable = type(name, (Variable,), { - "value_type": variable["value_type"], - "entity": variable["entity"], - "default_value": variable["default_value"], - "definition_period": variable["definition_period"], - "label": variable["label"], - "reference": variable["reference"], - }) - - return NewVariable - - -class add_dynamic_variable(Reform): - def apply(self): - """ - Apply reform. - - A reform always defines an `apply` method that builds the reformed tax - and benefit system from the reference one. - - See https://openfisca.org/doc/coding-the-legislation/reforms.html#writing-a-reform - """ - NewVariable = create_dynamic_variable( - name = "goes_to_school", - value_type = bool, - entity = Person, - default_value = True, - definition_period = MONTH, - label = "The person goes to school (only relevant for children)", - reference = "https://law.gov.example/goes_to_school", - ) - - self.add_variable(NewVariable) diff --git a/images/rules-as-code/openfisca_rules/reforms/add_new_tax.py b/images/rules-as-code/openfisca_rules/reforms/add_new_tax.py deleted file mode 100644 index 710698c..0000000 --- a/images/rules-as-code/openfisca_rules/reforms/add_new_tax.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -This file defines a reform. - -A reform is a set of modifications to be applied to a reference tax and benefit system to carry out experiments. - -See https://openfisca.org/doc/key-concepts/reforms.html -""" - -# Import from openfisca-core the Python objects used to code the legislation in OpenFisca -from openfisca_core.periods import MONTH -from openfisca_core.reforms import Reform -from openfisca_core.variables import Variable - -# Import the Entities specifically defined for this tax and benefit system -from openfisca_country_template.entities import Person - - -class has_car(Variable): - value_type = bool - entity = Person - default_value = True - definition_period = MONTH - label = "The person has a car" - reference = "https://law.gov.example/new_tax" # Always use the most official source - - -class new_tax(Variable): - value_type = float - entity = Person - definition_period = MONTH - label = "New tax" - reference = "https://law.gov.example/new_tax" # Always use the most official source - - def formula(person, period, _parameters): - """ - New tax reform. - - Our reform adds a new variable `new_tax` that is calculated based on - the current `income_tax`, if the person has a car. - """ - income_tax = person("income_tax", period) - has_car = person("has_car", period) - - return (income_tax + 100.0) * has_car - - -class add_new_tax(Reform): - def apply(self): - """ - Apply reform. - - A reform always defines an `apply` method that builds the reformed tax - and benefit system from the reference one. - - See https://openfisca.org/doc/coding-the-legislation/reforms.html#writing-a-reform - """ - self.add_variable(has_car) - self.add_variable(new_tax) diff --git a/images/rules-as-code/openfisca_rules/reforms/flat_social_security_contribution.py b/images/rules-as-code/openfisca_rules/reforms/flat_social_security_contribution.py deleted file mode 100644 index c224fc1..0000000 --- a/images/rules-as-code/openfisca_rules/reforms/flat_social_security_contribution.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -This file defines a reform. - -A reform is a set of modifications to be applied to a reference tax and benefit system to carry out experiments. - -See https://openfisca.org/doc/key-concepts/reforms.html -""" - -# Import from openfisca-core the Python objects used to code the legislation in OpenFisca -from openfisca_core.reforms import Reform -from openfisca_core.variables import Variable - - -class social_security_contribution(Variable): - # Variable metadata don't need to be redefined. By default, the reference variable metadatas will be used. - - def formula(person, period, _parameters): - """ - Social security contribution reform. - - Our reform replaces `social_security_contribution` (the "reference" variable) by the following variable. - """ - return person("salary", period) * 0.03 - - -class flat_social_security_contribution(Reform): - def apply(self): - """ - Apply reform. - - A reform always defines an `apply` method that builds the reformed tax and benefit system from the reference one. - See https://openfisca.org/doc/coding-the-legislation/reforms.html#writing-a-reform - """ - self.update_variable(social_security_contribution) diff --git a/images/rules-as-code/openfisca_rules/reforms/modify_social_security_taxation.py b/images/rules-as-code/openfisca_rules/reforms/modify_social_security_taxation.py deleted file mode 100644 index 7d4099d..0000000 --- a/images/rules-as-code/openfisca_rules/reforms/modify_social_security_taxation.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -This file defines a reform. - -A reform is a set of modifications to be applied to a reference tax and benefit system to carry out experiments. - -See https://openfisca.org/doc/key-concepts/reforms.html -""" - -# Import from openfisca-core the Python objects used to code the legislation in OpenFisca -from openfisca_core.parameters import ParameterScaleBracket -from openfisca_core.reforms import Reform - - -class modify_social_security_taxation(Reform): - def apply(self): - """ - Apply reform. - - A reform always defines an `apply` method that builds the reformed tax and benefit system from the reference one. - See https://openfisca.org/doc/coding-the-legislation/reforms.html#writing-a-reform - - Our reform modifies the `social_security_contribution` parameter, which is a scale. - This parameter is declared in `parameters/taxes/social_security_contribution.yaml`. - - See https://openfisca.org/doc/coding-the-legislation/legislation_parameters.html - """ - self.modify_parameters(modifier_function = self.modify_brackets) - - @staticmethod - def modify_brackets(parameters): - """ - Social security taxation reform. - - This function takes an argument `parameters` which is a in-memory representation - of the YAML parameters. It can be modified and must be returned. - """ - # Access the right parameter node: - brackets = parameters.taxes.social_security_contribution.brackets - - # Add 0.1 to the rates of the second bracket, keeping the same thresholds: - for rate in brackets[1].rate.values_list: - rate.value += 0.1 - - # Remove the first bracket: - del brackets[0] - - # Add a new bracket with a higher tax rate for rich people: - new_bracket = ParameterScaleBracket( - "new_bracket", - data = { - "rate": {"2017-01-01": {"value": 0.4}}, - "threshold": {"2017-01-01": {"value": 40000}}, - }, - ) - brackets.append(new_bracket) - - return parameters diff --git a/images/rules-as-code/openfisca_rules/reforms/removal_basic_income.py b/images/rules-as-code/openfisca_rules/reforms/removal_basic_income.py deleted file mode 100644 index 58de496..0000000 --- a/images/rules-as-code/openfisca_rules/reforms/removal_basic_income.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -This file defines a reform. - -A reform is a set of modifications to be applied to a reference tax and benefit system to carry out experiments. - -See https://openfisca.org/doc/key-concepts/reforms.html -""" - -# Import from openfisca-core the Python objects used to code the legislation in OpenFisca -from openfisca_core.reforms import Reform - - -class removal_basic_income(Reform): - def apply(self): - """ - Apply reform. - - A reform always defines an `apply` method that builds the reformed tax and benefit system from the reference one. - See https://openfisca.org/doc/coding-the-legislation/reforms.html#writing-a-reform - - Our reform neutralizes the `basic_income` variable. When this reform is applied, calculating `basic_income` will always return its default value, 0. - """ - self.neutralize_variable("basic_income") diff --git a/images/rules-as-code/openfisca_rules/situation_examples/__init__.py b/images/rules-as-code/openfisca_rules/situation_examples/__init__.py deleted file mode 100644 index b1b7cfb..0000000 --- a/images/rules-as-code/openfisca_rules/situation_examples/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -"""This file provides a function to load json example situations.""" - -import json -import os - - -DIR_PATH = os.path.dirname(os.path.abspath(__file__)) - - -def parse(file_name): - """Load json example situations.""" - file_path = os.path.join(DIR_PATH, file_name) - with open(file_path, "r", encoding="utf8") as file: - return json.loads(file.read()) - - -single = parse("single.json") -couple = parse("couple.json") diff --git a/images/rules-as-code/openfisca_rules/situation_examples/couple.json b/images/rules-as-code/openfisca_rules/situation_examples/couple.json deleted file mode 100644 index e04c75b..0000000 --- a/images/rules-as-code/openfisca_rules/situation_examples/couple.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "persons": { - "Alicia": { - "birth": { - "ETERNITY": "1980-01-01" - }, - "salary": { - "2017-01": 4000 - }, - "disposable_income": { - "2017-01": null - } - }, - "Javier": { - "birth": { - "ETERNITY": "1984-01-01" - }, - "salary": { - "2017-01": 2500 - }, - "disposable_income": { - "2017-01": null - } - } - }, - "households": { - "_": { - "parents": ["Alicia", "Javier"], - "total_benefits": { - "2017-01": null - }, - "total_taxes": { - "2017-01": null - } - } - } -} diff --git a/images/rules-as-code/openfisca_rules/situation_examples/housing.json b/images/rules-as-code/openfisca_rules/situation_examples/housing.json deleted file mode 100644 index de039a4..0000000 --- a/images/rules-as-code/openfisca_rules/situation_examples/housing.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "persons": { - "Alicia": { - "birth": { - "2017-01": null - }, - "disposable_income": { - "2017-01": null - } - } - }, - "households": { - "_": { - "parents": ["Alicia"], - "housing_tax": { - "2017": null - }, - "housing_occupancy_status": { - "2017-01": null - } - } - } -} \ No newline at end of file diff --git a/images/rules-as-code/openfisca_rules/situation_examples/single.json b/images/rules-as-code/openfisca_rules/situation_examples/single.json deleted file mode 100644 index c1ca2bc..0000000 --- a/images/rules-as-code/openfisca_rules/situation_examples/single.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "persons": { - "Alicia": { - "birth": { - "2017-01": null - }, - "disposable_income": { - "2017-01": null - } - } - }, - "households": { - "_": { - "parents": ["Alicia"] - } - } -} diff --git a/images/rules-as-code/openfisca_rules/tests/age.yaml b/images/rules-as-code/openfisca_rules/tests/age.yaml deleted file mode 100644 index 458ab56..0000000 --- a/images/rules-as-code/openfisca_rules/tests/age.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# Test files describe situations and their expected outcomes -# We can run this test on our command line using `openfisca-run-test age.yaml` - -- name: Birthday month is taken into consideration - period: 2016-01 - input: - birth: 1980-02-15 - output: - age: - 2015-02: 34 - 2015-03: 35 - -- name: Years are taken into consideration - period: 2016-01 - input: - birth: 1980-12-31 - output: - age: - 2015-12: 34 - 2016-01: 35 - -- name: The first year is considered of age 0 - period: 2016-01 - input: - birth: 1980-02-01 - output: - age: - 1980-02: 0 - 1980-03: 0 - 1981-03: 1 - -- name: Leap years are supported - period: 2016-01 - input: - birth: 1980-02-29 - output: - age: - 2015-02: 34 - 2015-03: 35 diff --git a/images/rules-as-code/openfisca_rules/tests/basic_income.yaml b/images/rules-as-code/openfisca_rules/tests/basic_income.yaml deleted file mode 100644 index 8d09eb3..0000000 --- a/images/rules-as-code/openfisca_rules/tests/basic_income.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# Test files describe situations and their expected outcomes -# We can run this test on our command line using `openfisca-run-test basic_income.yaml` - -- name: The basic income should be 0 before it was introduced - period: 2015-11 - input: - age: 18 - salary: 0 - output: - basic_income: 0 - -- name: In Dec 2015, an adult with no salary should get a basic income of 600 - period: 2015-12 - input: - salary: 0 - age: 18 - output: - basic_income: 600 - -- name: In Dec 2015, a child with no salary should get no basic income - period: 2015-12 - input: - salary: 0 - age: 17 - output: - basic_income: 0 - -- name: In Dec 2015, an adult with a salary should get no basic income - period: 2015-12 - input: - salary: 1200 - age: 18 - output: - basic_income: 0 - -- name: In Dec 2016, a child with no salary should get no basic income - period: 2016-12 - input: - salary: 0 - age: 17 - output: - basic_income: 0 - -- name: In Dec 2016, an adult with a salary should get a basic income of 600 - period: 2016-12 - input: - salary: 1200 - age: 18 - output: - basic_income: 600 diff --git a/images/rules-as-code/openfisca_rules/tests/disposable_income.yaml b/images/rules-as-code/openfisca_rules/tests/disposable_income.yaml deleted file mode 100644 index 71cbbb2..0000000 --- a/images/rules-as-code/openfisca_rules/tests/disposable_income.yaml +++ /dev/null @@ -1,65 +0,0 @@ -# Test files describe situations and their expected outcomes -# We can run this test on our command line using `openfisca-run-test disposable_income.yaml` - -- name: Person earning no salary in Jan 2015 - period: 2015-01 - input: - salary: 0 - output: - disposable_income: 0 - -- name: Person earning 2500 in Jan 2015 - period: 2015-01 - input: - salary: 2500 - output: - disposable_income: 2025 - -- name: Person earning 10000 in Jan 2015 - period: 2015-01 - input: - salary: 10000 - output: - disposable_income: 8100 - -- name: Person earning no salary in Jan 2016 - period: 2016-01 - input: - salary: 0 - output: - disposable_income: 600 - -- name: Person earning 2500 in Jan 2016 - period: 2016-01 - input: - salary: 2500 - output: - disposable_income: 2025 - -- name: Person earning 10000 in Jan 2016 - period: 2016-01 - input: - salary: 10000 - output: - disposable_income: 8100 - -- name: Person earning no salary in Jan 2017 - period: 2017-01 - input: - salary: 0 - output: - disposable_income: 600 - -- name: Person earning 2500 in Jan 2017 - period: 2017-01 - input: - salary: 2500 - output: - disposable_income: 2675 - -- name: Person earning 10000 in Jan 2017 - period: 2017-01 - input: - salary: 10000 - output: - disposable_income: 8740 diff --git a/images/rules-as-code/openfisca_rules/tests/housing_allowance.yaml b/images/rules-as-code/openfisca_rules/tests/housing_allowance.yaml deleted file mode 100644 index 7ed043e..0000000 --- a/images/rules-as-code/openfisca_rules/tests/housing_allowance.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# Test files describe situations and their expected outcomes -# We can run this test on our command line using `openfisca-run-test housing_allowance.yaml` - -- name: In january 2016, a household paying 400 of rent gets an allowance of 100 - period: 2016-01 - input: - rent: 400 - output: - housing_allowance: 100 - -- name: The housing_allowance disappeared in Dec 2016 - period: 2016-12 - input: - rent: 400 - output: - housing_allowance: 0 diff --git a/images/rules-as-code/openfisca_rules/tests/housing_tax.yaml b/images/rules-as-code/openfisca_rules/tests/housing_tax.yaml deleted file mode 100644 index c3bde40..0000000 --- a/images/rules-as-code/openfisca_rules/tests/housing_tax.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# Test files describe situations and their expected outcomes -# We can run this test on our command line using `openfisca-run-test housing_tax.yaml` - -- name: Tenant living in a 40 sq. metres accommodation - period: 2017 - input: - accommodation_size: - 2017-01: 40 - housing_occupancy_status: - 2017-01: tenant - output: - housing_tax: 400 - -- name: Free lodgers living in a 40 sq. metres accommodation - period: 2017 - input: - accommodation_size: - 2017-01: 40 - housing_occupancy_status: - 2017-01: free_lodger - output: - housing_tax: 0 - -- name: Household living in a 100 sq. metres accommodation - period: 2017 - input: - accommodation_size: - 2017-01: 100 - output: - housing_tax: 1000 - housing_occupancy_status: - 2017-01: tenant diff --git a/images/rules-as-code/openfisca_rules/tests/income_tax.yaml b/images/rules-as-code/openfisca_rules/tests/income_tax.yaml deleted file mode 100644 index d38f626..0000000 --- a/images/rules-as-code/openfisca_rules/tests/income_tax.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Test files describe situations and their expected outcomes -# We can run this test on our command line using `openfisca-run-test income_tax.yaml` - -- name: Someone making 10000 should pay 1500 of taxes - period: 2017-01 - input: - salary: 10000 - output: - income_tax: 1500 diff --git a/images/rules-as-code/openfisca_rules/tests/reforms/add_dynamic_variable.yaml b/images/rules-as-code/openfisca_rules/tests/reforms/add_dynamic_variable.yaml deleted file mode 100644 index dc27d1c..0000000 --- a/images/rules-as-code/openfisca_rules/tests/reforms/add_dynamic_variable.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# Test files describe situations and their expected outcomes -# -# We can run this test on our command line using -# `openfisca-run-test modify_social_security_taxation.yaml` -# -# Note the `reforms: ` key in the below YAML blocks. - -- name: We will dinamically add new variable "goes_to_school" thanks to a reform - reforms: openfisca_country_template.reforms.add_dynamic_variable.add_dynamic_variable - period: 2017-01 - output: - goes_to_school: true diff --git a/images/rules-as-code/openfisca_rules/tests/reforms/add_new_tax.yaml b/images/rules-as-code/openfisca_rules/tests/reforms/add_new_tax.yaml deleted file mode 100644 index 18ae17e..0000000 --- a/images/rules-as-code/openfisca_rules/tests/reforms/add_new_tax.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# Test files describe situations and their expected outcomes -# -# We can run this test on our command line using -# `openfisca-run-test modify_social_security_taxation.yaml` -# -# Note the `reforms: ` key in the below YAML blocks. - -- name: The new tax applies to car-holding people - reforms: openfisca_country_template.reforms.add_new_tax.add_new_tax - period: 2017-01 - input: - salary: 2000 - has_car: true - output: - income_tax: 300 - new_tax: 400 - -- name: The new tax does not apply otherwise - reforms: openfisca_country_template.reforms.add_new_tax.add_new_tax - period: 2017-01 - input: - salary: 2000 - has_car: false - output: - income_tax: 300 - new_tax: 0 diff --git a/images/rules-as-code/openfisca_rules/tests/reforms/modify_social_security_taxation.yaml b/images/rules-as-code/openfisca_rules/tests/reforms/modify_social_security_taxation.yaml deleted file mode 100644 index ff7f2fd..0000000 --- a/images/rules-as-code/openfisca_rules/tests/reforms/modify_social_security_taxation.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# Test files describe situations and their expected outcomes -# We can run this test on our command line using `openfisca-run-test modify_social_security_taxation.yaml` - -# This test is a partial adaptation of `social_security_contribution.yaml` to match the modifications introduced by the reform of the same name. - -# Note the `reforms: ` key in the below YAML blocks. - -- name: No social security contribution on small salaries - reforms: openfisca_country_template.reforms.modify_social_security_taxation.modify_social_security_taxation - period: 2017-01 - input: - salary: 2000 - output: - social_security_contribution: 0 - -- name: Increased social security contribution on medium salaries - reforms: openfisca_country_template.reforms.modify_social_security_taxation.modify_social_security_taxation - period: 2017-01 - input: - salary: 15000 - output: - social_security_contribution: 1336 - -- name: High social security contribution on high salaries - reforms: openfisca_country_template.reforms.modify_social_security_taxation.modify_social_security_taxation - period: 2017-01 - input: - salary: 50000 - output: - social_security_contribution: 8336 diff --git a/images/rules-as-code/openfisca_rules/tests/situations/income_tax.yaml b/images/rules-as-code/openfisca_rules/tests/situations/income_tax.yaml deleted file mode 100644 index e2d863a..0000000 --- a/images/rules-as-code/openfisca_rules/tests/situations/income_tax.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# You can also use test files to describe complex situations with different entities -# We can run this test on our command line using `openfisca-run-test tests/situations/income_tax.yaml` - -- name: Income tax for a single parent and a child - description: Income tax should get properly computed across all members of a household - period: 2017-01 - absolute_error_margin: 0 - input: - household: - parents: [ Alicia ] - children: [ Michael ] - accommodation_size: 100 - housing_occupancy_status: tenant - persons: - Alicia: - birth: 1961-01-15 - salary: - 2017-01: 2400 - Michael: - birth: 2002-01-15 - salary: - 2016: 0 - output: - persons: - Alicia: - income_tax: 360 - Michael: - income_tax: 0 - household: - housing_tax: - 2017: 1000 diff --git a/images/rules-as-code/openfisca_rules/tests/situations/parenting_allowance.yaml b/images/rules-as-code/openfisca_rules/tests/situations/parenting_allowance.yaml deleted file mode 100644 index bce6d59..0000000 --- a/images/rules-as-code/openfisca_rules/tests/situations/parenting_allowance.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# You can also use test files to describe complex situations with different entities -# We can run this test on our command line using `openfisca-run-test tests/situations/income_tax.yaml` - -- name: Parenting allowance for a two parent household with little income - description: Parenting allowance relies on the incomes on the parents and ages of the children - period: 2020-01 - absolute_error_margin: 0 - input: - household: - parents: [Phil, Saz] - children: [Caz, Eille, Nimasay] - persons: - Phil: - birth: 1981-01-15 - salary: - 2017-01: 250 - 2018-01: 250 - Saz: - birth: 1982-01-15 - salary: - 2017-01: 250 - 2018-01: 251 - Caz: - birth: 2010-01-15 - Eille: - birth: 2012-01-15 - Nimasay: - birth: 2018-01-15 - output: - household: - parenting_allowance: - 2017-01: 600 - 2018-01: 0 diff --git a/images/rules-as-code/openfisca_rules/tests/social_security_contribution.yaml b/images/rules-as-code/openfisca_rules/tests/social_security_contribution.yaml deleted file mode 100644 index 29500ac..0000000 --- a/images/rules-as-code/openfisca_rules/tests/social_security_contribution.yaml +++ /dev/null @@ -1,45 +0,0 @@ - -# Test files describe situations and their expected outcomes -# We can run this test on our command line using `openfisca-run-test social_security_contribution.yaml` - -- name: Person earning 2000 in 2013-01 - period: 2013-01 - input: - salary: 2000 - output: - social_security_contribution: 60 - -- name: Person earning 15000 in 2013-01 - period: 2013-01 - input: - salary: 15000 - output: - social_security_contribution: 660 - -- name: Person earning 2000 in 2015-01 - period: 2015-01 - input: - salary: 2000 - output: - social_security_contribution: 80 - -- name: Person earning 15000 in 2015-01 - period: 2015-01 - input: - salary: 15000 - output: - social_security_contribution: 824 - -- name: Person earning 2000 in 2017-01 - period: 2017-01 - input: - salary: 2000 - output: - social_security_contribution: 40 - -- name: Person earning 15000 in 2017-01 - period: 2017-01 - input: - salary: 15000 - output: - social_security_contribution: 816 diff --git a/images/rules-as-code/openfisca_rules/variables/__init__.py b/images/rules-as-code/openfisca_rules/variables/__init__.py deleted file mode 100644 index 718ad20..0000000 --- a/images/rules-as-code/openfisca_rules/variables/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -This sub-package is used to define variables. - -A variable is a property of an Entity such as a Person, a Household… - -See https://openfisca.org/doc/key-concepts/variables.html -""" diff --git a/images/rules-as-code/openfisca_rules/variables/benefits.py b/images/rules-as-code/openfisca_rules/variables/benefits.py deleted file mode 100644 index 3703113..0000000 --- a/images/rules-as-code/openfisca_rules/variables/benefits.py +++ /dev/null @@ -1,134 +0,0 @@ -""" -This file defines variables for the modelled legislation. - -A variable is a property of an Entity such as a Person, a Household… - -See https://openfisca.org/doc/key-concepts/variables.html -""" - -# Import from openfisca-core the Python objects used to code the legislation in OpenFisca -from openfisca_core.periods import MONTH -from openfisca_core.variables import Variable - -# Import the Entities specifically defined for this tax and benefit system -from openfisca_country_template.entities import Household, Person - - -class basic_income(Variable): - value_type = float - entity = Person - definition_period = MONTH - label = "Basic income provided to adults" - reference = "https://law.gov.example/basic_income" # Always use the most official source - - def formula_2016_12(person, period, parameters): - """ - Basic income provided to adults. - - Since Dec 1st 2016, the basic income is provided to any adult, without considering their income. - """ - age_condition = person("age", period) >= parameters(period).general.age_of_majority - return age_condition * parameters(period).benefits.basic_income # This '*' is a vectorial 'if'. See https://openfisca.org/doc/coding-the-legislation/25_vectorial_computing.html#control-structures - - def formula_2015_12(person, period, parameters): - """ - Basic income provided to adults. - - From Dec 1st 2015 to Nov 30 2016, the basic income is provided to adults who have no income. - Before Dec 1st 2015, the basic income does not exist in the law, and calculating it returns its default value, which is 0. - """ - age_condition = person("age", period) >= parameters(period).general.age_of_majority - salary_condition = person("salary", period) == 0 - return age_condition * salary_condition * parameters(period).benefits.basic_income # The '*' is also used as a vectorial 'and'. See https://openfisca.org/doc/coding-the-legislation/25_vectorial_computing.html#boolean-operations - - -class housing_allowance(Variable): - value_type = float - entity = Household - definition_period = MONTH - label = "Housing allowance" - reference = "https://law.gov.example/housing_allowance" # Always use the most official source - end = "2016-11-30" # This allowance was removed on the 1st of Dec 2016. Calculating it before this date will always return the variable default value, 0. - unit = "currency-EUR" - documentation = """ - This allowance was introduced on the 1st of Jan 1980. - It disappeared in Dec 2016. - """ - - def formula_1980(household, period, parameters): - """ - Housing allowance. - - This allowance was introduced on the 1st of Jan 1980. - Calculating it before this date will always return the variable default value, 0. - - To compute this allowance, the 'rent' value must be provided for the same month, - but 'housing_occupancy_status' is not necessary. - """ - return household("rent", period) * parameters(period).benefits.housing_allowance - - -# By default, you can use utf-8 characters in a variable. OpenFisca web API manages utf-8 encoding. -class pension(Variable): - value_type = float - entity = Person - definition_period = MONTH - label = "Pension for the elderly. Pension attribuée aux personnes âgées. تقاعد." - reference = ["https://fr.wikipedia.org/wiki/Retraite_(économie)", "https://ar.wikipedia.org/wiki/تقاعد"] - - def formula(person, period, parameters): - """ - Pension for the elderly. - - A person's pension depends on their birth date. - In French: retraite selon l'âge. - In Arabic: تقاعد. - """ - age_condition = person("age", period) >= parameters(period).general.age_of_retirement - return age_condition - - -class parenting_allowance(Variable): - value_type = float - entity = Household - definition_period = MONTH - label = "Allowance for low income people with children to care for." - documentation = "Loosely based on the Australian parenting pension." - reference = "https://www.servicesaustralia.gov.au/individuals/services/centrelink/parenting-payment/who-can-get-it" - - def formula(household, period, parameters): - """ - Parenting allowance for households. - - A person's parenting allowance depends on how many dependents they have, - how much they, and their partner, earn - if they are single with a child under 8 - or if they are partnered with a child under 6. - """ - parenting_allowance = parameters(period).benefits.parenting_allowance - - household_income = household("household_income", period) - income_threshold = parenting_allowance.income_threshold - income_condition = household_income <= income_threshold - - is_single = household.nb_persons(Household.PARENT) == 1 - ages = household.members("age", period) - under_8 = household.any(ages < 8) - under_6 = household.any(ages < 6) - - allowance_condition = income_condition * ((is_single * under_8) + under_6) - allowance_amount = parenting_allowance.amount - - return allowance_condition * allowance_amount - - -class household_income(Variable): - value_type = float - entity = Household - definition_period = MONTH - label = "The sum of the salaries of those living in a household" - - def formula(household, period, _parameters): - """A household's income.""" - salaries = household.members("salary", period) - return household.sum(salaries) diff --git a/images/rules-as-code/openfisca_rules/variables/demographics.py b/images/rules-as-code/openfisca_rules/variables/demographics.py deleted file mode 100644 index 4a73f17..0000000 --- a/images/rules-as-code/openfisca_rules/variables/demographics.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -This file defines variables for the modelled legislation. - -A variable is a property of an Entity such as a Person, a Household… - -See https://openfisca.org/doc/key-concepts/variables.html -""" - -from datetime import date - -# Import from numpy the operations you need to apply on OpenFisca's population vectors -# Import from openfisca-core the Python objects used to code the legislation in OpenFisca -from numpy import where -from openfisca_core.periods import ETERNITY, MONTH -from openfisca_core.variables import Variable - -# Import the Entities specifically defined for this tax and benefit system -from openfisca_country_template.entities import Person - - -# This variable is a pure input: it doesn't have a formula -class birth(Variable): - value_type = date - default_value = date(1970, 1, 1) # By default, if no value is set for a simulation, we consider the people involved in a simulation to be born on the 1st of Jan 1970. - entity = Person - label = "Birth date" - definition_period = ETERNITY # This variable cannot change over time. - reference = "https://en.wiktionary.org/wiki/birthdate" - - -class age(Variable): - value_type = int - entity = Person - definition_period = MONTH - label = "Person's age (in years)" - - def formula(person, period, _parameters): - """ - Person's age (in years). - - A person's age is computed according to its birth date. - """ - birth = person("birth", period) - birth_year = birth.astype("datetime64[Y]").astype(int) + 1970 - birth_month = birth.astype("datetime64[M]").astype(int) % 12 + 1 - birth_day = (birth - birth.astype("datetime64[M]") + 1).astype(int) - - is_birthday_past = (birth_month < period.start.month) + (birth_month == period.start.month) * (birth_day <= period.start.day) - - return (period.start.year - birth_year) - where(is_birthday_past, 0, 1) # If the birthday is not passed this year, subtract one year diff --git a/images/rules-as-code/openfisca_rules/variables/housing.py b/images/rules-as-code/openfisca_rules/variables/housing.py deleted file mode 100644 index 780720e..0000000 --- a/images/rules-as-code/openfisca_rules/variables/housing.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -This file defines variables for the modelled legislation. - -A variable is a property of an Entity such as a Person, a Household… - -See https://openfisca.org/doc/key-concepts/variables.html -""" - -# Import from openfisca-core the Python objects used to code the legislation in OpenFisca -from openfisca_core.indexed_enums import Enum -from openfisca_core.periods import MONTH -from openfisca_core.variables import Variable - -# Import the Entities specifically defined for this tax and benefit system -from openfisca_country_template.entities import Household - - -# This variable is a pure input: it doesn't have a formula -class accommodation_size(Variable): - value_type = float - entity = Household - definition_period = MONTH - label = "Size of the accommodation, in square metres" - - -# This variable is a pure input: it doesn't have a formula -class rent(Variable): - value_type = float - entity = Household - definition_period = MONTH - label = "Rent paid by the household" - - -# Possible values for the housing_occupancy_status variable, defined further down -# See more at -class HousingOccupancyStatus(Enum): - __order__ = "owner tenant free_lodger homeless" - owner = "Owner" - tenant = "Tenant" - free_lodger = "Free lodger" - homeless = "Homeless" - - -class housing_occupancy_status(Variable): - value_type = Enum - possible_values = HousingOccupancyStatus - default_value = HousingOccupancyStatus.tenant - entity = Household - definition_period = MONTH - label = "Legal housing situation of the household concerning their main residence" - - -class postal_code(Variable): - value_type = str - max_length = 5 - entity = Household - definition_period = MONTH - label = "Postal code of the household" diff --git a/images/rules-as-code/openfisca_rules/variables/income.py b/images/rules-as-code/openfisca_rules/variables/income.py deleted file mode 100644 index 1b48144..0000000 --- a/images/rules-as-code/openfisca_rules/variables/income.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -This file defines variables for the modelled legislation. - -A variable is a property of an Entity such as a Person, a Household… - -See https://openfisca.org/doc/key-concepts/variables.html -""" - -# Import from openfisca-core the Python objects used to code the legislation in OpenFisca -from openfisca_core.holders import set_input_divide_by_period -from openfisca_core.periods import MONTH -from openfisca_core.variables import Variable - -# Import the Entities specifically defined for this tax and benefit system -from openfisca_country_template.entities import Person - - -# This variable is a pure input: it doesn't have a formula -class salary(Variable): - value_type = float - entity = Person - definition_period = MONTH - set_input = set_input_divide_by_period # Optional attribute. Allows user to declare a salary for a year. OpenFisca will spread the yearly amount over the months contained in the year. - label = "Salary" - reference = "https://law.gov.example/salary" # Always use the most official source - - -class disposable_income(Variable): - value_type = float - entity = Person - definition_period = MONTH - label = "Actual amount available to the person at the end of the month" - reference = "https://stats.gov.example/disposable_income" # Some variables represent quantities used in economic models, and not defined by law. Always give the source of your definitions. - - def formula(person, period, _parameters): - """Disposable income.""" - return ( - + person("salary", period) - + person("basic_income", period) - - person("income_tax", period) - - person("social_security_contribution", period) - ) diff --git a/images/rules-as-code/openfisca_rules/variables/stats.py b/images/rules-as-code/openfisca_rules/variables/stats.py deleted file mode 100644 index d2fa6f4..0000000 --- a/images/rules-as-code/openfisca_rules/variables/stats.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -This file defines variables for the modelled legislation. - -A variable is a property of an Entity such as a Person, a Household… - -See https://openfisca.org/doc/key-concepts/variables.html -""" - -# Import from openfisca-core the Python objects used to code the legislation in OpenFisca -from openfisca_core.periods import MONTH -from openfisca_core.variables import Variable - -# Import the Entities specifically defined for this tax and benefit system -from openfisca_country_template.entities import Household - - -class total_benefits(Variable): - value_type = float - entity = Household - definition_period = MONTH - label = "Sum of the benefits perceived by a household" - reference = "https://stats.gov.example/benefits" - - def formula(household, period, _parameters): - """Total benefits.""" - basic_income_i = household.members("basic_income", period) # Calculates the value of basic_income for each member of the household - - return ( - + household.sum(basic_income_i) # Sum the household members basic incomes - + household("housing_allowance", period) - ) - - -class total_taxes(Variable): - value_type = float - entity = Household - definition_period = MONTH - label = "Sum of the taxes paid by a household" - reference = "https://stats.gov.example/taxes" - - def formula(household, period, _parameters): - """Total taxes.""" - income_tax_i = household.members("income_tax", period) - social_security_contribution_i = household.members("social_security_contribution", period) - - return ( - + household.sum(income_tax_i) - + household.sum(social_security_contribution_i) - + household("housing_tax", period.this_year) / 12 - ) diff --git a/images/rules-as-code/openfisca_rules/variables/taxes.py b/images/rules-as-code/openfisca_rules/variables/taxes.py deleted file mode 100644 index 3d78ccb..0000000 --- a/images/rules-as-code/openfisca_rules/variables/taxes.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -This file defines variables for the modelled legislation. - -A variable is a property of an Entity such as a Person, a Household… - -See https://openfisca.org/doc/key-concepts/variables.html -""" - -# Import from numpy the operations you need to apply on OpenFisca's population vectors -# Import from openfisca-core the Python objects used to code the legislation in OpenFisca -from numpy import maximum as max_ -from openfisca_core.periods import MONTH, YEAR -from openfisca_core.variables import Variable - -# Import the Entities specifically defined for this tax and benefit system -from openfisca_country_template.entities import Household, Person - - -class income_tax(Variable): - value_type = float - entity = Person - definition_period = MONTH - label = "Income tax" - reference = "https://law.gov.example/income_tax" # Always use the most official source - - def formula(person, period, parameters): - """ - Income tax. - - The formula to compute the income tax for a given person at a given period - """ - return person("salary", period) * parameters(period).taxes.income_tax_rate - - -class social_security_contribution(Variable): - value_type = float - entity = Person - definition_period = MONTH - label = "Progressive contribution paid on salaries to finance social security" - reference = "https://law.gov.example/social_security_contribution" # Always use the most official source - - def formula(person, period, parameters): - """ - Social security contribution. - - The social_security_contribution is computed according to a marginal scale. - """ - salary = person("salary", period) - scale = parameters(period).taxes.social_security_contribution - - return scale.calc(salary) - - -class housing_tax(Variable): - value_type = float - entity = Household - definition_period = YEAR # This housing tax is defined for a year. - label = "Tax paid by each household proportionally to the size of its accommodation" - reference = "https://law.gov.example/housing_tax" # Always use the most official source - - def formula(household, period, parameters): - """ - Housing tax. - - The housing tax is defined for a year, but depends on the `accommodation_size` and `housing_occupancy_status` on the first month of the year. - Here period is a year. We can get the first month of a year with the following shortcut. - To build different periods, see https://openfisca.org/doc/coding-the-legislation/35_periods.html#calculate-dependencies-for-a-specific-period - """ - january = period.first_month - accommodation_size = household("accommodation_size", january) - - tax_params = parameters(period).taxes.housing_tax - tax_amount = max_(accommodation_size * tax_params.rate, tax_params.minimal_amount) - - # `housing_occupancy_status` is an Enum variable - occupancy_status = household("housing_occupancy_status", january) - HousingOccupancyStatus = occupancy_status.possible_values # Get the enum associated with the variable - # To access an enum element, we use the `.` notation. - tenant = occupancy_status == HousingOccupancyStatus.tenant - owner = occupancy_status == HousingOccupancyStatus.owner - - # The tax is applied only if the household owns or rents its main residency - return (owner + tenant) * tax_amount diff --git a/images/rules-as-code/setup.cfg b/images/rules-as-code/setup.cfg deleted file mode 100644 index 3e758f3..0000000 --- a/images/rules-as-code/setup.cfg +++ /dev/null @@ -1,38 +0,0 @@ -; D101: Variables already provide label/description -; D107: We do not document __init__ method -; D401: We do not require the imperative mood -; E128/133: We prefer hang-closing visual indents -; E251: We prefer `function(x = 1)` over `function(x=1)` -; E501: We do not enforce a maximum line length -; W503/4: We break lines before binary operators (Knuth's style) - -[flake8] -hang-closing = true -ignore = D101,D107,D401,E128,E251,E501,W503 -in-place = true -inline-quotes = " -multiline-quotes = """ -import-order-style = appnexus -no-accept-encodings = true -application-import-names = openfisca_country_template -application-package-names = openfisca_country_template,openfisca_extension_template - -; C0103: We (still) snake case variables and reforms -; C0115: Variables already provide label/description -; C0301: We do not enforce a maximum line length -; E0213: This requires changes in OpenFisca-Core -; E0244: This requires changes in OpenFisca-Core -; E1101: False positive, as entities have members -; E1102: False positive, as entities are callable -; W0621: We name variable values the variable name -; W1203: We prefer to log with f-strings - -[pylint.message_control] -disable = C0103,C0115,C0301,E0213,E0244,E1101,E1102,W0621,W1203 -score = no - -[tool:pytest] -addopts = --showlocals --exitfirst --doctest-modules -testpaths = openfisca_country_template/tests -python_files = **/*.py -filterwarnings = ignore::DeprecationWarning diff --git a/images/rules-as-code/setup.py b/images/rules-as-code/setup.py deleted file mode 100644 index c731292..0000000 --- a/images/rules-as-code/setup.py +++ /dev/null @@ -1,45 +0,0 @@ -"""This file contains your openfisca package's metadata and dependencies.""" - -from pathlib import Path - -from setuptools import find_packages, setup - - -this_directory = Path(__file__).parent -long_description = (this_directory / "README.md").read_text() # pylint: disable=W1514 - -setup( - name = "Openfisca-Rules", - version = "0.0.1", - author = "Salsa Digital", - author_email = "info@salsa.digital", - description = "The rules as code entrypoint.", - long_description=long_description, - long_description_content_type="text/markdown", - keywords = "", - url = "", - install_requires = [ - "openfisca-core[web-api] >= 41.0.0, < 42.0.0", - ], - extras_require = { - "dev": [ - "autopep8 >= 2.0.2, < 3.0", - "flake8 >= 6.0.0, < 7.0", - "flake8-bugbear >= 23.3.23, < 24.0", - "flake8-builtins >= 2.1.0, < 3.0", - "flake8-coding >= 1.3.2, < 2.0", - "flake8-commas >= 2.1.0, < 3.0", - "flake8-comprehensions >= 3.11.1, < 4.0", - "flake8-docstrings >= 1.7.0, < 2.0", - "flake8-import-order >= 0.18.2, < 0.19.0", - "flake8-print >= 5.0.0, < 6.0", - "flake8-quotes >= 3.3.2, < 4.0", - "flake8-simplify >= 0.19.3, < 0.20.0", - "flake8-use-fstring >= 1.4, < 2", - "importlib-metadata >= 6.1.0, < 7.0", - "pycodestyle >= 2.10.0, < 3.0", - "pylint >= 2.17.1, < 3.0", - ], - }, - packages = find_packages(), -)