carljm: This approach looks fine to me; thanks for the report and fix!

Normally we try to automatically provide the right imports for annotations too, so `monkeytype apply` doesn't result in modules with missing imports. However, I don't think that's possible with the current runtime implementation of `NewType`; the calling module is not stored anywhere in the resulting function object, so there's no way we can introspect it. So unless we change that in `typing.py` we're stuck with the limitation of not being able to automatically add NewType imports.

It would be great to add tests for NewType in `test_stubs.py`; thanks!
carljm: Er, never mind about generating imports; `NewType` annotations can only occur as existing annotations, never as traced types. So the import should always be present already.
folz: Added a test for this and updated the changelog. I think you're right that this doesn't need to worry about imports - if the import isn't present, it wasn't valid to mypy in the first place.
carljm: Awesome, thank you!
diff --git a/.gitignore b/.gitignore
index a31079d..2f4a0c7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ htmlcov/
 doc/_build
 dist/
 build/
+.idea/
\ No newline at end of file
diff --git a/CHANGES.rst b/CHANGES.rst
index 3350f81..c3d23d3 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -5,7 +5,7 @@ master
 ------
 
 * Fix passing args to script run with ``monkeytype run`` (#18; merge of #21).
-
+* Fix generated annotations for NewType types (#22; merge of #23).
 
 17.12.1
 -------
diff --git a/monkeytype/stubs.py b/monkeytype/stubs.py
index 574fc35..8abc90b 100644
--- a/monkeytype/stubs.py
+++ b/monkeytype/stubs.py
@@ -319,6 +319,8 @@ def render_annotation(anno: Any) -> str:
         elem_type = _get_optional_elem(anno)
         rendered = render_annotation(elem_type)
         return 'Optional[' + rendered + ']'
+    elif hasattr(anno, '__supertype__'):
+        return anno.__name__
     elif getattr(anno, '__module__', None) == 'typing':
         return repr(anno).replace('typing.', '')
     elif anno is NoneType:

`NewType` generated into invalid type signatures
Given

```python
UserId = NewType('UserId', int)

def get_user(self, user_id: UserId) -> 'User':
```

MonkeyType generates

```python
def get_user(
    self,
    user_id: <function NewType.<locals>.new_type at 0x1090a52f0>
) -> 'User': ...
```

which then causes retype to fail with this error message:

```
error: /path/to/module.py: invalid syntax (<unknown>, line 18)
```

This happens even when `--exclude-unparsable-defaults` is passed.

I was able to come up with a solution to this, which I'll submit a PR for. However, it seems hacky to me and I'd appreciate feedback on it.
diff --git a/tests/test_stubs.py b/tests/test_stubs.py
index bbe5913..acfa771 100644
--- a/tests/test_stubs.py
+++ b/tests/test_stubs.py
@@ -11,6 +11,7 @@ from typing import (
     Generator,
     Iterator,
     List,
+    NewType,
     Optional,
     Set,
     Tuple,
@@ -42,6 +43,8 @@ from monkeytype.tracing import CallTrace
 from monkeytype.typing import NoneType
 from .util import Dummy
 
+UserId = NewType('UserId', int)
+
 
 class TestImportMap:
     def test_merge(self):
@@ -133,6 +136,10 @@ def has_length_exceeds_120_chars(
     return None
 
 
+def has_newtype_param(user_id: UserId) -> None:
+    pass
+
+
 class TestHasUnparsableDefaults:
     @pytest.mark.parametrize(
         'func, expected',
@@ -241,6 +248,11 @@ class TestFunctionStub:
         expected = 'def test(x: Optional[int] = None) -> None: ...'
         assert stub.render() == expected
 
+    def test_newtype_parameter_annotation(self):
+        stub = FunctionStub('test', inspect.signature(has_newtype_param), FunctionKind.MODULE)
+        expected = 'def test(user_id: UserId) -> None: ...'
+        assert stub.render() == expected
+
 
 def _func_stub_from_callable(func: Callable, strip_modules: List[str] = None):
     kind = FunctionKind.from_callable(func)

pip install -e .[dev]
parse_log_pytest
Pipfile
pytest pytest-smartcov
pip install --user pipenv
3.6
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==22.2.0
certifi==2021.5.30
click==8.0.4
coverage==6.2
distlib==0.3.9
filelock==3.4.1
importlib-metadata==4.8.3
importlib-resources==5.4.0
iniconfig==1.1.1
-e git+https://github.com/Instagram/MonkeyType.git@666b2a1c5fc09f219a9ef5811af68946cd9c1830#egg=MonkeyType
packaging==21.3
pathspec==0.9.0
pipenv==2022.4.8
pipfile==0.0.2
platformdirs==2.4.0
pluggy==1.0.0
py==1.11.0
pyparsing==3.1.4
pytest==7.0.1
pytest-smartcov==0.3
retype==21.10.0
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
tomli==1.2.3
typed-ast==1.5.5
typing_extensions==4.1.1
virtualenv==20.17.1
virtualenv-clone==0.5.7
zipp==3.6.0

name: MonkeyType
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - pipfile=0.0.2=py_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - click==8.0.4
      - coverage==6.2
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - packaging==21.3
      - pathspec==0.9.0
      - pluggy==1.0.0
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - pytest-smartcov==0.3
      - retype==21.10.0
      - tomli==1.2.3
      - typed-ast==1.5.5
      - typing-extensions==4.1.1
      - zipp==3.6.0
prefix: /opt/conda/envs/MonkeyType

tests/test_stubs.py::TestFunctionStub::test_newtype_parameter_annotation
tests/test_stubs.py::TestImportMap::test_merge tests/test_stubs.py::TestImportBlockStub::test_single_import tests/test_stubs.py::TestImportBlockStub::test_multiple_imports tests/test_stubs.py::TestHasUnparsableDefaults::test_has_unparsable_defaults[simple_add-False] tests/test_stubs.py::TestHasUnparsableDefaults::test_has_unparsable_defaults[has_parsable_defaults-False] tests/test_stubs.py::TestHasUnparsableDefaults::test_has_unparsable_defaults[has_unparsable_default-True] tests/test_stubs.py::TestFunctionStub::test_classmethod tests/test_stubs.py::TestFunctionStub::test_staticmethod tests/test_stubs.py::TestFunctionStub::test_property tests/test_stubs.py::TestFunctionStub::test_simple tests/test_stubs.py::TestFunctionStub::test_with_prefix tests/test_stubs.py::TestFunctionStub::test_strip_modules tests/test_stubs.py::TestFunctionStub::test_async_function tests/test_stubs.py::TestFunctionStub::test_optional_parameter_annotation tests/test_stubs.py::TestFunctionStub::test_optional_union_parameter_annotation tests/test_stubs.py::TestFunctionStub::test_optional_return_annotation tests/test_stubs.py::TestFunctionStub::test_split_parameters_across_multiple_lines tests/test_stubs.py::TestFunctionStub::test_default_none_parameter_annotation tests/test_stubs.py::TestClassStub::test_render tests/test_stubs.py::TestModuleStub::test_render tests/test_stubs.py::TestBuildModuleStubs::test_build_module_stubs tests/test_stubs.py::TestStubIndexBuilder::test_ignore_non_matching_functions tests/test_stubs.py::TestStubIndexBuilder::test_build_index tests/test_stubs.py::TestUpdateSignatureArgs::test_update_arg tests/test_stubs.py::TestUpdateSignatureArgs::test_update_arg_with_anno tests/test_stubs.py::TestUpdateSignatureArgs::test_update_self tests/test_stubs.py::TestUpdateSignatureArgs::test_update_class tests/test_stubs.py::TestUpdateSignatureReturn::test_update_return tests/test_stubs.py::TestUpdateSignatureReturn::test_update_return_with_anno tests/test_stubs.py::TestUpdateSignatureReturn::test_update_yield tests/test_stubs.py::TestUpdateSignatureReturn::test_update_yield_and_return tests/test_stubs.py::TestUpdateSignatureReturn::test_update_yield_none_and_return tests/test_stubs.py::TestUpdateSignatureReturn::test_update_yield_and_return_none tests/test_stubs.py::TestFunctionKind::test_from_callable[a_static_method-FunctionKind.STATIC] tests/test_stubs.py::TestFunctionKind::test_from_callable[a_class_method-FunctionKind.CLASS] tests/test_stubs.py::TestFunctionKind::test_from_callable[an_instance_method-FunctionKind.INSTANCE] tests/test_stubs.py::TestFunctionKind::test_from_callable[a_property-FunctionKind.PROPERTY] tests/test_stubs.py::TestFunctionKind::test_from_callable[a_module_func-FunctionKind.MODULE] tests/test_stubs.py::TestFunctionDefinition::test_has_self[a_static_method-False] tests/test_stubs.py::TestFunctionDefinition::test_has_self[a_class_method-True] tests/test_stubs.py::TestFunctionDefinition::test_has_self[an_instance_method-True] tests/test_stubs.py::TestFunctionDefinition::test_has_self[a_property-True] tests/test_stubs.py::TestFunctionDefinition::test_has_self[a_module_func-False] tests/test_stubs.py::TestFunctionDefinition::test_from_callable[a_static_method-expected0] tests/test_stubs.py::TestFunctionDefinition::test_from_callable[a_class_method-expected1] tests/test_stubs.py::TestFunctionDefinition::test_from_callable[an_instance_method-expected2] tests/test_stubs.py::TestFunctionDefinition::test_from_callable[a_property-expected3] tests/test_stubs.py::TestFunctionDefinition::test_from_callable[a_module_func-expected4] tests/test_stubs.py::TestFunctionDefinition::test_from_callable[an_async_func-expected5] tests/test_stubs.py::TestShrinkTracedTypes::test_shrink_args tests/test_stubs.py::TestShrinkTracedTypes::test_shrink_return tests/test_stubs.py::TestShrinkTracedTypes::test_shrink_yield tests/test_stubs.py::TestGetImportsForAnnotation::test_no_imports[_empty0] tests/test_stubs.py::TestGetImportsForAnnotation::test_no_imports[_empty1] tests/test_stubs.py::TestGetImportsForAnnotation::test_no_imports[not tests/test_stubs.py::TestGetImportsForAnnotation::test_no_imports[int] tests/test_stubs.py::TestGetImportsForAnnotation::test_special_case_types[anno0-expected0] tests/test_stubs.py::TestGetImportsForAnnotation::test_special_case_types[anno1-expected1] tests/test_stubs.py::TestGetImportsForAnnotation::test_user_defined_class tests/test_stubs.py::TestGetImportsForAnnotation::test_container_types[Dict-expected0] tests/test_stubs.py::TestGetImportsForAnnotation::test_container_types[List-expected1] tests/test_stubs.py::TestGetImportsForAnnotation::test_container_types[Set-expected2] tests/test_stubs.py::TestGetImportsForAnnotation::test_container_types[Tuple-expected3] tests/test_stubs.py::TestGetImportsForAnnotation::test_container_types[Type-expected4] tests/test_stubs.py::TestGetImportsForAnnotation::test_container_types[anno5-expected5] tests/test_stubs.py::TestGetImportsForAnnotation::test_nested_class tests/test_stubs.py::TestBuildModuleStubsFromTraces::test_remove_funcs_with_unparsable_defaults
.gitignore monkeytype/stubs.py CHANGES.rst
.gitignore monkeytype/stubs.py CHANGES.rst