Skip to content

Commit

Permalink
progress
Browse files Browse the repository at this point in the history
  • Loading branch information
lazka committed Aug 17, 2016
1 parent 9714077 commit fcabb5b
Show file tree
Hide file tree
Showing 11 changed files with 588 additions and 171 deletions.
23 changes: 23 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ Helper functions to work with the fsnative type

.. autoclass:: fsnative

.. autofunction:: path2fsn

.. autofunction:: fsn2text

.. autofunction:: fsn2bytes

.. autofunction:: bytes2fsn

.. autofunction:: uri2fsn

.. autofunction:: fsn2uri

.. autofunction:: fsn2uri_ascii


Stdlib Replacements
-------------------
Expand Down Expand Up @@ -57,6 +71,8 @@ default arguments) or Unicode support for Windows is added (sys.argv)

.. autofunction:: unsetenv

.. autofunction:: print_


Documentation Types
-------------------
Expand All @@ -75,3 +91,10 @@ types depending on the Python version and platform used.

Represents :obj:`python:str` under Python 2 and :obj:`python3:bytes` under
Python 3.


.. class:: pathlike()

Anything the Python stdlib allows as a path. This includes `fsnative`,
ASCII :obj:`python:str` under Python 2 + Windows and :obj:`python3:bytes`
under Python 3 + Unix.
8 changes: 4 additions & 4 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ How?

It introduces a virtual type called `fsnative` which actually represents

- `unicode` under Py2 + Windows
- `str` under Py2 on other platforms
- `str` under Py3 + Windows
- `str` + ``surrogates`` under Py3 on other platforms [#]_
- :obj:`python:unicode` under Py2 + Windows
- :obj:`python:str` under Py2 on other platforms
- :obj:`python3:str` under Py3 + Windows
- :obj:`python3:str` + ``surrogates`` under Py3 on other platforms [#]_

The type is used for file names, environment variables and process arguments
and senf provides functions so you can tread it as an opaque type and not have
Expand Down
34 changes: 16 additions & 18 deletions senf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.

from ._fsnative import fsnative, py2fsn
from ._fsnative import fsnative, path2fsn, fsn2text, fsn2bytes, \
bytes2fsn, uri2fsn, fsn2uri, fsn2uri_ascii
from ._print import print_
from ._stdlib import sep, pathsep, curdir, pardir, altsep, extsep, devnull, \
defpath, getcwd, getenv, unsetenv, putenv
defpath, getcwd
from ._argv import argv
from ._environ import environ
from ._environ import environ, getenv, unsetenv, putenv
from ._temp import mkstemp, gettempdir, gettempprefix, mkdtemp


fsnative, print_, py2fsn, getcwd, getenv, unsetenv, putenv
fsnative, print_, getcwd, getenv, unsetenv, putenv, environ, \
path2fsn, fsn2text, fsn2bytes, bytes2fsn, uri2fsn, fsn2uri, mkstemp, \
gettempdir, gettempprefix, mkdtemp, fsn2uri_ascii


version = (0, 0, 0)
Expand All @@ -31,45 +35,39 @@
"""`str`: A version string"""


environ = environ
"""Dict[`fsnative`, `fsnative`]: Like `os.environ` but contains unicode keys
and values under Windows + Python 2
"""


argv = argv
"""List[`fsnative`]: Like `sys.argv` but contains unicode under
Windows + Python 2
"""


sep = sep
"""`fsnative`: Like os.sep or os.path.sep but a fsnative path"""
"""`fsnative`: Like `os.sep` but a `fsnative`"""


pathsep = pathsep
"""`fsnative`: Like os.pathsep but a fsnative path"""
"""`fsnative`: Like `os.pathsep` but a `fsnative`"""


curdir = curdir
"""`fsnative`: Like os.curdir but a fsnative path"""
"""`fsnative`: Like `os.curdir` but a `fsnative`"""


pardir = pardir
"""`fsnative`: Like os.pardir but a fsnative path"""
"""`fsnative`: Like `os.pardir` but a fsnative"""


altsep = altsep
"""`fsnative` or `None`: Like os.altsep but a fsnative path"""
"""`fsnative` or `None`: Like `os.altsep` but a `fsnative` or `None`"""


extsep = extsep
"""`fsnative`: Like os.extsep but a fsnative path"""
"""`fsnative`: Like `os.extsep` but a `fsnative`"""


devnull = devnull
"""`fsnative`: Like os.devnull but a fsnative path"""
"""`fsnative`: Like `os.devnull` but a `fsnative`"""


defpath = defpath
"""`fsnative`: Like os.defpath but a fsnative path"""
"""`fsnative`: Like `os.defpath` but a `fsnative`"""
10 changes: 10 additions & 0 deletions senf/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,23 @@


if PY2:
from urlparse import urlparse
urlparse
from urllib import pathname2url, url2pathname, quote
pathname2url, url2pathname, quote

string_types = (str, unicode)
text_type = unicode

iteritems = lambda d: d.iteritems()
itervalues = lambda d: d.itervalues()
iterkeys = lambda d: d.iterkeys()
elif PY3:
from urllib.parse import urlparse, quote
urlparse, quote
from urllib.request import pathname2url, url2pathname
pathname2url, url2pathname

string_types = (str,)
text_type = str

Expand Down
106 changes: 81 additions & 25 deletions senf/_environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import collections

from ._compat import text_type, PY2
from ._fsnative import path2fsn
if os.name == "nt":
from ._winapi import SetEnvironmentVariableW, GetEnvironmentStringsW, \
FreeEnvironmentStringsW, GetEnvironmentVariableW
Expand Down Expand Up @@ -115,39 +116,45 @@ def read_windows_environ():
return dict_


class WindowsEnviron(collections.MutableMapping):
"""os.environ that supports unicode on Windows.
Like os.environ it will only contain the environment content present at
load time. Changes will be synced with the real environment.
class Environ(collections.MutableMapping):
"""Dict[`fsnative`, `fsnative`]: Like `os.environ` but contains unicode
keys and values under Windows + Python 2
"""

def __init__(self):
try:
env = read_windows_environ()
except WindowsError:
env = {}
if os.name == "nt" and PY2:
try:
env = read_windows_environ()
except WindowsError:
env = {}
else:
env = os.environ
self._env = env

def __getitem__(self, key):
key = text_type(key)
key = path2fsn(key)
return self._env[key]

def __setitem__(self, key, value):
key = text_type(key)
value = text_type(value)
try:
set_windows_env_var(key, value)
except WindowsError:
pass
key = path2fsn(key)
value = path2fsn(value)

if os.name == "nt" and PY2:
try:
set_windows_env_var(key, value)
except WindowsError:
pass
self._env[key] = value

def __delitem__(self, key):
key = text_type(key)
try:
del_windows_env_var(key)
except WindowsError:
pass
key = path2fsn(key)

if os.name == "nt" and PY2:
try:
del_windows_env_var(key)
except WindowsError:
pass

del self._env[key]

def __iter__(self):
Expand All @@ -160,10 +167,59 @@ def __repr__(self):
return repr(self._env)


def create_environ():
environ = Environ()


def getenv(key, value=None):
"""Like `os.getenv` but returns unicode under Windows + Python 2
Args:
key (pathlike): The env var to get
value (object): The value to return if the env var does not exist
Returns:
`fsnative` or `object`:
The env var or the passed value if it doesn't exist
"""

key = path2fsn(key)
if os.name == "nt" and PY2:
return WindowsEnviron()
return os.environ
return environ.get(key, value)
return os.getenv(key, value)


environ = create_environ()
def unsetenv(key):
"""Like `os.unsetenv` but takes unicode under Windows + Python 2
Args:
key (pathlike): The env var to unset
"""

key = path2fsn(key)
if os.name == "nt":
# python 3 has no unsetenv under Windows -> use our ctypes one as well
try:
del_windows_env_var(key)
except WindowsError:
pass
else:
os.unsetenv(key)


def putenv(key, value):
"""Like `os.putenv` but takes unicode under Windows + Python 2
Args:
key (pathlike): The env var to get
value (pathlike): The value to set
"""

key = path2fsn(key)
value = path2fsn(value)

if os.name == "nt" and PY2:
try:
set_windows_env_var(key, value)
except WindowsError:
pass
else:
os.putenv(key, value)

0 comments on commit fcabb5b

Please sign in to comment.