Repository: Tinche/aiofiles (language: python)

Issue:
Add aiofiles.os.symlink function
The `os` module in the stdlib provides a function called `os.symlink` that creates a symlink to the src file. This PR adds the async version of that.

Docs: https://docs.python.org/3/library/os.html#os.symlink

I've added the relevant unit test in test_os.py, plus updated the `aiofiles.os.link` test to better differentiate the two.


Discussion / hints:
# [Codecov](https://codecov.io/gh/Tinche/aiofiles/pull/124?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tin+Tvrtkovi%C4%87) Report
> Merging [#124](https://codecov.io/gh/Tinche/aiofiles/pull/124?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tin+Tvrtkovi%C4%87) (554e090) into [master](https://codecov.io/gh/Tinche/aiofiles/commit/db6c5bef7b36c8b7298fd21148709044e3380bc5?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tin+Tvrtkovi%C4%87) (db6c5be) will **increase** coverage by `0.03%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/Tinche/aiofiles/pull/124/graphs/tree.svg?width=650&height=150&src=pr&token=nUnoVWaIfu&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tin+Tvrtkovi%C4%87)](https://codecov.io/gh/Tinche/aiofiles/pull/124?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tin+Tvrtkovi%C4%87)

```diff
@@            Coverage Diff             @@
##           master     #124      +/-   ##
==========================================
+ Coverage   89.66%   89.70%   +0.03%     
==========================================
  Files          10       10              
  Lines         300      301       +1     
==========================================
+ Hits          269      270       +1     
  Misses         31       31              
```


| [Impacted Files](https://codecov.io/gh/Tinche/aiofiles/pull/124?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tin+Tvrtkovi%C4%87) | Coverage Δ | |
|---|---|---|
| [src/aiofiles/os.py](https://codecov.io/gh/Tinche/aiofiles/pull/124/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tin+Tvrtkovi%C4%87#diff-c3JjL2Fpb2ZpbGVzL29zLnB5) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Tinche/aiofiles/pull/124?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tin+Tvrtkovi%C4%87).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tin+Tvrtkovi%C4%87)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Tinche/aiofiles/pull/124?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tin+Tvrtkovi%C4%87). Last update [db6c5be...554e090](https://codecov.io/gh/Tinche/aiofiles/pull/124?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tin+Tvrtkovi%C4%87). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Tin+Tvrtkovi%C4%87).

You're on quite a roll! Thanks.

Fix patch:
diff --git a/src/aiofiles/os.py b/src/aiofiles/os.py
index faed721..19e5699 100644
--- a/src/aiofiles/os.py
+++ b/src/aiofiles/os.py
@@ -30,6 +30,7 @@ async def run(*args, loop=None, executor=None, **kwargs):
 removedirs = wrap(os.removedirs)
 link = wrap(os.link)
 symlink = wrap(os.symlink)
+readlink = wrap(os.readlink)
 
 if hasattr(os, "sendfile"):
     sendfile = wrap(os.sendfile)


Test patch:
diff --git a/tests/test_os.py b/tests/test_os.py
index d496b41..8e9b3cc 100644
--- a/tests/test_os.py
+++ b/tests/test_os.py
@@ -275,3 +275,14 @@ async def test_symlink():
     )
     await aiofiles.os.remove(dst_filename)
     assert exists(src_filename) and exists(dst_filename) is False
+
+
+@pytest.mark.asyncio
+async def test_readlink():
+    """Test the readlink call."""
+    src_filename = join(dirname(__file__), "resources", "test_file1.txt")
+    dst_filename = join(dirname(__file__), "resources", "test_file2.txt")
+    await aiofiles.os.symlink(src_filename, dst_filename)
+    symlinked_path = await aiofiles.os.readlink(dst_filename)
+    assert src_filename == symlinked_path
+    await aiofiles.os.remove(dst_filename)