1

We have some async properties (using @property) and some usual ones. We have to use hy to check if one is async or not using asyncio.iscoroutine function. The problem is we have to use getattr and not . operator, since dot will call the property inner function. We want to change our hy code without breaking the DSL used in other projects, that is, we do not want to use string notation (double quotes) for attribute name and therefore we need to write some macro working just like . but internally calls getattr.

=> (defmacro attr [obj attr] `(getattr ~obj '~attr))
=> (attr 5 real)
Traceback (most recent call last):
  File "stdin-5bbedde10a6366314d9be4bd343639582b4d0748", line 1, in <module>
    (attr 5 real)
AttributeError: 'int' object has no attribute 'real'
=> (. 5 real)
5
Kamyar
  • 2,494
  • 2
  • 22
  • 33
  • The equivalent defmacro works fine in Hissp. You might need to convert attr to a string to make this work in Hy, rather than just quoting it. A symbol is not the same thing as a string in Hy. – gilch Jul 27 '21 at 07:00
  • What's your exact version of Hy? It's been changing a lot lately, so we'd want to test on the same version. – gilch Jul 27 '21 at 07:05
  • @gilch We are using hy 1.0.a3, and we can not use string in macro params since we want to keep compatibility with other codes using this macro for non-async code. – Kamyar Jul 27 '21 at 08:57

3 Answers3

3

It sounds like you're confused about the semantics of Python properties, which is understandable, since they're rather hairy. In Python (and thus also in Hy for the equivalent constructions), foo.x and getattr(foo, "x") are always equivalent, even if x is a property. To get a property method as an object instead of calling it, you need to retrieve the attribute for the class (type(x)) instead of an instance, and getattr with a string literal and . remain interchangeable. In this example, getattr(type(foo), 'bar').fset could also be written as type(foo).bar.fset.

Kodiologist
  • 2,984
  • 18
  • 33
1

I tried

(defmacro attr [obj attr]
  `(getattr ~obj ~(str attr)))

(print (attr 5 real))

in the web interpreter and it prints 5.

I was unable to reproduce your issue in the web interpreter though. It must still be running an older version, because I had to install your exact version to do it. I suspect that the following breaking change announced for 1.0a2 accounts for the difference:

Hy model objects are no longer equal to ordinary Python values. For example, (!= 1 '1). You can promote values to models with hy.as-model before making such a check.

My version of attr does work on Hy 1.0a3. I checked. Try it.

Attributes in Python are stored in the object's .__dict__ using string keys. Since Hy's symbols are no longer equal to strings, the lookup of a string key using a symbol will always fail. Converting the symbol to a string first fixes it. My initial comment was correct. (And this step is unnecessary in Hissp because it lacks Hy's separate model types.)

gilch
  • 10,813
  • 1
  • 23
  • 28
  • Oops, I did not mean to leave that quote in there. It was late. @Kamyar Try this version. – gilch Jul 27 '21 at 17:37
1

Although the latter answer works, but I found out that the problem is getting the method behind the property and as @kodiologist wrote, getattr and dot are equivalent. SO I used fget and :

(iscoroutinefunction (.fget (. (type obj) ~attr)))
Kamyar
  • 2,494
  • 2
  • 22
  • 33