The Wayback Machine - https://web.archive.org/web/20210414105808/https://github.com/microsoft/TypeScript/issues/8277
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

Always allow code before super call when it does not use "this" #8277

Open
pdfernhout opened this issue Apr 24, 2016 · 26 comments
Open

Always allow code before super call when it does not use "this" #8277

pdfernhout opened this issue Apr 24, 2016 · 26 comments

Comments

@pdfernhout
Copy link

@pdfernhout pdfernhout commented Apr 24, 2016

The TypeScript specification currently reads:

The first statement in the body of a constructor must be a super call if both of the following are true:

  • The containing class is a derived class.
  • The constructor declares parameter properties or the containing class declares instance member variables with initializers.

It is reasonable in TypeScript to not permit this to be referenced in a constructor before calling super when there are initialized properties or constructor parameter properties because this is not fully initialized until after super is called. But broader restrictions on calling other code before super that is not directly using this don't seem that helpful and can be worked around anyway. So why keep them?

A common use case for having code before a call to super is to transform constructor parameters in the subclass constructor before passing them to the superclass constructor. If such transformations are complex, a programmer might want to do the transformation step-by-step on multiple lines for increased readability and easier debugging.

An example of bypassing the compiler's restriction of no code before super is just making function calls wrapping arguments to a super call such as super(logThisName(name)) where the called function refers to this.

As show by an example in the Handbook discussion linked below on improving the explanation for TypeScript constructor restrictions, ES6 permits other code in a constructor before a super call (although accessing this in called code would generate a runtime error before super was called). TypeScript is being more strict than what ES6 permits, and sometimes that is a good thing. But, is there any real value in this case by differing from what ES6 allows overall -- compared to just getting in the way? Why not always always allow code before a super call when it does not use this? Does the benefit of not allowing code before a super sometimes really benefit anyone compared to the confusion caused by requiring programmers to use awkward workarounds and to learn a more complex rule for writing constructors than "Don't use this before calling super"?

This idea was originally brought up in issue #945 (closed in October 2014). I am creating a new issue for that as discussed with @mhegazy here: microsoft/TypeScript-Handbook#214. There is a code example in that Handbook issue which can be used for testing the current behavior for TypeScript, Babel, and ES6.

@electricessence
Copy link

@electricessence electricessence commented Apr 25, 2016

Yeah, this an interesting issue because I personally have had to write special cases where you have to pass closures to the super to ensure they get executed before other blocks of code.
There needs to be a way to allow for this.

On the other side of the coin, this is also an issue in C# as well because calling :base() you need to follow a similar pattern and have an onConstruct override or something like that.

Or... all your properties need to be lazy.. :/

@iby
Copy link

@iby iby commented May 3, 2016

I also have many cases where I check / initialise local variables before calling super. It's great that TypeScript uses the best from other well-typed languages, but the way it is right now is simply out of line with common sense. Like per @jbaron example:

constructor(id:String) {
   var label = I18N.translate(id);
   var icon = IconMap.get(id);
   super(label, icon);
   this.setBackground(this.color);
}

// vs…

constructor(id:String) {
   super(I18N.translate(id), IconMap.get(id));
   this.setBackground(this.color);
}

That limitation doesn't bring in any value. There was an argument on complexity of the checks – doing check for this use before super shouldn't be hard, this is also the same logic used in Swift, which inherits the best from C languages.

@DanielRosenwasser
Copy link
Member

@DanielRosenwasser DanielRosenwasser commented Jul 19, 2016

It pretty much looks like this is fixed for 2.0 beta. Can you give it a try @pdfernhout?

@martinsik
Copy link

@martinsik martinsik commented Oct 26, 2016

@DanielRosenwasser It's probably all right now. The error message explains what went wrong precisely I think.

This is fine:

class MyClass {
  constructor(public str: string) { }
}

class OtherClass extends MyClass {
  constructor(str: string) {
    var that = str;
    super(str);
  }
}

This is not:

class MyClass {
  constructor(public str: string) { }
}

class OtherClass extends MyClass {
  constructor(public str: string) {
    var that = str;
    super(str);
  }
}
@captainjono
Copy link

@captainjono captainjono commented Mar 30, 2017

Could someone tell me why this code is not permitted ?

`export class MatterAccessRevokedForUser extends MatterUserDomainEvent {

constructor();
constructor(tenant: string, fileNumber: string, username: string);
constructor(tenant?: string, fileNumber?: string, username?: string) {
    if (arguments.length === 0) {
        super(null, null, null);
        this.constructor_MatterAccessRevokedForUser_0();
        return;
    }
    super(tenant, fileNumber, username); //ERROR: super must be called before this
    this.constructor_MatterAccessRevokedForUser_1(tenant, fileNumber, username);
}
private constructor_MatterAccessRevokedForUser_0(): void {
}
private constructor_MatterAccessRevokedForUser_1(tenant: string, fileNumber: string, username: string): void {
}

}`

@davidglezz
Copy link

@davidglezz davidglezz commented Sep 30, 2017

This example clearly shows the need to allow code before super call when it does not use "this" to apply transformations to the parameters of super()

Error:

constructor(opts: ReadableOptions) {
        opts.objectMode = true
        super(opts)
}

My solution

constructor(opts: ReadableOptions) {
        super((() => {
            opts.objectMode = true
            return opts
        })())
}
@marlon-tucker
Copy link

@marlon-tucker marlon-tucker commented Dec 14, 2017

Is there any reason why having variable initiators on private variables in the sub class disables the above functionality?

private _something = false;

constructor(args:any) {
    Guard.EnsureNotNull(args);
    super(args.somethingElse);
}

Moving the variable initialisation so it's after the super call fixes it - but I'm curious as to the reasoning as by definition private variables should not have any side effects on the base class?

@electricessence
Copy link

@electricessence electricessence commented Dec 15, 2017

@davidglezz this is exactly what I've had to do.

@mhegazy mhegazy added this to the Community milestone Jan 4, 2018
@pdfernhout
Copy link
Author

@pdfernhout pdfernhout commented Feb 22, 2018

@DanielRosenwasser I confirmed things works better under TypeScript 2.6. I did not test earlier 2.x versions. The Handbook page on Classes also reflects this improvement. Thanks to everyone who worked on those improvements. There are still edge cases that could be improved further like @marlon-tucker and @captainjono raised -- but as far as I am concerned the fix so far is good enough.

=== More details

Below is the test example I used -- where updatedStr can now be calculated before the super() call because of this improvement. Three comments in the example show what is still not permitted.

The third commented code statement contains a direct access to this before super() and is not permitted at any time. I doubt that many people would find that limit problematical -- and it also reflects a specific limit in ES6.

The first two commented code items are for an initialized property and a parameter property. They are both an indirect access to this which is not allowed only because there is code for the calculation before super(). As with @marlon-tucker's question, I feel one could still quibble about those two indirect this constraints since those initializations using this are something that could presumably be done after the super() call in any code generated by TypeScript. However, it is straightforward to work around those two limits by avoiding those indirect this-accessing constructs and doing the initialization yourself manually in the constructor after the super() call.

An edge case involving conditional code with a presumably analyzable bifurcation in the code path to call super() in two different but exclusive ways was pointed out by @captainjono (and is not included in the example). Workarounds include using temporary variables and flags to surround just one super() call or to instead do some application redesign perhaps with a factory class. While the edge case pointed out there seems like it should be supported in theory, in practice I wonder if that edge case is very common -- as it just feels to me like having more than one super() call in a constructor is asking for trouble.

Further improvements in those directions might be nice -- but such work is at risk of producing diminishing returns after the previous improvement. So, it is OK with me to close this issue and suggest people open a new issue if they want to continue discussing relaxing constraints further in such cases.

class MyClass {
    value: string;
    constructor(str: string) {
        this.value = str;
    }
}

class OtherClass extends MyClass {
    // Not permitted indirect this access via initialized property: x: string = "Baz";
    constructor(/* Not permitted indirect this access via parameter property: public y: 10, */ str: string) {
        const updatedStr = str + "FooBar"; // <-- no longer has an error thanks to fix
        // Not permitted direct this access via statement: console.log("test" + this.value);
        super(updatedStr);
    }
}
@Kingwl
Copy link
Member

@Kingwl Kingwl commented May 4, 2018

@mhegazy hi
what kind of pr that this issue accept😅

JoshuaKGoldberg added a commit to JoshuaKGoldberg/TypeScript that referenced this issue Jan 11, 2019
Fixes microsoft#8277.

It feels wrong to put a new `forEachChild` loop in the checker, though in the vast majority of user files this will be a very quick one. Is there a better way to check for a reference to `super` or `this`?
@JoshuaKGoldberg
Copy link
Contributor

@JoshuaKGoldberg JoshuaKGoldberg commented Jan 14, 2019

The implementation details in #29374 are starting to reach into the transformer realm, so a summary of the findings (thanks @ajafff for pointing much of these out!):

  • There are quite a few edge cases where this can be referenced, such as:
    • Class extensions: const x = class extends this.someProp { }
    • Object literals: const x = { [this.someProp]: true };
  • The transformer code assumes the first statement of the constructor is a super(...) call, so its logic makes assumptions based on that. See #29374 (comment).

The second point means this now requires some more changing to the checker and transformer. I think it's still doable if the original "you must call super immediately" requirement becomes "you must call a super before the end of the function or references to this or super" using control flow analysis. In other words, >=1 super(...) call must be reached by the end of the constructor.

class Test extends Base {
    prop = 1;

    // Not acceptable, as the `super(...)` might not be reached
    constructor() {
        if (Math.random() > .5) super(1);
    }
}
class Test extends Base {
    prop = 1;

    // Acceptable, as there's no way for a `super(...)` not to be reached
    constructor() {
        if (Math.random() > .5) { super(1); }
        else { super(0); }
    }
}

On top of that, super and this cannot be referenced until the line where TypeScript would add parameter properties or property initializers. See #29374 (comment)

Related but not the same: #23422 on the subject of multiple super()s.

@trusktr
Copy link

@trusktr trusktr commented Sep 5, 2019

Because of this limitation, we can write

let instance: Foo | null = null

class Foo {
  static singleton() {
    return new Foo()
  }

  private constructor() {
    if (instance) return instance
    instance = this
  }
}

but we can write this:

let instance: Foo | null = null

class Foo extends SomeOtherClass {
  static singleton() {
    return new Foo()
  }

  private constructor() {
    if (instance) return instance
    super()
    instance = this
  }
}

We can change constructor to the following, but it causes performance issues:

  private constructor() {
    super() // unnecessary call.
    if (instance) return instance
    instance = this
  }

Why not at the very least allow expressions-with-no-this before super() if the super() expression is on its own line, to make implementation easier to start with? And throw an error otherwise?

That'd probably allow the vast majority of use cases to work.

@trusktr
Copy link

@trusktr trusktr commented Sep 9, 2019

This just bit me in the foot. I ran into a case where the super() being before if (instance) return instance caused a huge performance bottleneck with regards to how consuming code was using a singleton.

It'd be great to allow at least simple expressions before super() if super() is on a single line. 👍

@lukescott
Copy link

@lukescott lukescott commented Feb 13, 2020

There seems to be inconsistency between how TypeScript handles properties.

Consider this code:

// TypeScript
class Foo {}
class Bar extends Foo {
    prop = 1
    constructor() {
        console.log("foo") // <-- A 'super' call must be the first statement in the constructor when a class contains initialized properties or has parameter properties.(2376)
        super()
    }
}

TypeScript transforms the code to this:

// TypeScript transformed JS
class Foo {}
class Bar extends Foo {
    constructor() {
        this.prop = 1;  // <-- TypeScript puts the initializer before super, hence the error
        console.log("foo");
        super();
    }
}

While Babel does this:

// Babel transformed JS
class Foo {}
class Bar extends Foo {
  constructor() {
    console.log("foo");
    super();
    _defineProperty(this, "prop", []); // <-- Babel puts the initializer after super
  }
}

Oddly enough if you take out the code before super, TypeScript then decides to do the initialization after super:

// TypeScript
class Foo {}
class Bar extends Foo {
    prop = 1
    constructor() {
        super()
    }
}

Gets transformed to:

// TypeScript transformed JS
class Foo {}
class Bar extends Foo {
    constructor() {
        super();
        this.prop = 1;
    }
}

Babel transforms the code the same way no matter if code is put before super or not. It allows code to be placed before super as long as it doesn't access this. Many other languages allow localized code as long as the instance isn't access (since it isn't initialized).

It appears that TypeScript also allows this, as long as you don't initialize the property inline. If you do the initialization manually inside the constructor it works as expected.

IMO, this is a bug. Property initialization should be done the same way regardless if code is placed before super or not. Babel does this correctly while TypeScript currently does not.

@piotrgajow
Copy link

@piotrgajow piotrgajow commented Mar 19, 2020

I agree with this! Recently I have come upon this issue multiple times in my code base:

abstract class A  {
    protected constructor() {
        this.init();
    }
    protected abstract init(): void;
}

class B extends A {
    private readonly methodBound = this.method.bind(this);
    constructor() {
        super();
    }
    protected init(): void {
        console.log(this.methodBound); // undefined
        console.log(this.method); // reference to method
    }
    private method(): void {
        // do something
    }
}

Being able to do this instead would be so nice:

class B extends A {
    private readonly methodBound: () => void;
    constructor() {
        this.methodBound = this.method.bind(this);
        super();
    }
    protected init(): void {
        console.log(this.methodBound); // works!
        console.log(this.method); // reference to method
    }
    private method(): void {
        // do something
    }
}
@lukescott
Copy link

@lukescott lukescott commented Mar 19, 2020

@piotrgajow Your example code uses this before the super call. The property also initializes after super is called. That will never change.

The issue we're discussing is allowing code before super() that does not touch this. Generally it involves code that mutates arguments that get passed into super.

Usually you can put code before super() that does not touch this. But for some reason the TypeScript compiler disallows all code when you have a property w/ a default value declared.

@dcporter
Copy link

@dcporter dcporter commented Mar 19, 2020

I've run into this as well, simply messing with parameters before passing them to super(). I'm using babel to compile it, and babel outputs correct, functional code, so I'm just // @ts-ignoreing the constructor. 😞

@piotrgajow
Copy link

@piotrgajow piotrgajow commented Mar 19, 2020

@lukescott Yeah I know, maybe I did not express myself clearly. What I meant was that such strict TypeScript compiler behaviour does not protect the developers from making mistakes anyway (as in the example I provided) but it limits them in certain ways, resulting in workaround and less readable code. Thus I also think that code before super call should be allowed.

@wgebczyk
Copy link

@wgebczyk wgebczyk commented Apr 2, 2020

Preventing "statements that does not touch this" before "super statement", leads to ugly code at first, but as well prevents construction objects in valid state.

In below example, in line with comment "Complex calculation here", we do calculate valid value for super parameter (this calculation might take a few lines/statements). As of now, we would have to either:

  • use ts-ignore - but that's simply bad, but like it the most now - have to only from time to time remove that and check if new bugs were not spawned in mean time ;)
  • call with dummy value and then re-set that with some helper method from parent class
  • create static private method and use that in place of all those statements - bad that TS/ES do not support private static methods in form of "static #calc() {}"
  • create inside of "super statement" IIFE, which is inviting the past HACK to this bright future.

All cases in this playground

class A {
    #a: number;
    constructor(a: number) { this.#a = a; }
}
class B extends A {
    #c: number;

    constructor(c: number) {
        const x = c + 1; // Complex calculation here
        super(x);
        this.#c = c;
    }
}

In short:
Is this blocker? Nope! Tones of hacks to be used.
Does current limitation help TS maintainers? Probably yes as it simplifies a lot for them.
Is current behavior natural for newcomers to TS? I doubt so, they have to simple learn to avoid this odd thing.

This limitation seems to not bring safety to written code, it just brings limitations.

@chharvey
Copy link

@chharvey chharvey commented May 20, 2020

I think I found a bug, but since it’s directly related to this I’m not sure if it needs a separate issue.

In the comments above (#8277 (comment), #8277 (comment)), people are talking about passing anon functions / immediately-invoked-function-expressions (IIFEs) as arguments to super() to circumvent the “no code before super” rule.

constructor(opts: ReadableOptions) {
	super((() => {
		opts.objectMode = true
		return opts
	})())
}

The bug I’ve found is that this IIFE can reference this, which (since it’s in an arrow function) refers to the current class.

constructor (opts: ReadableOptions) {
	super((() => {
		console.log(this) // oh no!
		opts.objectMode = true
		return opts
	})())
}

TypeScript in its current version (v3.9.2) does not emit an error, but when attempting to run this code, the JavaScript runtime will throw this error:

ReferenceError: must call super constructor before using 'this' in derived class constructor

You can see a full playground here.

Since Design Goal 1 is “Statically identify constructs that are likely to be errors”, I would propose adding to this issue by emitting an error for this use case. An IIFE passed as an argument to super() should not be able to reference this.

@pschiffmann
Copy link

@pschiffmann pschiffmann commented Aug 26, 2020

I just encountered error ts(2376). As far as I could see my use case hasn't been mentioned in this thread, so I'll add it as another motivation why it's desirable to allow other code before super().

In my case, the super constructor has side effects that must only run if the object instantiation is successful; and the derived class must validate its constructor arguments and throw on invalid values. It looks like this:

abstract class Node {
  #parent: Node | null;
  #children = new Set<Node>();
  constructor(parent: Node | null) {
    this.#parent = parent;
    if (parent) parent.#children.add(this);
  }

  destroy() {
    this.#parent?.children.delete(this);
  }
}

class TextNode extends Node {
  #text: string;
  constructor(parent: Node, text: string) {
    if (!text) throw new Error("`text` is required");
    super(parent);
    this.#text = text;
  }
}

Moving the line if (!text) ... after the super call introduces a memory leak because parent.#children will still have a reference to the created object. But the TextNode constructor throws, so the caller can't obtain a reference to the object to call destroy() on it.

@chharvey
Copy link

@chharvey chharvey commented Sep 10, 2020

I think I found another bug: Calling super() within a try {} block but not in the catch {} block does not emit an error.

 class Foo {
	 constructor (n: number) {
		 if (n < 0) throw new RangeError()
	 }
 }
 class Bar extends Foo {
	 constructor (n: number) {
		 try {
			 super(n)
		 } catch {
			// Expected a TS error here:
			// > Constructors for derived classes must contain a 'super' call.
		 }
	 }
 }

 new Bar(-1) // runtime error (not predicted by TS):
 // > must call super constructor before using 'this' in derived class constructor
// > Must call super constructor in derived class before accessing 'this' or returning from derived constructor
@fprott
Copy link

@fprott fprott commented Dec 1, 2020

I would like to add to this an argument why allowing code before the super call might be a good idea. My argument is the following: not allowing to call super after regular code will entice young programmers to call super with dummy values just to get it initialized. This will lead to existing objects that are in an dangerous internal state. Add lazy loading to the mix and you have essentially a race-condition generator.

In other words, if there can be no regular code before calling super, people are enticed to do that after super which will leave the object in a dangerous state for a short time. You don't see that since every member is initialized!

Here is a very long example (please only read that if you have time for an coffee break):

This is loosely based on a bug I just found in our code-base. Please note, we started with pure JavaScript and have converted this code to TypeScript. In JavaScript you can call the super later, therefore this code is written this way (I assume, I didn't write it).

class FancyThing extends Thing{
    constructor(){
        //now we do a lot of config stuff, I wrote so much dummy code to show how big the code is
        let fancyConfigBuilder = new configBuilder(fancy);
        let configA = fancyConfigBuilder.getConfig(also_fancy); //several lines of fancy configuration code as a javascript object
        let configB = fancyConfigBuilder.getConfig2(also_fancy)//some user specific stuff
        let configC = { //several lines of fancy configuration code };
        super(configA, configB, configC);
    }
}

The problem is that you can't write this since you needs to call super first. So what we could have done:

class FancyThing extends Thing{
    constructor(){
        super(new configBuilder(fancy).fancyConfigBuilder.getConfig(also_fancy), new configBuilder(fancy).fancyConfigBuilder.getConfig2(also_fancy), { //several lines of fancy configuration code as a javascript object, writen in human readable form }); //boy this is ugly and there is not a monitor in the world to show the whole code
    }
}

There are two problems her: the code is way too long (this is our fault since we made this mess) and we can not use the same configBuilder object! The problem is, if that object has an internal state you basically have to handle this object via an parameter even if that doesn't make sense.

Alright, someone came up with a easy but pretty stupid solution:

class FancyThing extends Thing{
    constructor(){
        super(dummy, dummy, dummy); //really bad idea
        initFancyThing();
    }
    initFancyThing(){
        let fancyConfigBuilder = new configBuilder(fancy);
        let configA = fancyConfigBuilder.getConfig(also_fancy); //several lines of fancy configuration code as a javascript object
        let configB = fancyConfigBuilder.getConfig2(also_fancy)//some user specific stuff
        let configC = { //several lines of fancy configuration code  };
        this.configA = configA;
        this.configB = configB;
        this.configC = configC;
    }
}

And it worked. Until someone did basically this:

class FancyThing extends Thing{
    constructor(){
        super(dummy, dummy, dummy); //really bad idea
        initFancyThing(); //will now load lazily, but we don't use a better dummy
    }

    async initFancyThing(){ //now with lazy loading
          //can take 1 ms to 9 hours depending on the weather
    }
}

And this was the point where all objects figuratively exploded if the internet connection was too fast or your device was too fast or the sun was felling that way. And since you work in a nice office with good internet connection this bug isn't too obvious.

TLDR; If we can't run regular code before super it will entice the usage of dummy values for the super call. This can lead to really ugly bugs.

@CrimsonCodes0
Copy link

@CrimsonCodes0 CrimsonCodes0 commented Jan 19, 2021

Here's a toy example:

declare class T {
    constructor(x: number, y: number);
}

class H extends T {
    x = 0;
    constructor() {
        const rand = Math.random();
        super(rand, rand);
    }
}

this cannot be represented in TS.

Actually, it can, like this:

declare class T {
    constructor(x: number, y: number);
}

class H extends T {
    x = 0;
    static rand = NaN;
    constructor() {
        super(H.rand = Math.random(), H.rand);
    }
}

that is ugly, but TS allows it. ¯\_(ツ)_/¯

Otherwise, I strongly believe that TS2376 is obsolete with the introduction of TS17009.

@Jamesernator
Copy link

@Jamesernator Jamesernator commented Feb 27, 2021

Since Design Goal 1 is “Statically identify constructs that are likely to be errors”, I would propose adding to this issue by emitting an error for this use case. An IIFE passed as an argument to super() should not be able to reference this.

TypeScript should not do this, an arrow function can be passed to super(() => ...) and stored on the instance for use after the constructor has finished.

As an example, this is a simplified version of something I'm already doing today (and works):

class MathView {
  readonly #render: () => Element;
  
  constructor(render: () => Element | Promise<Element>) {
    this.#render = render;
  }
  
  async render(): Promise<Element> {
    const element = await this.#render();
    return wrapAndSetMetadata(element, this);
  }
}

class MathPlusView extends MathView {
  readonly addend: View;
  readonly summand: View;
  constructor(addend: View, summand: View) {
    super(() => this.#render()); // This works fine, when the public
                                 // .render() is called, "this" will be available
    this.addend = addend;
    this.summand = summand;
  }

  #render = async () => {
    const [addendElement, summandElement] = await Promise.all([
      this.addend.render(),
      this.summand.render(),
    ]);
    return fromTemplate`
      <mrow>${ base }<mo>+</mo>${ superScript }</mrow>
    `;
  }
}

Now TypeScript could detect "this" within IIFEs within super(), but once we can include code before super() there wouldn't be any real reason to use such a hack.

@chharvey
Copy link

@chharvey chharvey commented Feb 27, 2021

@Jamesernator An IIFE (immediately-invoked function expression) is a function that is called immediately after it is defined. In your example, you have a regular arrow function, but it’s not called right away — as you correctly state, it doesn’t get called until the public .render() is called, and by that time the this (from inside the arrow function) has already been constructed. That’s why your code works.

In my example, an IIFE is sent as an argument to super, and this fails at runtime because this is referenced before it is constructed.

	super((() => {
		console.log(this) // ReferenceError!
	})())
//	  ^ notice the call here — the function expression is invoked immediately

Your code poses no danger, as the argument sent to super is in fact a function that doesn’t get called until later. My code sends a value (which just so happens to be a function call) that involves the use of this before it gets constructed, and that’s what makes it dangerous. So TypeScript should do something to differentiate between the two scenarios. A naïve “Hey, there’s a this in this here function!” is not sufficient.

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

Successfully merging a pull request may close this issue.

None yet