diff --git a/fastcore/docments.py b/fastcore/docments.py index 8d57a898..e50ccc75 100644 --- a/fastcore/docments.py +++ b/fastcore/docments.py @@ -155,8 +155,8 @@ def _get_comment(line, arg, comments, parms): def _get_full(p, docs, eval_str=False): anno = p.annotation - if anno==empty: - if p.default!=empty: anno = type(p.default) + if anno is empty: + if p.default is not empty: anno = type(p.default) elif eval_str: anno = None return AttrDict(docment=docs.get(p.name), anno=anno, default=p.default, kind=p.kind) @@ -255,7 +255,7 @@ def extract_docstrings(code): def _bold(s): return f'**{s}**' if s.strip() else s def _maybe_nm(o): - if (o == inspect._empty): return '' + if (o is inspect._empty): return '' else: return o.__name__ if hasattr(o, '__name__') else str(o) # %% ../nbs/04_docments.ipynb #ac070254 @@ -291,13 +291,13 @@ def __init__(self, obj, verbose=True, returns=True): def _columns(self): "Fields with at least one non-empty value" candidates = self._map if self.verbose else {'docment': 'Details'} - return {k:v for k,v in candidates.items() if any(d[k] != empty for d in self.dm.values())} + return {k:v for k,v in candidates.items() if any(d[k] is not empty for d in self.dm.values())} @property def has_docment(self): return 'docment' in self._columns and bool(self.params) @property - def has_return(self): return self.returns and any(v != empty for v in self.dm.get('return', {}).values()) + def has_return(self): return self.returns and any(v is not empty for v in self.dm.get('return', {}).values()) @property def hdr_str(self): @@ -330,7 +330,7 @@ def __eq__(self,other): return self.__str__() == str(other).strip() class DocmentList(_DocmentBase): def _fmt(self, nm, p): anno,default,doc = _maybe_nm(p.get('anno','')), p.get('default',empty), p.get('docment','') - s = f'`{nm}{":" + anno if anno else ""}{"=" + _maybe_nm(default) if default != empty else ""}`' + s = f'`{nm}{":" + anno if anno else ""}{"=" + _maybe_nm(default) if default is not empty else ""}`' br = '\xa0'*3 return f'- {s}' + (f'{br}*{doc}*' if doc else '') @@ -374,8 +374,8 @@ def __init__(self, obj, maxline=110, docstring=True): def _fmt_param(self, nm, p): anno,default,kind = p.get('anno',empty), p.get('default',empty), p.get('kind') pre = '*' if kind==Parameter.VAR_POSITIONAL else '**' if kind==Parameter.VAR_KEYWORD else '' - anno = f':{_type_str(anno)}' if anno != empty else '' - default = f'={_fmt_default(default)}' if default != empty else '' + anno = f':{_type_str(anno)}' if anno is not empty else '' + default = f'={_fmt_default(default)}' if default is not empty else '' return pre + nm + anno + default def _repr_markdown_(self): return f"```python\n{self}\n```" @@ -406,7 +406,7 @@ def _clean_text_sig(obj): @patch(as_prop=True) def _ret_str(self:DocmentText): ret = self.dm.get('return', {}) - anno = f"->{_type_str(ret['anno'])}" if ret.get('anno',empty) != empty else '' + anno = f"->{_type_str(ret['anno'])}" if ret.get('anno',empty) is not empty else '' doc = f" # {ret['docment']}" if ret.get('docment') else '' return f"){anno}:{doc}" diff --git a/nbs/04_docments.ipynb b/nbs/04_docments.ipynb index 760f900c..d0883272 100644 --- a/nbs/04_docments.ipynb +++ b/nbs/04_docments.ipynb @@ -600,8 +600,8 @@ "\n", "def _get_full(p, docs, eval_str=False):\n", " anno = p.annotation\n", - " if anno==empty:\n", - " if p.default!=empty: anno = type(p.default)\n", + " if anno is empty:\n", + " if p.default is not empty: anno = type(p.default)\n", " elif eval_str: anno = None\n", " return AttrDict(docment=docs.get(p.name), anno=anno, default=p.default, kind=p.kind)" ] @@ -1874,7 +1874,7 @@ "def _bold(s): return f'**{s}**' if s.strip() else s\n", "\n", "def _maybe_nm(o):\n", - " if (o == inspect._empty): return ''\n", + " if (o is inspect._empty): return ''\n", " else: return o.__name__ if hasattr(o, '__name__') else str(o)" ] }, @@ -1966,13 +1966,13 @@ " def _columns(self):\n", " \"Fields with at least one non-empty value\"\n", " candidates = self._map if self.verbose else {'docment': 'Details'}\n", - " return {k:v for k,v in candidates.items() if any(d[k] != empty for d in self.dm.values())}\n", + " return {k:v for k,v in candidates.items() if any(d[k] is not empty for d in self.dm.values())}\n", "\n", " @property\n", " def has_docment(self): return 'docment' in self._columns and bool(self.params)\n", "\n", " @property\n", - " def has_return(self): return self.returns and any(v != empty for v in self.dm.get('return', {}).values())\n", + " def has_return(self): return self.returns and any(v is not empty for v in self.dm.get('return', {}).values())\n", "\n", " @property\n", " def hdr_str(self):\n", @@ -2001,6 +2001,29 @@ " __repr__ = basic_repr()\n" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "9b1e7c3a", + "metadata": {}, + "outputs": [], + "source": [ + "class _NoBoolEq:\n", + " \"A default like a numpy array, whose `==`/`!=` can't be used as a bool\"\n", + " def __eq__(self, o): raise ValueError(\"ambiguous truth value\")\n", + " __ne__ = __eq__\n", + " __hash__ = object.__hash__\n", + " def __repr__(self): return 'NoBoolEq()'\n", + "\n", + "def _f(a:int, # first\n", + " b=_NoBoolEq()): # second\n", + " \"A function whose default can't be compared with `==`\"\n", + " ...\n", + "\n", + "test_eq(docments(_f, full=True)['b']['anno'], _NoBoolEq)\n", + "assert 'NoBoolEq()' in str(DocmentTbl(_f))" + ] + }, { "cell_type": "markdown", "id": "80fb1215", @@ -2254,7 +2277,7 @@ "class DocmentList(_DocmentBase):\n", " def _fmt(self, nm, p):\n", " anno,default,doc = _maybe_nm(p.get('anno','')), p.get('default',empty), p.get('docment','')\n", - " s = f'`{nm}{\":\" + anno if anno else \"\"}{\"=\" + _maybe_nm(default) if default != empty else \"\"}`'\n", + " s = f'`{nm}{\":\" + anno if anno else \"\"}{\"=\" + _maybe_nm(default) if default is not empty else \"\"}`'\n", " br = '\\xa0'*3\n", " return f'- {s}' + (f'{br}*{doc}*' if doc else '')\n", "\n", @@ -2405,8 +2428,8 @@ " def _fmt_param(self, nm, p):\n", " anno,default,kind = p.get('anno',empty), p.get('default',empty), p.get('kind')\n", " pre = '*' if kind==Parameter.VAR_POSITIONAL else '**' if kind==Parameter.VAR_KEYWORD else ''\n", - " anno = f':{_type_str(anno)}' if anno != empty else ''\n", - " default = f'={_fmt_default(default)}' if default != empty else ''\n", + " anno = f':{_type_str(anno)}' if anno is not empty else ''\n", + " default = f'={_fmt_default(default)}' if default is not empty else ''\n", " return pre + nm + anno + default\n", "\n", " def _repr_markdown_(self): return f\"```python\\n{self}\\n```\"" @@ -2484,7 +2507,7 @@ "@patch(as_prop=True)\n", "def _ret_str(self:DocmentText):\n", " ret = self.dm.get('return', {})\n", - " anno = f\"->{_type_str(ret['anno'])}\" if ret.get('anno',empty) != empty else ''\n", + " anno = f\"->{_type_str(ret['anno'])}\" if ret.get('anno',empty) is not empty else ''\n", " doc = f\" # {ret['docment']}\" if ret.get('docment') else ''\n", " return f\"){anno}:{doc}\"" ]