Python Recursive Decorators

In Python decorators are a useful tool for changing the behaviour of functions without modifying the original function. For a recent release of openapi-SQLAlchemy, which added support for references among table columns, I used decorators to de-reference columns. I needed a way of supporting cases where a reference to a column was just a reference to another column. The solution was to essentially keep applying the decorator until the column was actually found.

What is a Column Reference?

If you are not familiar with openapi specifications, a simple schema for an object might be the following:

components:
  schemas:
    Employee:
      description: Person that works for a company.
      type: object
      properties:
        id:
          type: integer
          description: Unique identifier for the employee.
          example: 0
        name:
          type: string
          description: The name of the employee.
          example: David Andersson.

To be able to re-use the definition of the id property for another schema, you can do the following:

components:
  schemas:
    Id:
      type: integer
      description: Unique identifier for the employee.
      example: 0
    Employee:
      description: Person that works for a company.
      type: object
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
          description: The name of the employee.
          example: David Andersson.

In this case, the id property just references the Id schema. This could be done for other property definitions where the same schema applies to reduce duplicate schema definitions.

The Simple Case

The openapi-SQLAlchemy package allows you to map openapi schemas to SQLAlchemy models where an object becomes a table and a property becomes a column. The architecture of the package is broken into a factory for tables which then calls a column factory for each property of an object. The problem I had to solve was that ,when a reference is encountered, the column factory gets called with the following dictionary as the schema for the column (for the id column in this case):

{"$ref": "#/components/schemas/Id"}

instead of the schema for the column. Apart from doing some basic checks, what needs to happen is that the schema of Id needs to be found and the column factory be called with that schema instead of the reference. A perfect case for a decorator! The following is the code (minus some input checks):

_REF_PATTER = re.compile(r"^#\/components\/schemas\/(\w+)$")

def resolve_ref(func):
    """Resolve $ref schemas."""

    def inner(schema, schemas, **kwargs):
        """Replace function."""
        # Checking for $ref
        ref = schema.get("$ref")
        if ref is None:
            return func(schema=schema, **kwargs)

        # Retrieving new schema
        match = _REF_PATTER.match(ref)
        schema_name = match.group(1)
        ref_schema = schemas.get(schema_name)

        return func(schema=ref_schema, **kwargs)

    return inner

The first step is to check if the schema is a reference schema and call the column factory if not (lines 3-4). If it is a reference, then the referenced schema needs to be retrieved (lines 14-16) and the factory called with the referenced schema instead (line 18).

The Recursive Case

The problem with the simple decorator is that the following openapi specification is valid:

components:
  schemas:
    Id:
      $ref: "#/components/schemas/RefId"
    RefId:
      type: integer
      description: Unique identifier for the employee.
      example: 0
    Employee:
      description: Person that works for a company.
      type: object
      x-tablename: employee
      properties:
        id:
          $ref: "#/components/schemas/Id"
        name:
          type: string
          description: The name of the employee.
          example: David Andersson.

Noe that the Id schema just references the RefId schema. When this schema is used, the column factory would now be called with:

{"$ref": "#/components/schemas/RefId"}

That looks a lot like the original problem! The solution is that the decorator needs to be applied again. This also looks like a case for recursive programming. In recursive programming, you have the base case and the recursive case. The base case sounds a lot like the code that checks for whether the schema is a reference (lines 3-4 above). The recursive case needs to take a step towards the base case and apply the function again. In this case this is done by resolving one reference and then calling the decorator again. This means that on line 18 above we need to somehow apply the decorator again. The solution is actually quite simple, the code needs to be changed to the following:

_REF_PATTER = re.compile(r"^#\/components\/schemas\/(\w+)$")

def resolve_ref(func):
    """Resolve $ref schemas."""

    def inner(schema, schemas, **kwargs):
        """Replace function."""
        # Checking for $ref
        ref = schema.get("$ref")
        if ref is None:
            return func(schema=schema, **kwargs)

        # Retrieving new schema
        match = _REF_PATTER.match(ref)
        schema_name = match.group(1)
        ref_schema = schemas.get(schema_name)

        return inner(schema=ref_schema, schemas=schemas, **kwargs)

    return inner

The change is that inner is called instead of the original function func. We then also need to pass in all the required arguments for inner, which in this case, means passing through the schemas which func does not need.

Conclusion

Recursive decorators combine the ideas behind decorators and recursive programming. If the problem a decorator solves can be broken into steps where, after each step, the decorator might need to be applied again, you might have a case for a recursive decorator. The decorator must then implement a base case where the decorator is not applied again and a recursive case where one step is taken towards the base case and the decorator is applied again.

Getting Started with Service with a Subject in Angular

A powerful technique in Angular is the built in integration with RxJS. Making use of reactive programming (ie. RxJS) can remove a lot of code from your Angular application. This is an indictor that reactive programming takes care of a lot of the logic you would otherwise have to come up with and test yourself.

There are simple steps you can take to get started with writing reactive Angular applications. You can then use the understanding and confidence you get from the simple steps to start using reactive programming in other, more complicated cases.

Simple Service with a Subject

The following code is a simple Angular service with a subject.
name.service.ts

// name.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class NameService {
  private mName$ = new BehaviorSubject<string>(null);

  name$(): Observable<string> {
    return this.mName$;
  }

  constructor(private httpClient: HttpClient) { }

  loadName() {
    this.httpClient.get<string>('name URL')
      .subscribe(name => this.mName$.next(name));
  }
}

There are 3 pieces to the subject that come together to trigger getting the name from the API and passing on the retrieved name.

API Call

The entry point for a user of the service is the loadName function on line 18. It triggers the HTTP call to the API and passes on the retrieved name to mName$ in the subscribe call on line 20.

Storing the Retrieved Name

The mName$ member variable on line 10 of the service is used as private intermediate storage of the name retrieved from the API in the service. mName$ is tightly linked to the name$ function which is used to control access to the intermediate storage.

Passing on the Retrieved Name

The name$ function of the service is used to pass on the name retrieved from the API on line 12. Hiding the private intermediate storage mName$ behind the name$ function allows control over how the name is distributed throughout the Angular application.

The next step is to show the name in a component.

Reactive Component

Once the name has been retrieved from the API, the next step is to show it in a component.

Component Typescript Code

The following is the typescript code for the component.
name.component.ts

// name.component.ts
import { Component, OnInit } from '@angular/core';

import { NameService } from './name.service';

@Component({
  selector: 'app-name',
  templateUrl: './name.component.html',
  styleUrls: ['./name.component.css']
})
export class NameComponent implements OnInit {
  constructor(public nameService: NameService) { }

  ngOnInit() {
    this.nameService.loadName();
  }

}

There is hardly any code in the component that is not part of the required Angular component code. The only line that has been added is line 15 which instructs the service to load the name along with importing the service on line 4 and injecting it into the component on line 12.

Component Template

The following is the HTML template associated with the component.
name.component.html

<!-- name.component.html -->
<ng-container *ngIf="nameService.name$() | async as name">
  {{ name }}
</ng-container>

In the template the name$ function of the service is passed to the async pipe on line 2. The values emitted by the name$ observable are renamed to the name variable and then displayed on line 3.

That concludes the simple example for making use of a subject with a service. There are some additions to consider depending on the use case. For example, you may want to introduce error handling in the subject. You may also want to write tests for the service and the component.