Repository: python-poetry/poetry

Issue:
Poetry fails with intenral error on malformed author
<!--
  Hi there! Thank you for discovering and submitting an issue.

  Before you submit this; let's make sure of a few things.
  Please make sure the following boxes are ticked if they are correct.
  If not, please try and fulfill these first.
-->

<!-- Checked checkbox should look like this: [x] -->
- [x] I am on the [latest](https://github.com/sdispater/poetry/releases/latest) Poetry version.
- [x] I have searched the [issues](https://github.com/sdispater/poetry/issues) of this repo and believe that this is not a duplicate.
- [x] If an exception occurs when executing a command, I executed it again in debug mode (`-vvv` option).

<!--
  Once those are done, if you're able to fill in the following list with your information,
  it'd be very helpful to whoever handles the issue.
-->

- **OS version and name**: Windows 10
- **Poetry version**: 0.12.16
- **Link of a [Gist](https://gist.github.com/) with the contents of your pyproject.toml file**: <!-- Gist Link Here -->

## Issue
<!-- Now feel free to write your issue, but please be descriptive! Thanks again 🙌 ❤️ -->

I didn't pay attention to the format of the authors field and just typed in "name@domain.com" and got the following failure

```
[AttributeError]
'NoneType' object has no attribute 'group'

Exception trace:
 p:\.venv\lib\site-packages\cleo\application.py in run() at line 94
   status_code = self.do_run(input_, output_)
 p:\.venv\lib\site-packages\poetry\console\application.py in do_run() at line 88
   return super(Application, self).do_run(i, o)
 p:\.venv\lib\site-packages\cleo\application.py in do_run() at line 197
   status_code = command.run(input_, output_)
 p:\.venv\lib\site-packages\poetry\console\commands\command.py in run() at line 77
   return super(BaseCommand, self).run(i, o)
 p:\.venv\lib\site-packages\cleo\commands\base_command.py in run() at line 146
   status_code = self.execute(input_, output_)
 p:\.venv\lib\site-packages\cleo\commands\command.py in execute() at line 107
   return self.handle()
 p:\.venv\lib\site-packages\poetry\console\commands\install.py in handle() at line 61
   builder = EditableBuilder(self.poetry, self._env, NullIO())
 p:\.venv\lib\site-packages\poetry\masonry\builders\builder.py in __init__() at line 50
   self._meta = Metadata.from_package(self._package)
 p:\.venv\lib\site-packages\poetry\masonry\metadata.py in from_package() at line 54
   meta.author = package.author_name
 p:\.venv\lib\site-packages\poetry\packages\package.py in author_name() at line 130
   return self._get_author()["name"]
 p:\.venv\lib\site-packages\poetry\packages\package.py in _get_author() at line 146
   name = m.group("name")

install [--no-dev] [--dry-run] [-E|--extras EXTRAS] [--develop DEVELOP]
```

What I'd expect
- An error saying that the field is malformed
- `poetry check` to report this error as well.


Discussion:
I cannot reproduce the behavior you see...

I am prevented from using `name@domain.com` as author when running `poetry init`, changing pyproject.toml authors line to `authors = "name@domain.com"` returns error when using `poetry check`:

```
poetry check
Error: [authors] 'name@domain.com' is not of type 'array'
```
Thats what I get for thinking my post was obvious enough that I didn't need to take the time to strip people's private information from it :)

My example string was meant to be from within an array and not in place of the array.  Here is a stripped version of my pyproject.toml

```
[tool.poetry]
name = "foo"
version = "2.0.19"
description = "nest utility to build nibuild component"
authors = ["name@domain.com>"]

[tool.poetry.scripts]
foo = 'foo.__main__:main'

[tool.poetry.dependencies]
python = "^3.6"
GitPython = "^2.1"
keyring = "^15.0"
"keyrings.alt" = "^3.0"
mako = "^1.0"
networkx = "^2.0"
p4python  = "^2017"  # this version has linux binary
toml = "^0.10.0"
voluptuous = "^0.11.0"

[tool.poetry.dev-dependencies]
black = "^19.3b0"
check-manifest = "^0.37"
coverage = "^4.5.2"
docutils = "^0.14"
hacking = "^1.1.0"
mock = "^2.0.0"
mypy = "^0.670"
pep8-naming = "^0.8.2"
pytest-cov = "^2.6.1"
pytest = "^4.3.0"

[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"
```
Sorry, couldn't reproduce with that either. When do you see this error? 

> Sorry, couldn't reproduce with that either

What did you get in this case?  Are you reproducing with a release version or a version from git?

Unless a validity check has been added elsewhere, [there is no check inside of `get_author` still](https://github.com/sdispater/poetry/blob/master/poetry/packages/package.py#L140)

> When do you see this error?

I was just doing basic stuff like `poetry install` and `poetry run`.
> What did you get in this case? 

Install works fine, `poetry run foo` fails, but because there's no foo.

<details>
<summary>output</summary>

<pre>
poetry install
Creating virtualenv foo-py3.6 in /Users/kristofferb/Library/Caches/pypoetry/virtualenvs
Updating dependencies
Resolving dependencies... (0.5s)

Writing lock file


Package operations: 42 installs, 0 updates, 0 removals

  - Installing zipp (0.5.1)
  - Installing importlib-metadata (0.17)
  - Installing mccabe (0.5.3)
  - Installing pycodestyle (2.0.0)
  - Installing pyflakes (1.2.3)
  - Installing six (1.12.0)
  - Installing atomicwrites (1.3.0)
  - Installing attrs (19.1.0)
  - Installing flake8 (2.6.2)
  - Installing more-itertools (7.0.0)
  - Installing pluggy (0.12.0)
  - Installing py (1.8.0)
  - Installing smmap2 (2.0.5)
  - Installing wcwidth (0.1.7)
  - Installing appdirs (1.4.3)
  - Installing click (7.0)
  - Installing coverage (4.5.3)
  - Installing decorator (4.4.0)
  - Installing entrypoints (0.3)
  - Installing flake8-polyfill (1.0.2)
  - Installing gitdb2 (2.0.5)
  - Installing markupsafe (1.1.1)
  - Installing mypy-extensions (0.4.1)
  - Installing pbr (5.2.1)
  - Installing pytest (4.5.0)
  - Installing toml (0.10.0)
  - Installing typed-ast (1.3.5)
  - Installing black (19.3b0)
  - Installing check-manifest (0.37)
  - Installing docutils (0.14)
  - Installing gitpython (2.1.11)
  - Installing hacking (1.1.0)
  - Installing keyring (15.2.0)
  - Installing keyrings.alt (3.1.1)
  - Installing mako (1.0.11)
  - Installing mock (2.0.0)
  - Installing mypy (0.670)
  - Installing networkx (2.3)
  - Installing p4python (2017.2.1615960)
  - Installing pep8-naming (0.8.2)
  - Installing pytest-cov (2.7.1)
  - Installing voluptuous (0.11.5)
</pre>

<pre>
poetry run foo

[ModuleOrPackageNotFound]
No file/folder found for package foo

run <args> (<args>)...
</pre>

</details>

> Are you reproducing with a release version or a version from git?

<details>
<summary>poetry debug:info</summary>

<pre>
Poetry
======

 * Version: 0.12.16
 * Python:  3.6.7


Virtualenv
==========

 * Python:         3.6.7
 * Implementation: CPython
 * Path:           NA


System
======

 * Platform: darwin
 * OS:       posix
 * Python:   /Users/kristofferb/.pyenv/versions/3.6.7
</pre>

</details>

I am on MacOS, that could behave differently from Windows (though I do not see that the code being touceh
@epage Thank you for submitting this report!

I was only able to reproduce the error when running `poetry install` on a poetry project with and without an existing lockfile. However, the dependencies were still installed properly. This will be filed as a bug for now.

I am also unable to reproduce your error using the example `pyproject.toml`. I am using a release version of poetry.
> I am also unable to reproduce your error using the example pyproject.toml. I am using a release version of poetry.

So I played with it some more.  You have to at minimum have `foo/__init__.py` (even if empty) which makes sense since what it is doing is installing an editable version of the package (I think).

I'm surprised `run` doesn't reproduce this , that it has different behavior than `install`.  I would have assumed `run` implies `install`.
Yes and not: `run` does not implies `install`, but it can look into the pyproject.toml `scripts` directly:

https://github.com/sdispater/poetry/blob/426dbdcff02eb0552f4e336bedb53aa16198c57f/poetry/console/commands/run.py#L15-L18

Also, issue about author field already exists (#370).

P.S.: I always add `__init__.py` to my packages because of habit and relative import support.
> Yes and not: run does not implies install, but it can look into the pyproject.toml scripts directly:

Knowing poetry was inspired by cargo is why I felt this behavior was surprising.  In cargo, I can just type `cargo run` and it will prepare everything for running, including
- Ensuring the lock file is not out of sync with the manifest file
- Ensure deps are processed
- Ensure it is runnable

So it was surprising when I typed `poetry run` and it didn't install all of my deps into the venv.  I think I've also seen warnings about my lock file being out of date, so it seems it also doesn't implicitly sync the lock file with the manifest file.

> Also, issue about author field already exists (#370).

I missed that, thanks!  How much they are a dup is a question of how someone fixes 370.  In that one, the user put in a character that should be valid but instead failed.  This could just be fixed by updating the parser without impacting the error reporting.  In this one, I put in an invalid author and the error was not helpful.  

Personally, I think three things need to be done
- Update the parser
- Ensure a good error is reported
- Ensure the error is returned by `poetry check`
`poetry check` seems to be a `pyproject.toml` linter.
It should be a subset of the allowed cases in practice IMO.

It should be a plugin eventually.
Same issue, seeing:

```
$ poetry install
Updating dependencies
Resolving dependencies... (1.5s)

Writing lock file

Nothing to install or update


[AttributeError]
'NoneType' object has no attribute 'group'
```

With:

```toml
[tool.poetry]
name = "art"
version = "0.1.0"
description = ""
authors = ["foo@bar.com"]

[tool.poetry.dependencies]
python = "^3.7"
p5 = "^0.6.0"
ipython = "^7.8.0"

[tool.poetry.dev-dependencies]
pytest = "^3.0"

[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"
```

Everything works correctly if I use `authors = ["Foo foo@bar.com>"]`.

It would be nice to validate `pyproject.toml` and output a friendly error message if it fails validation.
What version of `poetry` do you use? With the latest 1.0.0b3 I cannot reproduce it :(
I was on 1.0.0b2, it does appear to be happening under b3 as well:

```
$ poetry install
Installing dependencies from lock file

Nothing to install or update


[AttributeError]
'NoneType' object has no attribute 'group'
```

Same `pyproject.toml` as above, errors with `foo@bar.com` but not `Foo <foo@bar.com>`. Happens under Python 3.7 and 3.8.
I was now able to reproduce it. I'm with @epage that `poetry check` should report this as well.

I further think, that the method, that do the validation, should also check the validation/presents of more mandatory fields and this should be called every time before poetry starts any action where a valid `pyproject.toml` is needed.

I could work on this. What do you think @sdispater, @stephsamson ?

Resolving patch:
diff --git a/poetry/packages/package.py b/poetry/packages/package.py
--- a/poetry/packages/package.py
+++ b/poetry/packages/package.py
@@ -162,6 +162,12 @@ def _get_author(self):  # type: () -> dict
 
         m = AUTHOR_REGEX.match(self._authors[0])
 
+        if m is None:
+            raise ValueError(
+                "Invalid author string. Must be in the format: "
+                "John Smith <john@example.com>"
+            )
+
         name = m.group("name")
         email = m.group("email")
 
@@ -173,6 +179,12 @@ def _get_maintainer(self):  # type: () -> dict
 
         m = AUTHOR_REGEX.match(self._maintainers[0])
 
+        if m is None:
+            raise ValueError(
+                "Invalid maintainer string. Must be in the format: "
+                "John Smith <john@example.com>"
+            )
+
         name = m.group("name")
         email = m.group("email")
 


Test patch:
diff --git a/tests/packages/test_package.py b/tests/packages/test_package.py
--- a/tests/packages/test_package.py
+++ b/tests/packages/test_package.py
@@ -18,6 +18,19 @@ def test_package_authors():
     assert package.author_email is None
 
 
+def test_package_authors_invalid():
+    package = Package("foo", "0.1.0")
+
+    package.authors.insert(0, "<John Doe")
+    with pytest.raises(ValueError) as e:
+        package.author_name
+
+    assert (
+        str(e.value)
+        == "Invalid author string. Must be in the format: John Smith <john@example.com>"
+    )
+
+
 @pytest.mark.parametrize("category", ["main", "dev"])
 def test_package_add_dependency_vcs_category(category):
     package = Package("foo", "0.1.0")