merge with 3.21.3
The change in unittest_serverctl.py is needed because of daef7ce08fea
(from 3.20.11) and 3914388b2d0f (from the 3.22 branch). Due to both
changes, CubicWebTC.config.repository no longer creates a new repository
(and thus, a new connection). Since both DBDumpCommand and
CubicWebTC.tearDown try to shutdown the repo, tearDown breaks apart.
The solution is to temporarily disable ServerConfiguration's config
cache. By forcing DBDumpCommand to get a new configuration object, it
then gets its own Repo object, allowing tearDown and DBDumpCommand to
work independently.
--- a/__init__.py Wed Dec 09 18:42:13 2015 +0100
+++ b/__init__.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,23 +22,21 @@
# ignore the pygments UserWarnings
import warnings
-import cPickle
import zlib
warnings.filterwarnings('ignore', category=UserWarning,
message='.*was already imported',
module='.*pygments')
-import __builtin__
-# '_' is available in builtins to mark internationalized string but should
-# not be used to do the actual translation
-if not hasattr(__builtin__, '_'):
- __builtin__._ = unicode
+from six import PY2, binary_type, text_type
+from six.moves import builtins
CW_SOFTWARE_ROOT = __path__[0]
import sys, os, logging
-from StringIO import StringIO
+from io import BytesIO
+
+from six.moves import cPickle as pickle
from logilab.common.deprecation import deprecated
from logilab.common.logging_ext import set_log_methods
@@ -56,6 +54,14 @@
from cubicweb._exceptions import *
from logilab.common.registry import ObjectNotFound, NoSelectableObject, RegistryNotFound
+
+# '_' is available to mark internationalized string but should not be used to
+# do the actual translation
+_ = text_type
+if not hasattr(builtins, '_'):
+ builtins._ = deprecated("[3.22] Use 'from cubicweb import _'")(_)
+
+
# convert eid to the right type, raise ValueError if it's not a valid eid
@deprecated('[3.17] typed_eid() was removed. replace it with int() when needed.')
def typed_eid(eid):
@@ -66,17 +72,19 @@
#import threading
#threading.settrace(log_thread)
-class Binary(StringIO):
- """customize StringIO to make sure we don't use unicode"""
- def __init__(self, buf=''):
- assert isinstance(buf, (str, buffer, bytearray)), \
- "Binary objects must use raw strings, not %s" % buf.__class__
- StringIO.__init__(self, buf)
+class Binary(BytesIO):
+ """class to hold binary data. Use BytesIO to prevent use of unicode data"""
+ _allowed_types = (binary_type, bytearray, buffer if PY2 else memoryview)
+
+ def __init__(self, buf=b''):
+ assert isinstance(buf, self._allowed_types), \
+ "Binary objects must use bytes/buffer objects, not %s" % buf.__class__
+ super(Binary, self).__init__(buf)
def write(self, data):
- assert isinstance(data, (str, buffer, bytearray)), \
- "Binary objects must use raw strings, not %s" % data.__class__
- StringIO.write(self, data)
+ assert isinstance(data, self._allowed_types), \
+ "Binary objects must use bytes/buffer objects, not %s" % data.__class__
+ super(Binary, self).write(data)
def to_file(self, fobj):
"""write a binary to disk
@@ -132,22 +140,22 @@
def zpickle(cls, obj):
""" return a Binary containing a gzipped pickle of obj """
retval = cls()
- retval.write(zlib.compress(cPickle.dumps(obj, protocol=2)))
+ retval.write(zlib.compress(pickle.dumps(obj, protocol=2)))
return retval
def unzpickle(self):
""" decompress and loads the stream before returning it """
- return cPickle.loads(zlib.decompress(self.getvalue()))
+ return pickle.loads(zlib.decompress(self.getvalue()))
def check_password(eschema, value):
- return isinstance(value, (str, Binary))
+ return isinstance(value, (binary_type, Binary))
BASE_CHECKERS['Password'] = check_password
def str_or_binary(value):
if isinstance(value, Binary):
return value
- return str(value)
+ return binary_type(value)
BASE_CONVERTERS['Password'] = str_or_binary
@@ -255,4 +263,3 @@
not be processed, a memory allocation error occurred during processing,
etc.
"""
-
--- a/__pkginfo__.py Wed Dec 09 18:42:13 2015 +0100
+++ b/__pkginfo__.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,8 +22,8 @@
modname = distname = "cubicweb"
-numversion = (3, 21, 3)
-version = '.'.join(str(num) for num in numversion)
+numversion = (3, 21, 99)
+version = '.'.join(str(num) for num in numversion) + '.dev0'
description = "a repository of entities / relations for knowledge management"
author = "Logilab"
@@ -39,10 +39,11 @@
]
__depends__ = {
+ 'six': '>= 1.4.0',
'logilab-common': '>= 0.63.1',
'logilab-mtconverter': '>= 0.8.0',
'rql': '>= 0.31.2',
- 'yams': '>= 0.40.0',
+ 'yams': '>= 0.41.1',
#gettext # for xgettext, msgcat, etc...
# web dependencies
'lxml': '',
--- a/_exceptions.py Wed Dec 09 18:42:13 2015 +0100
+++ b/_exceptions.py Thu Dec 10 12:34:15 2015 +0100
@@ -21,6 +21,8 @@
from warnings import warn
+from six import PY3, text_type
+
from logilab.common.decorators import cachedproperty
from yams import ValidationError
@@ -30,23 +32,24 @@
class CubicWebException(Exception):
"""base class for cubicweb server exception"""
msg = ""
- def __str__(self):
+ def __unicode__(self):
if self.msg:
if self.args:
return self.msg % tuple(self.args)
else:
return self.msg
else:
- return u' '.join(unicode(arg) for arg in self.args)
+ return u' '.join(text_type(arg) for arg in self.args)
+ __str__ = __unicode__ if PY3 else lambda self: self.__unicode__().encode('utf-8')
class ConfigurationError(CubicWebException):
"""a misconfiguration error"""
class InternalError(CubicWebException):
- """base class for exceptions which should not occurs"""
+ """base class for exceptions which should not occur"""
class SecurityError(CubicWebException):
- """base class for cubicweb server security exception"""
+ """base class for cubicweb server security exceptions"""
class RepositoryError(CubicWebException):
"""base class for repository exceptions"""
@@ -185,7 +188,7 @@
commit time.
:type txuuix: int
- :param txuuid: Unique identifier of the partialy undone transaction
+ :param txuuid: Unique identifier of the partially undone transaction
:type errors: list
:param errors: List of errors occurred during undoing
@@ -204,4 +207,3 @@
# pylint: disable=W0611
from logilab.common.clcommands import BadCommandUsage
-
--- a/_gcdebug.py Wed Dec 09 18:42:13 2015 +0100
+++ b/_gcdebug.py Thu Dec 10 12:34:15 2015 +0100
@@ -15,6 +15,7 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+from __future__ import print_function
import gc, types, weakref
@@ -68,7 +69,7 @@
except KeyError:
ocounters[key] = 1
if isinstance(obj, viewreferrersclasses):
- print ' ', obj, referrers(obj, showobjs, maxlevel)
+ print(' ', obj, referrers(obj, showobjs, maxlevel))
garbage = [repr(obj) for obj in gc.garbage]
return counters, ocounters, garbage
--- a/crypto.py Wed Dec 09 18:42:13 2015 +0100
+++ b/crypto.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,9 +18,10 @@
"""Simple cryptographic routines, based on python-crypto."""
__docformat__ = "restructuredtext en"
-from pickle import dumps, loads
from base64 import b64encode, b64decode
+from six.moves import cPickle as pickle
+
from Crypto.Cipher import Blowfish
@@ -34,7 +35,7 @@
def encrypt(data, seed):
- string = dumps(data)
+ string = pickle.dumps(data)
string = string + '*' * (8 - len(string) % 8)
string = b64encode(_cypherer(seed).encrypt(string))
return unicode(string)
@@ -43,4 +44,4 @@
def decrypt(string, seed):
# pickle ignores trailing characters so we do not need to strip them off
string = _cypherer(seed).decrypt(b64decode(string))
- return loads(string)
+ return pickle.loads(string)
--- a/cubicweb.spec Wed Dec 09 18:42:13 2015 +0100
+++ b/cubicweb.spec Thu Dec 10 12:34:15 2015 +0100
@@ -20,10 +20,11 @@
BuildArch: noarch
Requires: %{python}
+Requires: %{python}-six >= 1.4.0
Requires: %{python}-logilab-common >= 0.63.1
Requires: %{python}-logilab-mtconverter >= 0.8.0
Requires: %{python}-rql >= 0.31.2
-Requires: %{python}-yams >= 0.40.0
+Requires: %{python}-yams >= 0.41.1
Requires: %{python}-logilab-database >= 1.13.0
Requires: %{python}-passlib
Requires: %{python}-lxml
--- a/cwconfig.py Wed Dec 09 18:42:13 2015 +0100
+++ b/cwconfig.py Thu Dec 10 12:34:15 2015 +0100
@@ -164,9 +164,9 @@
Directory where pid files will be written
"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
-_ = unicode
import sys
import os
@@ -179,6 +179,8 @@
basename, isdir, dirname, splitext)
from warnings import warn, filterwarnings
+from six import text_type
+
from logilab.common.decorators import cached, classproperty
from logilab.common.deprecation import deprecated
from logilab.common.logging_ext import set_log_methods, init_log
@@ -186,7 +188,7 @@
ConfigurationMixIn, merge_options)
from cubicweb import (CW_SOFTWARE_ROOT, CW_MIGRATION_MAP,
- ConfigurationError, Binary)
+ ConfigurationError, Binary, _)
from cubicweb.toolsutils import create_dir
CONFIGURATIONS = []
@@ -350,7 +352,7 @@
}),
('umask',
{'type' : 'int',
- 'default': 077,
+ 'default': 0o077,
'help': 'permission umask for files created by the server',
'group': 'main', 'level': 2,
}),
@@ -503,7 +505,7 @@
deps = {}
else:
deps = dict( (x[len('cubicweb-'):], v)
- for x, v in gendeps.iteritems()
+ for x, v in gendeps.items()
if x.startswith('cubicweb-'))
for depcube in deps:
try:
@@ -650,7 +652,7 @@
self.adjust_sys_path()
self.load_defaults()
# will be properly initialized later by _gettext_init
- self.translations = {'en': (unicode, lambda ctx, msgid: unicode(msgid) )}
+ self.translations = {'en': (text_type, lambda ctx, msgid: text_type(msgid) )}
self._site_loaded = set()
# don't register ReStructured Text directives by simple import, avoid pb
# with eg sphinx.
@@ -960,7 +962,7 @@
i = 1
while exists(path) and i < 100: # arbitrary limit to avoid infinite loop
try:
- file(path, 'a')
+ open(path, 'a')
break
except IOError:
path = '%s-%s.log' % (basepath, i)
@@ -994,6 +996,13 @@
rtdir = abspath(os.environ.get('CW_RUNTIME_DIR', default))
return join(rtdir, '%s-%s.pid' % (self.appid, self.name))
+ # config -> repository
+
+ def repository(self, vreg=None):
+ from cubicweb.server.repository import Repository
+ from cubicweb.server.utils import TasksManager
+ return Repository(self, TasksManager(), vreg=vreg)
+
# instance methods used to get instance specific resources #############
def __init__(self, appid, debugmode=False, creating=False):
@@ -1001,7 +1010,7 @@
# set to true while creating an instance
self.creating = creating
super(CubicWebConfiguration, self).__init__(debugmode)
- fake_gettext = (unicode, lambda ctx, msgid: unicode(msgid))
+ fake_gettext = (text_type, lambda ctx, msgid: text_type(msgid))
for lang in self.available_languages():
self.translations[lang] = fake_gettext
self._cubes = None
@@ -1050,7 +1059,8 @@
def save(self):
"""write down current configuration"""
- self.generate_config(open(self.main_config_file(), 'w'))
+ with open(self.main_config_file(), 'w') as fobj:
+ self.generate_config(fobj)
def check_writeable_uid_directory(self, path):
"""check given directory path exists, belongs to the user running the
@@ -1101,7 +1111,7 @@
version = self.cube_version(pkg)
infos.append('%s-%s' % (pkg, version))
infos.append('cubicweb-%s' % str(self.cubicweb_version()))
- return md5(';'.join(infos)).hexdigest()
+ return md5((';'.join(infos)).encode('ascii')).hexdigest()
def load_configuration(self, **kw):
"""load instance's configuration files"""
@@ -1156,7 +1166,7 @@
def _gettext_init(self):
"""set language for gettext"""
- from cubicweb.gettext import translation
+ from cubicweb.cwgettext import translation
path = join(self.apphome, 'i18n')
for language in self.available_languages():
self.info("loading language %s", language)
@@ -1181,13 +1191,8 @@
def set_sources_mode(self, sources):
if not 'all' in sources:
- print 'warning: ignoring specified sources, requires a repository '\
- 'configuration'
-
- def migration_handler(self):
- """return a migration handler instance"""
- from cubicweb.migration import MigrationHelper
- return MigrationHelper(self, verbosity=self.verbosity)
+ print('warning: ignoring specified sources, requires a repository '
+ 'configuration')
def i18ncompile(self, langs=None):
from cubicweb import i18n
--- a/cwctl.py Wed Dec 09 18:42:13 2015 +0100
+++ b/cwctl.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,6 +18,7 @@
"""the cubicweb-ctl tool, based on logilab.common.clcommands to
provide a pluggable commands system.
"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
@@ -28,7 +29,6 @@
from warnings import warn, filterwarnings
from os import remove, listdir, system, pathsep
from os.path import exists, join, isfile, isdir, dirname, abspath
-from urlparse import urlparse
try:
from os import kill, getpgid
@@ -38,6 +38,8 @@
def getpgid():
"""win32 getpgid implementation"""
+from six.moves.urllib.parse import urlparse
+
from logilab.common.clcommands import CommandLine
from logilab.common.shellutils import ASK
from logilab.common.configuration import merge_options
@@ -113,15 +115,15 @@
_allinstances = list_instances(regdir)
if isfile(join(regdir, 'startorder')):
allinstances = []
- for line in file(join(regdir, 'startorder')):
+ for line in open(join(regdir, 'startorder')):
line = line.strip()
if line and not line.startswith('#'):
try:
_allinstances.remove(line)
allinstances.append(line)
except ValueError:
- print ('ERROR: startorder file contains unexistant '
- 'instance %s' % line)
+ print('ERROR: startorder file contains unexistant '
+ 'instance %s' % line)
allinstances += _allinstances
else:
allinstances = _allinstances
@@ -146,7 +148,7 @@
status = 0
for appid in args:
if askconfirm:
- print '*'*72
+ print('*'*72)
if not ASK.confirm('%s instance %r ?' % (self.name, appid)):
continue
try:
@@ -184,13 +186,13 @@
forkcmd = None
for appid in args:
if askconfirm:
- print '*'*72
+ print('*'*72)
if not ASK.confirm('%s instance %r ?' % (self.name, appid)):
continue
if forkcmd:
status = system('%s %s' % (forkcmd, appid))
if status:
- print '%s exited with status %s' % (forkcmd, status)
+ print('%s exited with status %s' % (forkcmd, status))
else:
self.run_arg(appid)
@@ -224,19 +226,19 @@
from cubicweb.migration import ConfigurationProblem
if mode == 'all':
- print 'CubicWeb %s (%s mode)' % (cwcfg.cubicweb_version(), cwcfg.mode)
- print
+ print('CubicWeb %s (%s mode)' % (cwcfg.cubicweb_version(), cwcfg.mode))
+ print()
if mode in ('all', 'config', 'configurations'):
- print 'Available configurations:'
+ print('Available configurations:')
for config in CONFIGURATIONS:
- print '*', config.name
+ print('*', config.name)
for line in config.__doc__.splitlines():
line = line.strip()
if not line:
continue
- print ' ', line
- print
+ print(' ', line)
+ print()
if mode in ('all', 'cubes'):
cfgpb = ConfigurationProblem(cwcfg)
@@ -244,11 +246,11 @@
cubesdir = pathsep.join(cwcfg.cubes_search_path())
namesize = max(len(x) for x in cwcfg.available_cubes())
except ConfigurationError as ex:
- print 'No cubes available:', ex
+ print('No cubes available:', ex)
except ValueError:
- print 'No cubes available in %s' % cubesdir
+ print('No cubes available in %s' % cubesdir)
else:
- print 'Available cubes (%s):' % cubesdir
+ print('Available cubes (%s):' % cubesdir)
for cube in cwcfg.available_cubes():
try:
tinfo = cwcfg.cube_pkginfo(cube)
@@ -257,59 +259,59 @@
except (ConfigurationError, AttributeError) as ex:
tinfo = None
tversion = '[missing cube information: %s]' % ex
- print '* %s %s' % (cube.ljust(namesize), tversion)
+ print('* %s %s' % (cube.ljust(namesize), tversion))
if self.config.verbose:
if tinfo:
descr = getattr(tinfo, 'description', '')
if not descr:
descr = tinfo.__doc__
if descr:
- print ' '+ ' \n'.join(descr.splitlines())
+ print(' '+ ' \n'.join(descr.splitlines()))
modes = detect_available_modes(cwcfg.cube_dir(cube))
- print ' available modes: %s' % ', '.join(modes)
- print
+ print(' available modes: %s' % ', '.join(modes))
+ print()
if mode in ('all', 'instances'):
try:
regdir = cwcfg.instances_dir()
except ConfigurationError as ex:
- print 'No instance available:', ex
- print
+ print('No instance available:', ex)
+ print()
return
instances = list_instances(regdir)
if instances:
- print 'Available instances (%s):' % regdir
+ print('Available instances (%s):' % regdir)
for appid in instances:
modes = cwcfg.possible_configurations(appid)
if not modes:
- print '* %s (BROKEN instance, no configuration found)' % appid
+ print('* %s (BROKEN instance, no configuration found)' % appid)
continue
- print '* %s (%s)' % (appid, ', '.join(modes))
+ print('* %s (%s)' % (appid, ', '.join(modes)))
try:
config = cwcfg.config_for(appid, modes[0])
except Exception as exc:
- print ' (BROKEN instance, %s)' % exc
+ print(' (BROKEN instance, %s)' % exc)
continue
else:
- print 'No instance available in %s' % regdir
- print
+ print('No instance available in %s' % regdir)
+ print()
if mode == 'all':
# configuration management problem solving
cfgpb.solve()
if cfgpb.warnings:
- print 'Warnings:\n', '\n'.join('* '+txt for txt in cfgpb.warnings)
+ print('Warnings:\n', '\n'.join('* '+txt for txt in cfgpb.warnings))
if cfgpb.errors:
- print 'Errors:'
+ print('Errors:')
for op, cube, version, src in cfgpb.errors:
if op == 'add':
- print '* cube', cube,
+ print('* cube', cube, end=' ')
if version:
- print ' version', version,
- print 'is not installed, but required by %s' % src
+ print(' version', version, end=' ')
+ print('is not installed, but required by %s' % src)
else:
- print '* cube %s version %s is installed, but version %s is required by %s' % (
- cube, cfgpb.cubes[cube], version, src)
+ print('* cube %s version %s is installed, but version %s is required by %s' % (
+ cube, cfgpb.cubes[cube], version, src))
def check_options_consistency(config):
if config.automatic and config.config_level > 0:
@@ -380,20 +382,20 @@
templdirs = [cwcfg.cube_dir(cube)
for cube in cubes]
except ConfigurationError as ex:
- print ex
- print '\navailable cubes:',
- print ', '.join(cwcfg.available_cubes())
+ print(ex)
+ print('\navailable cubes:', end=' ')
+ print(', '.join(cwcfg.available_cubes()))
return
# create the registry directory for this instance
- print '\n'+underline_title('Creating the instance %s' % appid)
+ print('\n'+underline_title('Creating the instance %s' % appid))
create_dir(config.apphome)
# cubicweb-ctl configuration
if not self.config.automatic:
- print '\n'+underline_title('Configuring the instance (%s.conf)'
- % configname)
+ print('\n'+underline_title('Configuring the instance (%s.conf)'
+ % configname))
config.input_config('main', self.config.config_level)
# configuration'specific stuff
- print
+ print()
helper.bootstrap(cubes, self.config.automatic, self.config.config_level)
# input for cubes specific options
if not self.config.automatic:
@@ -402,23 +404,23 @@
and odict.get('level') <= self.config.config_level)
for section in sections:
if section not in ('main', 'email', 'web'):
- print '\n' + underline_title('%s options' % section)
+ print('\n' + underline_title('%s options' % section))
config.input_config(section, self.config.config_level)
# write down configuration
config.save()
self._handle_win32(config, appid)
- print '-> generated config %s' % config.main_config_file()
+ print('-> generated config %s' % config.main_config_file())
# handle i18n files structure
# in the first cube given
from cubicweb import i18n
langs = [lang for lang, _ in i18n.available_catalogs(join(templdirs[0], 'i18n'))]
errors = config.i18ncompile(langs)
if errors:
- print '\n'.join(errors)
+ print('\n'.join(errors))
if self.config.automatic \
or not ASK.confirm('error while compiling message catalogs, '
'continue anyway ?'):
- print 'creation not completed'
+ print('creation not completed')
return
# create the additional data directory for this instance
if config.appdatahome != config.apphome: # true in dev mode
@@ -427,9 +429,9 @@
if config['uid']:
from logilab.common.shellutils import chown
# this directory should be owned by the uid of the server process
- print 'set %s as owner of the data directory' % config['uid']
+ print('set %s as owner of the data directory' % config['uid'])
chown(config.appdatahome, config['uid'])
- print '\n-> creation done for %s\n' % repr(config.apphome)[1:-1]
+ print('\n-> creation done for %s\n' % repr(config.apphome)[1:-1])
if not self.config.no_db_create:
helper.postcreate(self.config.automatic, self.config.config_level)
@@ -487,7 +489,7 @@
if ex.errno != errno.ENOENT:
raise
confignames = ', '.join([config.name for config in configs])
- print '-> instance %s (%s) deleted.' % (appid, confignames)
+ print('-> instance %s (%s) deleted.' % (appid, confignames))
# instance commands ########################################################
@@ -551,7 +553,7 @@
the --force option."
raise ExecutionError(msg % (appid, pidf))
if helper.start_server(config) == 1:
- print 'instance %s started' % appid
+ print('instance %s started' % appid)
def init_cmdline_log_threshold(config, loglevel):
@@ -606,7 +608,7 @@
except OSError:
# already removed by twistd
pass
- print 'instance %s stopped' % appid
+ print('instance %s stopped' % appid)
class RestartInstanceCommand(StartInstanceCommand):
@@ -630,7 +632,7 @@
# get instances in startorder
for appid in args:
if askconfirm:
- print '*'*72
+ print('*'*72)
if not ASK.confirm('%s instance %r ?' % (self.name, appid)):
continue
StopInstanceCommand(self.logger).stop_instance(appid)
@@ -677,14 +679,14 @@
status = 0
for mode in cwcfg.possible_configurations(appid):
config = cwcfg.config_for(appid, mode)
- print '[%s-%s]' % (appid, mode),
+ print('[%s-%s]' % (appid, mode), end=' ')
try:
pidf = config['pid-file']
except KeyError:
- print 'buggy instance, pid file not specified'
+ print('buggy instance, pid file not specified')
continue
if not exists(pidf):
- print "doesn't seem to be running"
+ print("doesn't seem to be running")
status = 1
continue
pid = int(open(pidf).read().strip())
@@ -692,10 +694,10 @@
try:
getpgid(pid)
except OSError:
- print "should be running with pid %s but the process can not be found" % pid
+ print("should be running with pid %s but the process can not be found" % pid)
status = 1
continue
- print "running with pid %s" % (pid)
+ print("running with pid %s" % (pid))
return status
class UpgradeInstanceCommand(InstanceCommandFork):
@@ -756,7 +758,7 @@
)
def upgrade_instance(self, appid):
- print '\n' + underline_title('Upgrading the instance %s' % appid)
+ print('\n' + underline_title('Upgrading the instance %s' % appid))
from logilab.common.changelog import Version
config = cwcfg.config_for(appid)
instance_running = exists(config['pid-file'])
@@ -767,11 +769,11 @@
set_sources_mode(self.config.ext_sources or ('migration',))
# get instance and installed versions for the server and the componants
mih = config.migration_handler()
- repo = mih.repo_connect()
+ repo = mih.repo
vcconf = repo.get_versions()
helper = self.config_helper(config, required=False)
if self.config.force_cube_version:
- for cube, version in self.config.force_cube_version.iteritems():
+ for cube, version in self.config.force_cube_version.items():
vcconf[cube] = Version(version)
toupgrade = []
for cube in config.cubes():
@@ -797,30 +799,30 @@
# run cubicweb/componants migration scripts
if self.config.fs_only or toupgrade:
for cube, fromversion, toversion in toupgrade:
- print '-> migration needed from %s to %s for %s' % (fromversion, toversion, cube)
+ print('-> migration needed from %s to %s for %s' % (fromversion, toversion, cube))
with mih.cnx:
with mih.cnx.security_enabled(False, False):
mih.migrate(vcconf, reversed(toupgrade), self.config)
else:
- print '-> no data migration needed for instance %s.' % appid
+ print('-> no data migration needed for instance %s.' % appid)
# rewrite main configuration file
mih.rewrite_configuration()
mih.shutdown()
# handle i18n upgrade
if not self.i18nupgrade(config):
return
- print
+ print()
if helper:
helper.postupgrade(repo)
- print '-> instance migrated.'
+ print('-> instance migrated.')
if instance_running and not (CWDEV or self.config.nostartstop):
# restart instance through fork to get a proper environment, avoid
# uicfg pb (and probably gettext catalogs, to check...)
forkcmd = '%s start %s' % (sys.argv[0], appid)
status = system(forkcmd)
if status:
- print '%s exited with status %s' % (forkcmd, status)
- print
+ print('%s exited with status %s' % (forkcmd, status))
+ print()
def i18nupgrade(self, config):
# handle i18n upgrade:
@@ -832,10 +834,10 @@
langs = [lang for lang, _ in i18n.available_catalogs(join(templdir, 'i18n'))]
errors = config.i18ncompile(langs)
if errors:
- print '\n'.join(errors)
+ print('\n'.join(errors))
if not ASK.confirm('Error while compiling message catalogs, '
'continue anyway?'):
- print '-> migration not completed.'
+ print('-> migration not completed.')
return False
return True
@@ -856,10 +858,9 @@
config.quick_start = True
if hasattr(config, 'set_sources_mode'):
config.set_sources_mode(('migration',))
- repo = config.migration_handler().repo_connect()
- vcconf = repo.get_versions()
+ vcconf = config.repository().get_versions()
for key in sorted(vcconf):
- print key+': %s.%s.%s' % vcconf[key]
+ print(key+': %s.%s.%s' % vcconf[key])
class ShellCommand(Command):
"""Run an interactive migration shell on an instance. This is a python shell
@@ -940,9 +941,9 @@
repo = get_repository(appuri)
cnx = connect(repo, login=login, password=pwd, mulcnx=False)
except AuthenticationError as ex:
- print ex
+ print(ex)
except (KeyboardInterrupt, EOFError):
- print
+ print()
sys.exit(0)
else:
break
@@ -1003,7 +1004,7 @@
config.init_cubes(repo.get_cubes())
errors = config.i18ncompile()
if errors:
- print '\n'.join(errors)
+ print('\n'.join(errors))
class ListInstancesCommand(Command):
@@ -1015,7 +1016,7 @@
"""run the command with its specific arguments"""
regdir = cwcfg.instances_dir()
for appid in sorted(listdir(regdir)):
- print appid
+ print(appid)
class ListCubesCommand(Command):
@@ -1026,7 +1027,7 @@
def run(self, args):
"""run the command with its specific arguments"""
for cube in cwcfg.available_cubes():
- print cube
+ print(cube)
class ConfigureInstanceCommand(InstanceCommand):
"""Configure instance.
@@ -1048,7 +1049,7 @@
def configure_instance(self, appid):
if self.config.param is not None:
appcfg = cwcfg.config_for(appid)
- for key, value in self.config.param.iteritems():
+ for key, value in self.config.param.items():
try:
appcfg.global_set_option(key, value)
except KeyError:
@@ -1138,17 +1139,15 @@
def run(args):
"""command line tool"""
import os
- sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
- sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 0)
filterwarnings('default', category=DeprecationWarning)
cwcfg.load_cwctl_plugins()
try:
CWCTL.run(args)
except ConfigurationError as err:
- print 'ERROR: ', err
+ print('ERROR: ', err)
sys.exit(1)
except ExecutionError as err:
- print err
+ print(err)
sys.exit(2)
if __name__ == '__main__':
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cwgettext.py Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,118 @@
+# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+
+import gettext
+
+
+class cwGNUTranslations(gettext.GNUTranslations):
+ # The encoding of a msgctxt and a msgid in a .mo file is
+ # msgctxt + "\x04" + msgid (gettext version >= 0.15)
+ CONTEXT_ENCODING = "%s\x04%s"
+
+ def pgettext(self, context, message):
+ ctxt_msg_id = self.CONTEXT_ENCODING % (context, message)
+ missing = object()
+ tmsg = self._catalog.get(ctxt_msg_id, missing)
+ if tmsg is missing:
+ if self._fallback:
+ return self._fallback.pgettext(context, message)
+ return message
+ # Encode the Unicode tmsg back to an 8-bit string, if possible
+ if self._output_charset:
+ return tmsg.encode(self._output_charset)
+ elif self._charset:
+ return tmsg.encode(self._charset)
+ return tmsg
+
+ def lpgettext(self, context, message):
+ ctxt_msg_id = self.CONTEXT_ENCODING % (context, message)
+ missing = object()
+ tmsg = self._catalog.get(ctxt_msg_id, missing)
+ if tmsg is missing:
+ if self._fallback:
+ return self._fallback.lpgettext(context, message)
+ return message
+ if self._output_charset:
+ return tmsg.encode(self._output_charset)
+ return tmsg.encode(locale.getpreferredencoding())
+
+ def npgettext(self, context, msgid1, msgid2, n):
+ ctxt_msg_id = self.CONTEXT_ENCODING % (context, msgid1)
+ try:
+ tmsg = self._catalog[(ctxt_msg_id, self.plural(n))]
+ if self._output_charset:
+ return tmsg.encode(self._output_charset)
+ elif self._charset:
+ return tmsg.encode(self._charset)
+ return tmsg
+ except KeyError:
+ if self._fallback:
+ return self._fallback.npgettext(context, msgid1, msgid2, n)
+ if n == 1:
+ return msgid1
+ else:
+ return msgid2
+
+ def lnpgettext(self, context, msgid1, msgid2, n):
+ ctxt_msg_id = self.CONTEXT_ENCODING % (context, msgid1)
+ try:
+ tmsg = self._catalog[(ctxt_msg_id, self.plural(n))]
+ if self._output_charset:
+ return tmsg.encode(self._output_charset)
+ return tmsg.encode(locale.getpreferredencoding())
+ except KeyError:
+ if self._fallback:
+ return self._fallback.lnpgettext(context, msgid1, msgid2, n)
+ if n == 1:
+ return msgid1
+ else:
+ return msgid2
+
+ def upgettext(self, context, message):
+ ctxt_message_id = self.CONTEXT_ENCODING % (context, message)
+ missing = object()
+ tmsg = self._catalog.get(ctxt_message_id, missing)
+ if tmsg is missing:
+ # XXX logilab patch for compat w/ catalog generated by cw < 3.5
+ return self.ugettext(message)
+ if self._fallback:
+ return self._fallback.upgettext(context, message)
+ return unicode(message)
+ return tmsg
+
+ def unpgettext(self, context, msgid1, msgid2, n):
+ ctxt_message_id = self.CONTEXT_ENCODING % (context, msgid1)
+ try:
+ tmsg = self._catalog[(ctxt_message_id, self.plural(n))]
+ except KeyError:
+ if self._fallback:
+ return self._fallback.unpgettext(context, msgid1, msgid2, n)
+ if n == 1:
+ tmsg = unicode(msgid1)
+ else:
+ tmsg = unicode(msgid2)
+ return tmsg
+
+
+def translation(domain, localedir=None, languages=None,
+ class_=None, fallback=False, codeset=None):
+ if class_ is None:
+ class_ = cwGNUTranslations
+ return gettext.translation(domain, localedir=localedir,
+ languages=languages, class_=class_,
+ fallback=fallback, codeset=codeset)
--- a/cwvreg.py Wed Dec 09 18:42:13 2015 +0100
+++ b/cwvreg.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,7 +20,7 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
import sys
from os.path import join, dirname, realpath
@@ -28,6 +28,8 @@
from datetime import datetime, date, time, timedelta
from functools import reduce
+from six import text_type, binary_type
+
from logilab.common.decorators import cached, clear_cache
from logilab.common.deprecation import deprecated, class_deprecated
from logilab.common.modutils import cleanup_sys_modules
@@ -221,9 +223,9 @@
"""
obj = self.select(oid, req, rset=rset, **kwargs)
res = obj.render(**kwargs)
- if isinstance(res, unicode):
+ if isinstance(res, text_type):
return res.encode(req.encoding)
- assert isinstance(res, str)
+ assert isinstance(res, binary_type)
return res
def possible_views(self, req, rset=None, **kwargs):
@@ -382,7 +384,7 @@
return [item for item in super(CWRegistryStore, self).items()
if not item[0] in ('propertydefs', 'propertyvalues')]
def iteritems(self):
- return (item for item in super(CWRegistryStore, self).iteritems()
+ return (item for item in super(CWRegistryStore, self).items()
if not item[0] in ('propertydefs', 'propertyvalues'))
def values(self):
@@ -492,7 +494,7 @@
"""
self.schema = schema
for registry, regcontent in self.items():
- for objects in regcontent.itervalues():
+ for objects in regcontent.values():
for obj in objects:
obj.schema = schema
@@ -543,7 +545,7 @@
self.unregister(obj)
super(CWRegistryStore, self).initialization_completed()
if 'uicfg' in self: # 'uicfg' is not loaded in a pure repository mode
- for rtags in self['uicfg'].itervalues():
+ for rtags in self['uicfg'].values():
for rtag in rtags:
# don't check rtags if we don't want to cleanup_unused_appobjects
rtag.init(self.schema, check=self.config.cleanup_unused_appobjects)
@@ -576,7 +578,7 @@
if withsitewide:
return sorted(k for k in self['propertydefs']
if not k.startswith('sources.'))
- return sorted(k for k, kd in self['propertydefs'].iteritems()
+ return sorted(k for k, kd in self['propertydefs'].items()
if not kd['sitewide'] and not k.startswith('sources.'))
def register_property(self, key, type, help, default=None, vocabulary=None,
@@ -653,4 +655,3 @@
'TZTime': time,
'Interval': timedelta,
})
-
--- a/dataimport/csv.py Wed Dec 09 18:42:13 2015 +0100
+++ b/dataimport/csv.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,18 +16,20 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""Functions to help importing CSV data"""
+from __future__ import absolute_import, print_function
-from __future__ import absolute_import
-
+import codecs
import csv as csvmod
import warnings
import os.path as osp
+from six import PY2, PY3, string_types
+
from logilab.common import shellutils
def count_lines(stream_or_filename):
- if isinstance(stream_or_filename, basestring):
+ if isinstance(stream_or_filename, string_types):
f = open(stream_or_filename)
else:
f = stream_or_filename
@@ -48,10 +50,8 @@
if quote is not None:
quotechar = quote
warnings.warn("[3.20] 'quote' kwarg is deprecated, use 'quotechar' instead")
- if isinstance(stream_or_path, basestring):
- if not osp.exists(stream_or_path):
- raise Exception("file doesn't exists: %s" % stream_or_path)
- stream = open(stream_or_path)
+ if isinstance(stream_or_path, string_types):
+ stream = open(stream_or_path, 'rb')
else:
stream = stream_or_path
rowcount = count_lines(stream)
@@ -64,7 +64,7 @@
yield urow
if withpb:
pb.update()
- print ' %s rows imported' % rowcount
+ print(' %s rows imported' % rowcount)
def ucsvreader(stream, encoding='utf-8', delimiter=',', quotechar='"',
@@ -77,6 +77,8 @@
separators) will be skipped. This is useful for Excel exports which may be
full of such lines.
"""
+ if PY3:
+ stream = codecs.getreader(encoding)(stream)
if separator is not None:
delimiter = separator
warnings.warn("[3.20] 'separator' kwarg is deprecated, use 'delimiter' instead")
@@ -86,28 +88,33 @@
it = iter(csvmod.reader(stream, delimiter=delimiter, quotechar=quotechar))
if not ignore_errors:
if skipfirst:
- it.next()
+ next(it)
for row in it:
- decoded = [item.decode(encoding) for item in row]
+ if PY2:
+ decoded = [item.decode(encoding) for item in row]
+ else:
+ decoded = row
if not skip_empty or any(decoded):
yield decoded
else:
if skipfirst:
try:
- row = it.next()
+ row = next(it)
except csvmod.Error:
pass
# Safe version, that can cope with error in CSV file
while True:
try:
- row = it.next()
+ row = next(it)
# End of CSV, break
except StopIteration:
break
# Error in CSV, ignore line and continue
except csvmod.Error:
continue
- decoded = [item.decode(encoding) for item in row]
+ if PY2:
+ decoded = [item.decode(encoding) for item in row]
+ else:
+ decoded = row
if not skip_empty or any(decoded):
yield decoded
-
--- a/dataimport/deprecated.py Wed Dec 09 18:42:13 2015 +0100
+++ b/dataimport/deprecated.py Thu Dec 10 12:34:15 2015 +0100
@@ -58,10 +58,13 @@
.. BUG file with one column are not parsable
.. TODO rollback() invocation is not possible yet
"""
+from __future__ import print_function
import sys
import traceback
-from StringIO import StringIO
+from io import StringIO
+
+from six import add_metaclass
from logilab.common import attrdict, shellutils
from logilab.common.date import strptime
@@ -78,7 +81,7 @@
>>> data = lazytable(ucsvreader(open(filename)))
"""
- header = reader.next()
+ header = next(reader)
for row in reader:
yield dict(zip(header, row))
@@ -103,7 +106,7 @@
@deprecated('[3.21] deprecated')
def tell(msg):
- print msg
+ print(msg)
@deprecated('[3.21] deprecated')
@@ -115,9 +118,9 @@
return answer == 'Y'
+@add_metaclass(class_deprecated)
class catch_error(object):
"""Helper for @contextmanager decorator."""
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.21] deprecated'
def __init__(self, ctl, key='unexpected error', msg=None):
@@ -166,7 +169,9 @@
if res[dest] is None:
break
except ValueError as err:
- raise ValueError('error with %r field: %s' % (src, err)), None, sys.exc_info()[-1]
+ exc = ValueError('error with %r field: %s' % (src, err))
+ exc.__traceback__ = sys.exc_info()[-1]
+ raise exc
return res
@@ -254,6 +259,7 @@
if k is not None and len(v) > 1]
+@add_metaclass(class_deprecated)
class ObjectStore(object):
"""Store objects in memory for *faster* validation (development mode)
@@ -264,7 +270,6 @@
>>> group = store.prepare_insert_entity('CWUser', name=u'unknown')
>>> store.prepare_insert_relation(user, 'in_group', group)
"""
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.21] use the new importer API'
def __init__(self):
@@ -289,7 +294,7 @@
"""Given an entity type and eid, updates the corresponding fake entity with specified
attributes and inlined relations.
"""
- assert eid in self.types[etype], 'Trying to update with wrong type {}'.format(etype)
+ assert eid in self.types[etype], 'Trying to update with wrong type %s' % etype
data = self.eids[eid]
data.update(kwargs)
@@ -335,6 +340,7 @@
self.prepare_insert_relation(eid_from, rtype, eid_to, **kwargs)
+@add_metaclass(class_deprecated)
class CWImportController(object):
"""Controller of the data import process.
@@ -343,7 +349,6 @@
>>> ctl.data = dict_of_data_tables
>>> ctl.run()
"""
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.21] use the new importer API'
def __init__(self, store, askerror=0, catcherrors=None, tell=tell,
@@ -421,7 +426,7 @@
self.tell(pformat(sorted(error[1])))
def _print_stats(self):
- nberrors = sum(len(err) for err in self.errors.itervalues())
+ nberrors = sum(len(err) for err in self.errors.values())
self.tell('\nImport statistics: %i entities, %i types, %i relations and %i errors'
% (self.store.nb_inserted_entities,
self.store.nb_inserted_types,
@@ -456,5 +461,3 @@
return callfunc_every(self.store.commit,
self.commitevery,
self.get_data(datakey))
-
-
--- a/dataimport/importer.py Wed Dec 09 18:42:13 2015 +0100
+++ b/dataimport/importer.py Thu Dec 10 12:34:15 2015 +0100
@@ -69,7 +69,7 @@
def use_extid_as_cwuri_filter(extentities):
for extentity in extentities:
if extentity.extid not in extid2eid:
- extentity.values.setdefault('cwuri', set([unicode(extentity.extid)]))
+ extentity.values.setdefault('cwuri', set([extentity.extid.decode('utf-8')]))
yield extentity
return use_extid_as_cwuri_filter
@@ -83,15 +83,15 @@
def __init__(self, cnx, source=None):
self.cnx = cnx
- self._rql_template = 'Any S,O WHERE S {} O'
+ self._rql_template = 'Any S,O WHERE S %s O'
self._kwargs = {}
if source is not None:
- self._rql_template += ', S cw_source SO, O cw_source SO, SO eid %(s)s'
+ self._rql_template += ', S cw_source SO, O cw_source SO, SO eid %%(s)s'
self._kwargs['s'] = source.eid
def __getitem__(self, rtype):
"""Return a set of (subject, object) eids already related by `rtype`"""
- rql = self._rql_template.format(rtype)
+ rql = self._rql_template % rtype
return set(tuple(x) for x in self.cnx.execute(rql, self._kwargs))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dataimport/massive_store.py Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,742 @@
+# coding: utf-8
+# copyright 2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+
+import logging
+from datetime import datetime
+from collections import defaultdict
+from io import StringIO
+
+from six.moves import range
+
+from yams.constraints import SizeConstraint
+
+from psycopg2 import ProgrammingError
+
+from cubicweb.dataimport import stores, pgstore
+from cubicweb.utils import make_uid
+from cubicweb.server.sqlutils import SQL_PREFIX
+
+
+class MassiveObjectStore(stores.RQLObjectStore):
+ """
+ Store for massive import of data, with delayed insertion of meta data.
+
+ WARNINGS:
+ - This store may be only used with PostgreSQL for now, as it relies
+ on the COPY FROM method, and on specific PostgreSQL tables to get all
+ the indexes.
+ - This store can only insert relations that are not inlined (i.e.,
+ which do *not* have inlined=True in their definition in the schema).
+
+ It should be used as follows:
+
+ store = MassiveObjectStore(cnx)
+ store.init_rtype_table('Person', 'lives_in', 'Location')
+ ...
+
+ store.prepare_insert_entity('Person', subj_iid_attribute=person_iid, ...)
+ store.prepare_insert_entity('Location', obj_iid_attribute=location_iid, ...)
+ ...
+
+ # subj_iid_attribute and obj_iid_attribute are argument names
+ # chosen by the user (e.g. "cwuri"). These names can be identical.
+ # person_iid and location_iid are unique IDs and depend on the data
+ # (e.g URI).
+ store.flush()
+ store.relate_by_iid(person_iid, 'lives_in', location_iid)
+ # For example:
+ store.prepare_insert_entity('Person',
+ cwuri='http://dbpedia.org/toto',
+ name='Toto')
+ store.prepare_insert_entity('Location',
+ uri='http://geonames.org/11111',
+ name='Somewhere')
+ store.flush()
+ store.relate_by_iid('http://dbpedia.org/toto',
+ 'lives_in',
+ 'http://geonames.org/11111')
+ # Finally
+ store.convert_relations('Person', 'lives_in', 'Location',
+ 'subj_iid_attribute', 'obj_iid_attribute')
+ # For the previous example:
+ store.convert_relations('Person', 'lives_in', 'Location', 'cwuri', 'uri')
+ ...
+ store.commit()
+ store.finish()
+ """
+ # size of eid range reserved by the store for each batch
+ eids_seq_range = 10000
+ # initial eid (None means use the value in the db)
+ eids_seq_start = None
+ # max size of the iid, used to create the iid_eid conversion table
+ iid_maxsize = 1024
+
+ def __init__(self, cnx,
+ on_commit_callback=None, on_rollback_callback=None,
+ slave_mode=False,
+ source=None):
+ """ Create a MassiveObject store, with the following attributes:
+
+ - cnx: CubicWeb cnx
+ """
+ super(MassiveObjectStore, self).__init__(cnx)
+ self.logger = logging.getLogger('dataimport.massive_store')
+ self._cnx = cnx
+ self.sql = cnx.system_sql
+ self._data_uri_relations = defaultdict(list)
+
+ # etypes for which we have a uri_eid_%(etype)s table
+ self._init_uri_eid = set()
+ # etypes for which we have a uri_eid_%(e)s_idx index
+ self._uri_eid_inserted = set()
+ # set of rtypes for which we have a %(rtype)s_relation_iid_tmp table
+ self._uri_rtypes = set()
+ # set of etypes whose tables are created
+ self._entities = set()
+ # set of rtypes for which we have a %(rtype)s_relation_tmp table
+ self._rtypes = set()
+
+ self.slave_mode = slave_mode
+ self.default_values = get_default_values(cnx.vreg.schema)
+ pg_schema = cnx.repo.config.system_source_config.get('db-namespace') or 'public'
+ self._dbh = PGHelper(self._cnx, pg_schema)
+ self._data_entities = defaultdict(list)
+ self._data_relations = defaultdict(list)
+ self._now = datetime.now()
+ self._default_cwuri = make_uid('_auto_generated')
+ self._count_cwuri = 0
+ self.on_commit_callback = on_commit_callback
+ self.on_rollback_callback = on_rollback_callback
+ # Do our meta tables already exist?
+ self._init_massive_metatables()
+ # Internal markers of initialization
+ if self.eids_seq_start is not None and not self.slave_mode:
+ self._cnx.system_sql(self._cnx.repo.system_source.dbhelper.sql_restart_numrange(
+ 'entities_id_seq', initial_value=self.eids_seq_start + 1))
+ cnx.commit()
+ self.get_next_eid = lambda g=self._get_eid_gen(): next(g)
+ # recreate then when self.finish() is called
+ if not self.slave_mode:
+ self._drop_metatables_constraints()
+ if source is None:
+ source = cnx.repo.system_source
+ self.source = source
+ self._etype_eid_idx = dict(cnx.execute('Any XN,X WHERE X is CWEType, X name XN'))
+ cnx.read_security = False
+ cnx.write_security = False
+
+ ### INIT FUNCTIONS ########################################################
+
+ def init_rtype_table(self, etype_from, rtype, etype_to):
+ """ Build temporary table for standard rtype """
+ # Create an uri_eid table for each etype for a better
+ # control of which etype is concerned by a particular
+ # possibly multivalued relation.
+ for etype in (etype_from, etype_to):
+ if etype and etype not in self._init_uri_eid:
+ self._init_uri_eid_table(etype)
+ if rtype not in self._uri_rtypes:
+ # Create the temporary table
+ if not self._cnx.repo.schema.rschema(rtype).inlined:
+ try:
+ sql = 'CREATE TABLE %(r)s_relation_iid_tmp (uri_from character ' \
+ 'varying(%(s)s), uri_to character varying(%(s)s))'
+ self.sql(sql % {'r': rtype, 's': self.iid_maxsize})
+ except ProgrammingError:
+ # XXX Already exist (probably due to multiple import)
+ pass
+ else:
+ self.logger.warning("inlined relation %s: cannot insert it", rtype)
+ # Add it to the initialized set
+ self._uri_rtypes.add(rtype)
+
+ def _init_uri_eid_table(self, etype):
+ """ Build a temporary table for id/eid convertion
+ """
+ try:
+ sql = "CREATE TABLE uri_eid_%(e)s (uri character varying(%(size)s), eid integer)"
+ self.sql(sql % {'e': etype.lower(), 'size': self.iid_maxsize,})
+ except ProgrammingError:
+ # XXX Already exist (probably due to multiple import)
+ pass
+ # Add it to the initialized set
+ self._init_uri_eid.add(etype)
+
+ def _init_massive_metatables(self):
+ # Check if our tables are not already created (i.e. a restart)
+ self._initialized_table_created = self._dbh.table_exists('cwmassive_initialized')
+ self._constraint_table_created = self._dbh.table_exists('cwmassive_constraints')
+ self._metadata_table_created = self._dbh.table_exists('cwmassive_metadata')
+
+ ### RELATE FUNCTION #######################################################
+
+ def relate_by_iid(self, iid_from, rtype, iid_to):
+ """Add new relation based on the internal id (iid)
+ of the entities (not the eid)"""
+ # Push data
+ if isinstance(iid_from, unicode):
+ iid_from = iid_from.encode('utf-8')
+ if isinstance(iid_to, unicode):
+ iid_to = iid_to.encode('utf-8')
+ self._data_uri_relations[rtype].append({'uri_from': iid_from, 'uri_to': iid_to})
+
+ ### FLUSH FUNCTIONS #######################################################
+
+ def flush_relations(self):
+ """ Flush the relations data
+ """
+ for rtype, data in self._data_uri_relations.items():
+ if not data:
+ self.logger.info('No data for rtype %s', rtype)
+ buf = StringIO('\n'.join(['%(uri_from)s\t%(uri_to)s' % d for d in data]))
+ if not buf:
+ self.logger.info('Empty Buffer for rtype %s', rtype)
+ continue
+ cursor = self._cnx.cnxset.cu
+ if not self._cnx.repo.schema.rschema(rtype).inlined:
+ cursor.copy_from(buf, '%s_relation_iid_tmp' % rtype.lower(),
+ null='NULL', columns=('uri_from', 'uri_to'))
+ else:
+ self.logger.warning("inlined relation %s: cannot insert it", rtype)
+ buf.close()
+ # Clear data cache
+ self._data_uri_relations[rtype] = []
+
+ def fill_uri_eid_table(self, etype, uri_label):
+ """ Fill the uri_eid table
+ """
+ self.logger.info('Fill uri_eid for etype %s', etype)
+ sql = 'INSERT INTO uri_eid_%(e)s SELECT cw_%(l)s, cw_eid FROM cw_%(e)s'
+ self.sql(sql % {'l': uri_label, 'e': etype.lower()})
+ # Add indexes
+ self.sql('CREATE INDEX uri_eid_%(e)s_idx ON uri_eid_%(e)s' '(uri)' % {'e': etype.lower()})
+ # Set the etype as converted
+ self._uri_eid_inserted.add(etype)
+
+ def convert_relations(self, etype_from, rtype, etype_to,
+ uri_label_from='cwuri', uri_label_to='cwuri'):
+ """ Flush the converted relations
+ """
+ # Always flush relations to be sure
+ self.logger.info('Convert relations %s %s %s', etype_from, rtype, etype_to)
+ self.flush_relations()
+ if uri_label_from and etype_from not in self._uri_eid_inserted:
+ self.fill_uri_eid_table(etype_from, uri_label_from)
+ if uri_label_to and etype_to not in self._uri_eid_inserted:
+ self.fill_uri_eid_table(etype_to, uri_label_to)
+ if self._cnx.repo.schema.rschema(rtype).inlined:
+ self.logger.warning("Can't insert inlined relation %s", rtype)
+ return
+ if uri_label_from and uri_label_to:
+ sql = '''INSERT INTO %(r)s_relation (eid_from, eid_to) SELECT DISTINCT O1.eid, O2.eid
+ FROM %(r)s_relation_iid_tmp AS T, uri_eid_%(ef)s as O1, uri_eid_%(et)s as O2
+ WHERE O1.uri=T.uri_from AND O2.uri=T.uri_to AND NOT EXISTS (
+ SELECT 1 FROM %(r)s_relation AS TT WHERE TT.eid_from=O1.eid AND TT.eid_to=O2.eid);
+ '''
+ elif uri_label_to:
+ sql = '''INSERT INTO %(r)s_relation (eid_from, eid_to) SELECT DISTINCT
+ CAST(T.uri_from AS INTEGER), O1.eid
+ FROM %(r)s_relation_iid_tmp AS T, uri_eid_%(et)s as O1
+ WHERE O1.uri=T.uri_to AND NOT EXISTS (
+ SELECT 1 FROM %(r)s_relation AS TT WHERE
+ TT.eid_from=CAST(T.uri_from AS INTEGER) AND TT.eid_to=O1.eid);
+ '''
+ elif uri_label_from:
+ sql = '''INSERT INTO %(r)s_relation (eid_from, eid_to) SELECT DISTINCT O1.eid, T.uri_to
+ O1.eid, CAST(T.uri_to AS INTEGER)
+ FROM %(r)s_relation_iid_tmp AS T, uri_eid_%(ef)s as O1
+ WHERE O1.uri=T.uri_from AND NOT EXISTS (
+ SELECT 1 FROM %(r)s_relation AS TT WHERE
+ TT.eid_from=O1.eid AND TT.eid_to=CAST(T.uri_to AS INTEGER));
+ '''
+ try:
+ self.sql(sql % {'r': rtype.lower(),
+ 'et': etype_to.lower() if etype_to else u'',
+ 'ef': etype_from.lower() if etype_from else u''})
+ except Exception as ex:
+ self.logger.error("Can't insert relation %s: %s", rtype, ex)
+
+ ### SQL UTILITIES #########################################################
+
+ def drop_and_store_indexes_constraints(self, tablename):
+ # Drop indexes and constraints
+ if not self._constraint_table_created:
+ # Create a table to save the constraints
+ # Allow reload even after crash
+ sql = "CREATE TABLE cwmassive_constraints (origtable text, query text, type varchar(256))"
+ self.sql(sql)
+ self._constraint_table_created = True
+ self._drop_table_constraints_indexes(tablename)
+
+ def _drop_table_constraints_indexes(self, tablename):
+ """ Drop and store table constraints and indexes """
+ indexes, constraints = self._dbh.application_indexes_constraints(tablename)
+ for name, query in constraints.items():
+ sql = 'INSERT INTO cwmassive_constraints VALUES (%(e)s, %(c)s, %(t)s)'
+ self.sql(sql, {'e': tablename, 'c': query, 't': 'constraint'})
+ sql = 'ALTER TABLE %s DROP CONSTRAINT %s CASCADE' % (tablename, name)
+ self.sql(sql)
+ for name, query in indexes.items():
+ sql = 'INSERT INTO cwmassive_constraints VALUES (%(e)s, %(c)s, %(t)s)'
+ self.sql(sql, {'e': tablename, 'c': query, 't': 'index'})
+ sql = 'DROP INDEX %s' % name
+ self.sql(sql)
+
+ def reapply_constraint_index(self, tablename):
+ if not self._dbh.table_exists('cwmassive_constraints'):
+ self.logger.info('The table cwmassive_constraints does not exist')
+ return
+ sql = 'SELECT query FROM cwmassive_constraints WHERE origtable = %(e)s'
+ crs = self.sql(sql, {'e': tablename})
+ for query, in crs.fetchall():
+ self.sql(query)
+ self.sql('DELETE FROM cwmassive_constraints WHERE origtable = %(e)s '
+ 'AND query = %(q)s', {'e': tablename, 'q': query})
+
+ def _drop_metatables_constraints(self):
+ """ Drop all the constraints for the meta data"""
+ for tablename in ('created_by_relation', 'owned_by_relation',
+ 'is_instance_of_relation', 'is_relation',
+ 'entities'):
+ self.drop_and_store_indexes_constraints(tablename)
+
+ def _create_metatables_constraints(self):
+ """ Create all the constraints for the meta data"""
+ for tablename in ('entities',
+ 'created_by_relation', 'owned_by_relation',
+ 'is_instance_of_relation', 'is_relation'):
+ # Indexes and constraints
+ self.reapply_constraint_index(tablename)
+
+ def init_relation_table(self, rtype):
+ """ Get and remove all indexes for performance sake """
+ # Create temporary table
+ if not self.slave_mode and rtype not in self._rtypes:
+ sql = "CREATE TABLE %s_relation_tmp (eid_from integer, eid_to integer)" % rtype.lower()
+ self.sql(sql)
+ # Drop indexes and constraints
+ tablename = '%s_relation' % rtype.lower()
+ self.drop_and_store_indexes_constraints(tablename)
+ # Push the etype in the initialized table for easier restart
+ self.init_create_initialized_table()
+ sql = 'INSERT INTO cwmassive_initialized VALUES (%(e)s, %(t)s)'
+ self.sql(sql, {'e': rtype, 't': 'rtype'})
+ # Mark rtype as "initialized" for faster check
+ self._rtypes.add(rtype)
+
+ def init_create_initialized_table(self):
+ """ Create the cwmassive initialized table
+ """
+ if not self._initialized_table_created:
+ sql = "CREATE TABLE cwmassive_initialized (retype text, type varchar(128))"
+ self.sql(sql)
+ self._initialized_table_created = True
+
+ def init_etype_table(self, etype):
+ """ Add eid sequence to a particular etype table and
+ remove all indexes for performance sake """
+ if etype not in self._entities:
+ # Only for non-initialized etype and not slave mode store
+ if not self.slave_mode:
+ if self.eids_seq_range is None:
+ # Eids are directly set by the entities_id_seq.
+ # We attach this sequence to all the created etypes.
+ sql = ("ALTER TABLE cw_%s ALTER COLUMN cw_eid "
+ "SET DEFAULT nextval('entities_id_seq')" % etype.lower())
+ self.sql(sql)
+ # Drop indexes and constraints
+ tablename = 'cw_%s' % etype.lower()
+ self.drop_and_store_indexes_constraints(tablename)
+ # Push the etype in the initialized table for easier restart
+ self.init_create_initialized_table()
+ sql = 'INSERT INTO cwmassive_initialized VALUES (%(e)s, %(t)s)'
+ self.sql(sql, {'e': etype, 't': 'etype'})
+ # Mark etype as "initialized" for faster check
+ self._entities.add(etype)
+
+
+ ### ENTITIES CREATION #####################################################
+
+ def _get_eid_gen(self):
+ """ Function getting the next eid. This is done by preselecting
+ a given number of eids from the 'entities_id_seq', and then
+ storing them"""
+ while True:
+ last_eid = self._cnx.repo.system_source.create_eid(self._cnx, self.eids_seq_range)
+ for eid in range(last_eid - self.eids_seq_range + 1, last_eid + 1):
+ yield eid
+
+ def _apply_default_values(self, etype, kwargs):
+ """Apply the default values for a given etype, attribute and value."""
+ default_values = self.default_values[etype]
+ missing_keys = set(default_values) - set(kwargs)
+ kwargs.update((key, default_values[key]) for key in missing_keys)
+
+ # store api ################################################################
+
+ def prepare_insert_entity(self, etype, **kwargs):
+ """Given an entity type, attributes and inlined relations, returns the inserted entity's
+ eid.
+ """
+ # Init the table if necessary
+ self.init_etype_table(etype)
+ # Add meta data if not given
+ if 'modification_date' not in kwargs:
+ kwargs['modification_date'] = self._now
+ if 'creation_date' not in kwargs:
+ kwargs['creation_date'] = self._now
+ if 'cwuri' not in kwargs:
+ kwargs['cwuri'] = self._default_cwuri + str(self._count_cwuri)
+ self._count_cwuri += 1
+ if 'eid' not in kwargs and self.eids_seq_range is not None:
+ # If eid is not given and the eids sequence is set,
+ # use the value from the sequence
+ kwargs['eid'] = self.get_next_eid()
+ self._apply_default_values(etype, kwargs)
+ self._data_entities[etype].append(kwargs)
+ return kwargs.get('eid')
+
+ def prepare_insert_relation(self, eid_from, rtype, eid_to, **kwargs):
+ """Insert into the database a relation ``rtype`` between entities with eids ``eid_from``
+ and ``eid_to``.
+ """
+ # Init the table if necessary
+ self.init_relation_table(rtype)
+ self._data_relations[rtype].append({'eid_from': eid_from, 'eid_to': eid_to})
+
+ def flush(self):
+ """Flush the data"""
+ self.flush_entities()
+ self.flush_internal_relations()
+ self.flush_relations()
+
+ def commit(self):
+ """Commit the database transaction."""
+ self.on_commit()
+ super(MassiveObjectStore, self).commit()
+
+ def finish(self):
+ """Remove temporary tables and columns."""
+ self.logger.info("Start cleaning")
+ if self.slave_mode:
+ raise RuntimeError('Store cleanup is not allowed in slave mode')
+ self.logger.info("Start cleaning")
+ # Cleanup relations tables
+ for etype in self._init_uri_eid:
+ self.sql('DROP TABLE uri_eid_%s' % etype.lower())
+ # Remove relations tables
+ for rtype in self._uri_rtypes:
+ if not self._cnx.repo.schema.rschema(rtype).inlined:
+ self.sql('DROP TABLE %(r)s_relation_iid_tmp' % {'r': rtype})
+ else:
+ self.logger.warning("inlined relation %s: no cleanup to be done for it" % rtype)
+ # Get all the initialized etypes/rtypes
+ if self._dbh.table_exists('cwmassive_initialized'):
+ crs = self.sql('SELECT retype, type FROM cwmassive_initialized')
+ for retype, _type in crs.fetchall():
+ self.logger.info('Cleanup for %s' % retype)
+ if _type == 'etype':
+ # Cleanup entities tables - Recreate indexes
+ self._cleanup_entities(retype)
+ elif _type == 'rtype':
+ # Cleanup relations tables
+ self._cleanup_relations(retype)
+ self.sql('DELETE FROM cwmassive_initialized WHERE retype = %(e)s',
+ {'e': retype})
+ # Create meta constraints (entities, is_instance_of, ...)
+ self._create_metatables_constraints()
+ # Delete the meta data table
+ for table_name in ('cwmassive_initialized', 'cwmassive_constraints', 'cwmassive_metadata'):
+ if self._dbh.table_exists(table_name):
+ self.sql('DROP TABLE %s' % table_name)
+ self.commit()
+
+ ### FLUSH #################################################################
+
+ def on_commit(self):
+ if self.on_commit_callback:
+ self.on_commit_callback()
+
+ def on_rollback(self, exc, etype, data):
+ if self.on_rollback_callback:
+ self.on_rollback_callback(exc, etype, data)
+ self._cnx.rollback()
+ else:
+ raise exc
+
+ def flush_internal_relations(self):
+ """ Flush the relations data
+ """
+ for rtype, data in self._data_relations.items():
+ if not data:
+ # There is no data for these etype for this flush round.
+ continue
+ buf = pgstore._create_copyfrom_buffer(data, ('eid_from', 'eid_to'))
+ if not buf:
+ # The buffer is empty. This is probably due to error in _create_copyfrom_buffer
+ raise ValueError
+ cursor = self._cnx.cnxset.cu
+ # Push into the tmp table
+ cursor.copy_from(buf, '%s_relation_tmp' % rtype.lower(),
+ null='NULL', columns=('eid_from', 'eid_to'))
+ # Clear data cache
+ self._data_relations[rtype] = []
+
+ def flush_entities(self):
+ """ Flush the entities data
+ """
+ for etype, data in self._data_entities.items():
+ if not data:
+ # There is no data for these etype for this flush round.
+ continue
+ # XXX It may be interresting to directly infer the columns'
+ # names from the schema instead of using .keys()
+ columns = data[0].keys()
+ # XXX For now, the _create_copyfrom_buffer does a "row[column]"
+ # which can lead to a key error.
+ # Thus we should create dictionary with all the keys.
+ columns = set()
+ for d in data:
+ columns.update(d.keys())
+ _data = []
+ _base_data = dict.fromkeys(columns)
+ for d in data:
+ _d = _base_data.copy()
+ _d.update(d)
+ _data.append(_d)
+ buf = pgstore._create_copyfrom_buffer(_data, columns)
+ if not buf:
+ # The buffer is empty. This is probably due to error in _create_copyfrom_buffer
+ raise ValueError('Error in buffer creation for etype %s' % etype)
+ columns = ['cw_%s' % attr for attr in columns]
+ cursor = self._cnx.cnxset.cu
+ try:
+ cursor.copy_from(buf, 'cw_%s' % etype.lower(), null='NULL', columns=columns)
+ except Exception as exc:
+ self.on_rollback(exc, etype, data)
+ # Clear data cache
+ self._data_entities[etype] = []
+ self.flush_meta_data()
+
+ def flush_meta_data(self):
+ """ Flush the meta data (entities table, is_instance table, ...)
+ """
+ if self.slave_mode:
+ raise RuntimeError('Flushing meta data is not allow in slave mode')
+ if not self._dbh.table_exists('cwmassive_initialized'):
+ self.logger.info('No information available for initialized etypes/rtypes')
+ return
+ if not self._metadata_table_created:
+ # Keep the correctly flush meta data in database
+ sql = "CREATE TABLE cwmassive_metadata (etype text)"
+ self.sql(sql)
+ self._metadata_table_created = True
+ crs = self.sql('SELECT etype FROM cwmassive_metadata')
+ already_flushed = set(e for e, in crs.fetchall())
+ crs = self.sql('SELECT retype FROM cwmassive_initialized WHERE type = %(t)s',
+ {'t': 'etype'})
+ all_etypes = set(e for e, in crs.fetchall())
+ for etype in all_etypes:
+ if etype not in already_flushed:
+ # Deals with meta data
+ self.logger.info('Flushing meta data for %s' % etype)
+ self.insert_massive_meta_data(etype)
+ sql = 'INSERT INTO cwmassive_metadata VALUES (%(e)s)'
+ self.sql(sql, {'e': etype})
+
+ def _cleanup_entities(self, etype):
+ """ Cleanup etype table """
+ if self.eids_seq_range is None:
+ # Remove DEFAULT eids sequence if added
+ sql = 'ALTER TABLE cw_%s ALTER COLUMN cw_eid DROP DEFAULT;' % etype.lower()
+ self.sql(sql)
+ # Create indexes and constraints
+ tablename = SQL_PREFIX + etype.lower()
+ self.reapply_constraint_index(tablename)
+
+ def _cleanup_relations(self, rtype):
+ """ Cleanup rtype table """
+ # Push into relation table while removing duplicate
+ sql = '''INSERT INTO %(r)s_relation (eid_from, eid_to) SELECT DISTINCT
+ T.eid_from, T.eid_to FROM %(r)s_relation_tmp AS T
+ WHERE NOT EXISTS (SELECT 1 FROM %(r)s_relation AS TT WHERE
+ TT.eid_from=T.eid_from AND TT.eid_to=T.eid_to);''' % {'r': rtype}
+ self.sql(sql)
+ # Drop temporary relation table
+ sql = ('DROP TABLE %(r)s_relation_tmp' % {'r': rtype.lower()})
+ self.sql(sql)
+ # Create indexes and constraints
+ tablename = '%s_relation' % rtype.lower()
+ self.reapply_constraint_index(tablename)
+
+ def insert_massive_meta_data(self, etype):
+ """ Massive insertion of meta data for a given etype, based on SQL statements.
+ """
+ # Push data - Use coalesce to avoid NULL (and get 0), if there is no
+ # entities of this type in the entities table.
+ # Meta data relations
+ self.metagen_push_relation(etype, self._cnx.user.eid, 'created_by_relation')
+ self.metagen_push_relation(etype, self._cnx.user.eid, 'owned_by_relation')
+ self.metagen_push_relation(etype, self.source.eid, 'cw_source_relation')
+ self.metagen_push_relation(etype, self._etype_eid_idx[etype], 'is_relation')
+ self.metagen_push_relation(etype, self._etype_eid_idx[etype], 'is_instance_of_relation')
+ sql = ("INSERT INTO entities (eid, type, asource, extid) "
+ "SELECT cw_eid, '%s', 'system', NULL FROM cw_%s "
+ "WHERE NOT EXISTS (SELECT 1 FROM entities WHERE eid=cw_eid)"
+ % (etype, etype.lower()))
+ self.sql(sql)
+
+ def metagen_push_relation(self, etype, eid_to, rtype):
+ sql = ("INSERT INTO %s (eid_from, eid_to) SELECT cw_eid, %s FROM cw_%s "
+ "WHERE NOT EXISTS (SELECT 1 FROM entities WHERE eid=cw_eid)"
+ % (rtype, eid_to, etype.lower()))
+ self.sql(sql)
+
+
+### CONSTRAINTS MANAGEMENT FUNCTIONS ##########################################
+
+def get_size_constraints(schema):
+ """analyzes yams ``schema`` and returns the list of size constraints.
+
+ The returned value is a dictionary mapping entity types to a
+ sub-dictionnaries mapping attribute names -> max size.
+ """
+ size_constraints = {}
+ # iterates on all entity types
+ for eschema in schema.entities():
+ # for each entity type, iterates on attribute definitions
+ size_constraints[eschema.type] = eschema_constraints = {}
+ for rschema, aschema in eschema.attribute_definitions():
+ # for each attribute, if a size constraint is found,
+ # append it to the size constraint list
+ maxsize = None
+ rdef = rschema.rdef(eschema, aschema)
+ for constraint in rdef.constraints:
+ if isinstance(constraint, SizeConstraint):
+ maxsize = constraint.max
+ eschema_constraints[rschema.type] = maxsize
+ return size_constraints
+
+def get_default_values(schema):
+ """analyzes yams ``schema`` and returns the list of default values.
+
+ The returned value is a dictionary mapping entity types to a
+ sub-dictionnaries mapping attribute names -> default values.
+ """
+ default_values = {}
+ # iterates on all entity types
+ for eschema in schema.entities():
+ # for each entity type, iterates on attribute definitions
+ default_values[eschema.type] = eschema_constraints = {}
+ for rschema, _ in eschema.attribute_definitions():
+ # for each attribute, if a size constraint is found,
+ # append it to the size constraint list
+ if eschema.default(rschema.type) is not None:
+ eschema_constraints[rschema.type] = eschema.default(rschema.type)
+ return default_values
+
+
+class PGHelper(object):
+ def __init__(self, cnx, pg_schema='public'):
+ self.cnx = cnx
+ # Deals with pg schema, see #3216686
+ self.pg_schema = pg_schema
+
+ def application_indexes_constraints(self, tablename):
+ """ Get all the indexes/constraints for a given tablename """
+ indexes = self.application_indexes(tablename)
+ constraints = self.application_constraints(tablename)
+ _indexes = {}
+ for name, query in indexes.items():
+ # Remove pkey indexes (automatically created by constraints)
+ # Specific cases of primary key, see #3224079
+ if name not in constraints:
+ _indexes[name] = query
+ return _indexes, constraints
+
+ def table_exists(self, table_name):
+ sql = "SELECT * from information_schema.tables WHERE table_name=%(t)s AND table_schema=%(s)s"
+ crs = self.cnx.system_sql(sql, {'t': table_name, 's': self.pg_schema})
+ res = crs.fetchall()
+ if res:
+ return True
+ return False
+
+ # def check_if_primary_key_exists_for_table(self, table_name):
+ # sql = ("SELECT constraint_name FROM information_schema.table_constraints "
+ # "WHERE constraint_type = 'PRIMARY KEY' AND table_name=%(t)s AND table_schema=%(s)s")
+ # crs = self.cnx.system_sql(sql, {'t': table_name, 's': self.pg_schema})
+ # res = crs.fetchall()
+ # if res:
+ # return True
+ # return False
+
+ def index_query(self, name):
+ """Get the request to be used to recreate the index"""
+ return self.cnx.system_sql("SELECT pg_get_indexdef(c.oid) "
+ "from pg_catalog.pg_class c "
+ "LEFT JOIN pg_catalog.pg_namespace n "
+ "ON n.oid = c.relnamespace "
+ "WHERE c.relname = %(r)s AND n.nspname=%(n)s",
+ {'r': name, 'n': self.pg_schema}).fetchone()[0]
+
+ def constraint_query(self, name):
+ """Get the request to be used to recreate the constraint"""
+ return self.cnx.system_sql("SELECT pg_get_constraintdef(c.oid) "
+ "from pg_catalog.pg_constraint c "
+ "LEFT JOIN pg_catalog.pg_namespace n "
+ "ON n.oid = c.connamespace "
+ "WHERE c.conname = %(r)s AND n.nspname=%(n)s",
+ {'r': name, 'n': self.pg_schema}).fetchone()[0]
+
+ def application_indexes(self, tablename):
+ """ Iterate over all the indexes """
+ # This SQL query (cf http://www.postgresql.org/message-id/432F450F.4080700@squiz.net)
+ # aims at getting all the indexes for each table.
+ sql = '''SELECT c.relname as "Name"
+ FROM pg_catalog.pg_class c
+ JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid
+ JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid
+ LEFT JOIN pg_catalog.pg_user u ON u.usesysid = c.relowner
+ LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
+ WHERE c.relkind IN ('i','')
+ AND c2.relname = '%s'
+ AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
+ AND pg_catalog.pg_table_is_visible(c.oid);''' % tablename
+ indexes_list = self.cnx.system_sql(sql).fetchall()
+ indexes = {}
+ for name, in indexes_list:
+ indexes[name] = self.index_query(name)
+ return indexes
+
+ def application_constraints(self, tablename):
+ """ Iterate over all the constraints """
+ sql = '''SELECT i.conname as "Name"
+ FROM pg_catalog.pg_class c JOIN pg_catalog.pg_constraint i
+ ON i.conrelid = c.oid JOIN pg_catalog.pg_class c2 ON i.conrelid=c2.oid
+ LEFT JOIN pg_catalog.pg_user u ON u.usesysid = c.relowner
+ LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
+ WHERE c2.relname = '%s' AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
+ AND pg_catalog.pg_table_is_visible(c.oid);''' % tablename
+ indexes_list = self.cnx.system_sql(sql).fetchall()
+ constraints = {}
+ for name, in indexes_list:
+ query = self.constraint_query(name)
+ constraints[name] = 'ALTER TABLE %s ADD CONSTRAINT %s %s' % (tablename, name, query)
+ return constraints
--- a/dataimport/pgstore.py Wed Dec 09 18:42:13 2015 +0100
+++ b/dataimport/pgstore.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,18 +16,22 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""Postgres specific store"""
+from __future__ import print_function
import threading
import warnings
-import cPickle
import os.path as osp
-from StringIO import StringIO
+from io import StringIO
from time import asctime
from datetime import date, datetime, time
from collections import defaultdict
from base64 import b64encode
+from six import string_types, integer_types, text_type
+from six.moves import cPickle as pickle, range
+
from cubicweb.utils import make_uid
+from cubicweb.server.utils import eschema_eid
from cubicweb.server.sqlutils import SQL_PREFIX
from cubicweb.dataimport.stores import NoHookRQLObjectStore
@@ -40,7 +44,7 @@
try:
chunksize = (len(statements) / nb_threads) + 1
threads = []
- for i in xrange(nb_threads):
+ for i in range(nb_threads):
chunks = statements[i*chunksize:(i+1)*chunksize]
thread = threading.Thread(target=_execmany_thread,
args=(sql_connect, chunks,
@@ -52,7 +56,7 @@
for t in threads:
t.join()
except Exception:
- print 'Error in import statements'
+ print('Error in import statements')
def _execmany_thread_not_copy_from(cu, statement, data, table=None,
columns=None, encoding='utf-8'):
@@ -69,9 +73,9 @@
_execmany_thread_not_copy_from(cu, statement, data)
else:
if columns is None:
- cu.copy_from(buf, table, null='NULL')
+ cu.copy_from(buf, table, null=u'NULL')
else:
- cu.copy_from(buf, table, null='NULL', columns=columns)
+ cu.copy_from(buf, table, null=u'NULL', columns=columns)
def _execmany_thread(sql_connect, statements, dump_output_dir=None,
support_copy_from=True, encoding='utf-8'):
@@ -100,7 +104,7 @@
columns = list(data[0])
execmany_func(cu, statement, data, table, columns, encoding)
except Exception:
- print 'unable to copy data into table %s' % table
+ print('unable to copy data into table %s' % table)
# Error in import statement, save data in dump_output_dir
if dump_output_dir is not None:
pdata = {'data': data, 'statement': statement,
@@ -108,11 +112,10 @@
filename = make_uid()
try:
with open(osp.join(dump_output_dir,
- '%s.pickle' % filename), 'w') as fobj:
- fobj.write(cPickle.dumps(pdata))
+ '%s.pickle' % filename), 'wb') as fobj:
+ pickle.dump(pdata, fobj)
except IOError:
- print 'ERROR while pickling in', dump_output_dir, filename+'.pickle'
- pass
+ print('ERROR while pickling in', dump_output_dir, filename+'.pickle')
cnx.rollback()
raise
finally:
@@ -122,50 +125,44 @@
def _copyfrom_buffer_convert_None(value, **opts):
'''Convert None value to "NULL"'''
- return 'NULL'
+ return u'NULL'
def _copyfrom_buffer_convert_number(value, **opts):
'''Convert a number into its string representation'''
- return str(value)
+ return text_type(value)
def _copyfrom_buffer_convert_string(value, **opts):
'''Convert string value.
-
- Recognized keywords:
- :encoding: resulting string encoding (default: utf-8)
'''
- encoding = opts.get('encoding','utf-8')
- escape_chars = ((u'\\', ur'\\'), (u'\t', u'\\t'), (u'\r', u'\\r'),
+ escape_chars = ((u'\\', u'\\\\'), (u'\t', u'\\t'), (u'\r', u'\\r'),
(u'\n', u'\\n'))
for char, replace in escape_chars:
value = value.replace(char, replace)
- if isinstance(value, unicode):
- value = value.encode(encoding)
return value
def _copyfrom_buffer_convert_date(value, **opts):
'''Convert date into "YYYY-MM-DD"'''
# Do not use strftime, as it yields issue with date < 1900
# (http://bugs.python.org/issue1777412)
- return '%04d-%02d-%02d' % (value.year, value.month, value.day)
+ return u'%04d-%02d-%02d' % (value.year, value.month, value.day)
def _copyfrom_buffer_convert_datetime(value, **opts):
'''Convert date into "YYYY-MM-DD HH:MM:SS.UUUUUU"'''
# Do not use strftime, as it yields issue with date < 1900
# (http://bugs.python.org/issue1777412)
- return '%s %s' % (_copyfrom_buffer_convert_date(value, **opts),
- _copyfrom_buffer_convert_time(value, **opts))
+ return u'%s %s' % (_copyfrom_buffer_convert_date(value, **opts),
+ _copyfrom_buffer_convert_time(value, **opts))
def _copyfrom_buffer_convert_time(value, **opts):
'''Convert time into "HH:MM:SS.UUUUUU"'''
- return '%02d:%02d:%02d.%06d' % (value.hour, value.minute,
- value.second, value.microsecond)
+ return u'%02d:%02d:%02d.%06d' % (value.hour, value.minute,
+ value.second, value.microsecond)
# (types, converter) list.
_COPYFROM_BUFFER_CONVERTERS = [
(type(None), _copyfrom_buffer_convert_None),
- ((long, int, float), _copyfrom_buffer_convert_number),
- (basestring, _copyfrom_buffer_convert_string),
+ (integer_types + (float,), _copyfrom_buffer_convert_number),
+ (string_types, _copyfrom_buffer_convert_string),
(datetime, _copyfrom_buffer_convert_datetime),
(date, _copyfrom_buffer_convert_date),
(time, _copyfrom_buffer_convert_time),
@@ -185,7 +182,7 @@
rows = []
if columns is None:
if isinstance(data[0], (tuple, list)):
- columns = range(len(data[0]))
+ columns = list(range(len(data[0])))
elif isinstance(data[0], dict):
columns = data[0].keys()
else:
@@ -209,6 +206,7 @@
for types, converter in _COPYFROM_BUFFER_CONVERTERS:
if isinstance(value, types):
value = converter(value, **convert_opts)
+ assert isinstance(value, text_type)
break
else:
raise ValueError("Unsupported value type %s" % type(value))
@@ -335,7 +333,7 @@
self._sql.eid_insertdicts = {}
def flush(self):
- print 'starting flush'
+ print('starting flush')
_entities_sql = self._sql.entities
_relations_sql = self._sql.relations
_inlined_relations_sql = self._sql.inlined_relations
@@ -346,7 +344,7 @@
# In that case, simply update the insert dict and remove
# the need to make the
# UPDATE statement
- for statement, datalist in _inlined_relations_sql.iteritems():
+ for statement, datalist in _inlined_relations_sql.items():
new_datalist = []
# for a given inlined relation,
# browse each couple to be inserted
@@ -410,7 +408,7 @@
_sql[statement] = [data]
def add_entity(self, cnx, entity):
- with self._storage_handler(entity, 'added'):
+ with self._storage_handler(cnx, entity, 'added'):
attrs = self.preprocess_entity(entity)
rtypes = self._inlined_rtypes_cache.get(entity.cw_etype, ())
if isinstance(rtypes, str):
--- a/dataimport/stores.py Wed Dec 09 18:42:13 2015 +0100
+++ b/dataimport/stores.py Thu Dec 10 12:34:15 2015 +0100
@@ -21,7 +21,7 @@
>>> user_eid = store.prepare_insert_entity('CWUser', login=u'johndoe')
>>> group_eid = store.prepare_insert_entity('CWUser', name=u'unknown')
- >>> store.relate(user_eid, 'in_group', group_eid)
+ >>> store.prepare_insert_relation(user_eid, 'in_group', group_eid)
>>> store.flush()
>>> store.commit()
>>> store.finish()
@@ -61,6 +61,8 @@
from datetime import datetime
from copy import copy
+from six import text_type
+
from logilab.common.deprecation import deprecated
from logilab.common.decorators import cached
@@ -101,7 +103,7 @@
and inlined relations.
"""
entity = self._cnx.entity_from_eid(eid)
- assert entity.cw_etype == etype, 'Trying to update with wrong type {}'.format(etype)
+ assert entity.cw_etype == etype, 'Trying to update with wrong type %s' % etype
# XXX some inlined relations may already exists
entity.cw_set(**kwargs)
@@ -120,6 +122,10 @@
"""Commit the database transaction."""
return self._commit()
+ def finish(self):
+ """Nothing to do once import is terminated for this store."""
+ pass
+
@property
def session(self):
warnings.warn('[3.19] deprecated property.', DeprecationWarning, stacklevel=2)
@@ -168,7 +174,7 @@
"""Given an entity type, attributes and inlined relations, returns the inserted entity's
eid.
"""
- for k, v in kwargs.iteritems():
+ for k, v in kwargs.items():
kwargs[k] = getattr(v, 'eid', v)
entity, rels = self.metagen.base_etype_dicts(etype)
# make a copy to keep cached entity pristine
@@ -183,7 +189,7 @@
kwargs = dict()
if inspect.getargspec(self.add_relation).keywords:
kwargs['subjtype'] = entity.cw_etype
- for rtype, targeteids in rels.iteritems():
+ for rtype, targeteids in rels.items():
# targeteids may be a single eid or a list of eids
inlined = self.rschema(rtype).inlined
try:
@@ -298,7 +304,7 @@
genfunc = self.generate(attr)
if genfunc:
entity.cw_edited.edited_attribute(attr, genfunc(entity))
- if isinstance(extid, unicode):
+ if isinstance(extid, text_type):
extid = extid.encode('utf-8')
return self.source, extid
@@ -320,4 +326,3 @@
def gen_owned_by(self, entity):
return self._cnx.user.eid
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dataimport/test/data-massimport/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,154 @@
+# copyright 2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr -- mailto:contact@logilab.fr
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""cubicweb-geonames schema"""
+
+from yams.buildobjs import (EntityType, RelationDefinition, SubjectRelation,
+ String, Int, BigInt, Float, Date)
+from cubicweb.schemas.base import ExternalUri
+
+"""
+See geonames readme.txt for more details.
+"""
+
+class TestLocation(EntityType):
+ """
+ Entity type for location of Geonames.
+ See cities1000.zip, cities5000.zip, cities15000.zip and allCountries.txt
+ """
+ name = String(maxsize=1024, indexed=True, fulltextindexed=True)
+ geonameid = Int(required=True, unique=True, indexed=True)
+
+class Location(EntityType):
+ """
+ Entity type for location of Geonames.
+ See cities1000.zip, cities5000.zip, cities15000.zip and allCountries.txt
+ """
+ name = String(maxsize=1024, indexed=True, fulltextindexed=True)
+ geonameid = Int(indexed=True)
+ asciiname = String(maxsize=200, fulltextindexed=True)
+ alternatenames = String(fulltextindexed=True)
+ names = SubjectRelation('LocationName', cardinality='**')
+ latitude = Float(indexed=True)
+ longitude = Float(indexed=True)
+ feature_class = String(maxsize=1, indexed=True)
+ feature_code = SubjectRelation('FeatureCode', cardinality='?*', inlined=True)
+ country = SubjectRelation('Country', cardinality='?*', inlined=True)
+ alternate_country_code = String(maxsize=60)
+ main_administrative_region = SubjectRelation('AdministrativeRegion', cardinality='?*', inlined=True)
+ second_administrative_region = SubjectRelation('AdministrativeRegion', cardinality='?*', inlined=True)
+ admin_code_1 = String(maxsize=124)
+ admin_code_2 = String(maxsize=124)
+ admin_code_3 = String(maxsize=20)
+ admin_code_4 = String(maxsize=20)
+ population = BigInt(indexed=True)
+ elevation = Int(indexed=True)
+ gtopo30 = Int(indexed=True)
+ timezone = SubjectRelation('TimeZone', cardinality='?*', inlined=True)
+ geonames_date = Date()
+
+class LocationName(EntityType):
+ """
+ Name of a Location
+ """
+ name = String(maxsize=1024, indexed=True, fulltextindexed=True)
+ language = SubjectRelation('Language', cardinality='?*', inlined=True)
+ alternatenamesid = Int(indexed=True)
+
+class FeatureCode(EntityType):
+ """
+ Entity type for feature codes of Geonames.
+ See featureCodes_en.txt
+ """
+ name = String(maxsize=1024, indexed=True, fulltextindexed=True)
+ main_code = String(maxsize=1, indexed=True)
+ code = String(maxsize=12)
+ description = String(maxsize=1024, fulltextindexed=True)
+
+class AdministrativeRegion(EntityType):
+ """
+ Entity type for administrative regions of Geonames.
+ See admin1CodesASCII.txt and admin2Codes.txt
+ """
+ name = String(maxsize=1024, indexed=True, fulltextindexed=True)
+ code = String(maxsize=64, indexed=True)
+ country = SubjectRelation('Country', cardinality='?*', inlined=True)
+ geonameid = Int(indexed=True)
+ asciiname = String(maxsize=200, fulltextindexed=True)
+
+class Language(EntityType):
+ """
+ Entity type for languages of Geonames.
+ See admin1CodesASCII.txt and admin2Codes.txt
+ """
+ name = String(maxsize=1024, indexed=True, fulltextindexed=True)
+ iso_639_3 = String(maxsize=3, indexed=True)
+ iso_639_2 = String(maxsize=64, indexed=True)
+ iso_639_1 = String(maxsize=3, indexed=True)
+
+class Continent(EntityType):
+ """
+ Entity type for continents of geonames.
+ """
+ name = String(maxsize=1024, indexed=True, fulltextindexed=True)
+ code = String(maxsize=2, indexed=True)
+ geonameid = Int(indexed=True)
+
+class Country(EntityType):
+ """
+ Entity type for countries of geonames.
+ See countryInfo.txt
+ """
+ name = String(maxsize=1024, indexed=True, fulltextindexed=True)
+ code = String(maxsize=2, indexed=True)
+ code3 = String(maxsize=3, indexed=True)
+ codenum = Int(indexed=True)
+ fips = String(maxsize=2)
+ capital = String(maxsize=1024, fulltextindexed=True)
+ area = Float(indexed=True)
+ population = BigInt(indexed=True)
+ continent_code = String(maxsize=3)
+ continent = SubjectRelation('Continent', cardinality='?*', inlined=True)
+ tld = String(maxsize=64)
+ currency = String(maxsize=1024, fulltextindexed=True)
+ currency_code = String(maxsize=64)
+ geonameid = Int(indexed=True)
+ phone = String(maxsize=64)
+ postal_code = String(maxsize=200)
+ postal_code_regex = String(maxsize=200)
+ languages_code = String(maxsize=200)
+ neighbours_code = String(maxsize=200)
+ equivalent_fips = String(maxsize=2)
+
+class TimeZone(EntityType):
+ """
+ Entity type for timezone of geonames.
+ See timeZones.txt
+ """
+ code = String(maxsize=1024, indexed=True)
+ gmt = Float()
+ dst = Float()
+ raw_offset = Float()
+
+class used_language(RelationDefinition):
+ subject = 'Country'
+ object = 'Language'
+ cardinality = '**'
+
+class neighbour_of(RelationDefinition):
+ subject = 'Country'
+ object = 'Country'
+ cardinality = '**'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dataimport/test/data/geonames.csv Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,4000 @@
+3038814 Costa de Xurius Costa de Xurius 42.5 1.48333 T SLP AD 00 0 1316 Europe/Andorra 1993-12-23
+3038815 Font de la Xona Font de la Xona 42.55003 1.44986 H SPNG AD 04 0 2082 Europe/Andorra 2010-01-11
+3038816 Xixerella Xixerella 42.55327 1.48736 P PPL AD 04 0 1520 Europe/Andorra 2009-04-24
+3038817 Xixerella Xixerella Xixerella 42.55 1.48333 A ADMD AD 00 0 1548 Europe/Andorra 2011-11-05
+3038818 Riu Xic Riu Xic 42.56667 1.68333 H STM AD 00 0 2340 Europe/Andorra 1993-12-23
+3038819 Pas del Xic Pas del Xic 42.5 1.58333 R TRL AD 00 0 1888 Europe/Andorra 1993-12-23
+3038820 Roc del Xeig Roc del Xeig 42.56667 1.48333 T RK AD 00 0 1508 Europe/Andorra 1993-12-23
+3038821 Collada del Xeig Collada del Xeig 42.56667 1.48333 T PK AD 00 0 1508 Europe/Andorra 1993-12-23
+3038822 Fonts Vives Fonts Vives 42.5 1.56667 H SPNG AD 00 0 1776 Europe/Andorra 1993-12-23
+3038823 Roc de Vista Roc de Vista 42.5 1.48333 T RK AD 00 0 1316 Europe/Andorra 1993-12-23
+3038824 Obaga de Vista Obaga de Vista 42.48333 1.45 T SLP AD 00 0 1195 Europe/Andorra 1993-12-23
+3038825 Coll de Vista Coll de Vista 42.46667 1.58333 T SPUR AD 00 0 2367 Europe/Andorra 1993-12-23
+3038826 Coll de Vista Coll de Vista Coll de Vista 42.48333 1.43333 T PASS AD 00 0 1938 Europe/Andorra 2011-11-05
+3038827 Visanseny Visanseny Visanceny,Visanseny 42.56667 1.61667 L LCTY AD AD 00 0 1920 Europe/Andorra 2011-11-05
+3038828 Roc de la Vinya Roc de la Vinya 42.53333 1.56667 T RK AD 00 0 1418 Europe/Andorra 1993-12-23
+3038829 Canal de la Vinya Canal de la Vinya 42.51667 1.51667 H STM AD 00 0 1265 Europe/Andorra 1993-12-23
+3038830 Bosc de Villar Bosc de Villar 42.6 1.55 V FRST AD 00 0 2298 Europe/Andorra 1993-12-23
+3038831 Torrent de Vila Torrent de Vila 42.53333 1.56667 H STM AD 00 0 1418 Europe/Andorra 1993-12-23
+3038832 Vila Vila Casas Vila,Vila 42.53222 1.57392 P PPL AD 03 0 1418 Europe/Andorra 2011-11-05
+3038833 Basers de Vicenç Basers de Vicenc 42.48333 1.48333 T CLF AD 00 0 981 Europe/Andorra 1993-12-23
+3038834 Pla de Viàs Pla de Vias 42.58333 1.66667 T UPLD AD 00 0 2159 Europe/Andorra 1993-12-23
+3038835 Vial del Cardaire Vial del Cardaire 42.56667 1.5 L LCTY AD 00 0 1636 Europe/Andorra 1993-12-23
+3038836 Font del Vi Font del Vi 42.51667 1.48333 H SPNG AD 00 0 1839 Europe/Andorra 1993-12-23
+3038837 Font Verda Font Verda 42.55 1.56667 H SPNG AD 00 0 1828 Europe/Andorra 1993-12-23
+3038838 Costa Verda Costa Verda 42.48333 1.66667 T SLP AD 00 0 2524 Europe/Andorra 1993-12-23
+3038839 Costa Verda Costa Verda 42.48333 1.56667 T SLP AD 00 0 2231 Europe/Andorra 1993-12-23
+3038840 Serrat de Ventader Serrat de Ventader 42.48333 1.43333 T MT AD 00 0 1938 Europe/Andorra 1993-12-23
+3038841 Bony de Vellatocina Bony de Vellatocina 42.61667 1.5 T PK AD 00 0 2390 Europe/Andorra 1993-12-23
+3038842 Pleta Vella Pleta Vella 42.51667 1.61667 L GRAZ AD 00 0 2254 Europe/Andorra 1993-12-23
+3038843 Solà Vell Sola Vell 42.46667 1.48333 T SLP AD 00 0 1134 Europe/Andorra 1993-12-23
+3038844 Port Vell Port Vell 42.65 1.55 T PASS AD 00 0 2181 Europe/Andorra 1993-12-23
+3038845 Port Negre del Pallars Port Negre del Pallars Port Negre del Pallars,Port Vell 42.56667 1.45 T PASS AD 00 0 2137 Europe/Andorra 2011-11-05
+3038846 Bancal Vedeller Bancal Vedeller 42.6 1.46667 R TRL AD 00 0 2421 Europe/Andorra 1993-12-23
+3038847 Vedat del Xeig Vedat del Xeig 42.56667 1.48333 L LCTY AD 00 0 1508 Europe/Andorra 1993-12-23
+3038848 Vedat dels Plans Vedat dels Plans 42.53333 1.5 A ADMD AD 00 0 1357 Europe/Andorra 1993-12-23
+3038849 Vedat de Coll de les Cases Vedat de Coll de les Cases 42.56667 1.5 L LCTY AD 00 0 1636 Europe/Andorra 1993-12-23
+3038850 Serra del Vedat Serra del Vedat 42.46667 1.48333 T RDGE AD 00 0 1134 Europe/Andorra 1993-12-23
+3038851 Planades del Vedat Planades del Vedat 42.53333 1.5 T UPLD AD 00 0 1357 Europe/Andorra 1993-12-23
+3038852 Veda de Sorteny Veda de Sorteny 42.61667 1.55 L LCTY AD 00 0 2007 Europe/Andorra 1993-12-23
+3038853 Veda del Castellar Veda del Castellar 42.63333 1.51667 A ADMD AD 00 0 1894 Europe/Andorra 1993-12-23
+3038854 Canal de les Veces Canal de les Veces 42.51667 1.51667 H STM AD 00 0 1265 Europe/Andorra 1993-12-23
+3038855 Coma de Varilles Coma de Varilles 42.63333 1.53333 T VAL AD 00 0 2072 Europe/Andorra 1993-12-23
+3038856 Portella de les Vaques Portella de les Vaques 42.56667 1.45 T PASS AD 00 0 2137 Europe/Andorra 1993-12-23
+3038857 Pas de les Vaques Pas de les Vaques 42.58333 1.7 T PASS AD 00 0 2584 Europe/Andorra 1993-12-23
+3038858 Collada de les Vaques Collada de les Vaques 42.56667 1.56667 T PASS AD 00 0 2089 Europe/Andorra 1993-12-23
+3038859 Roc del Vaquer Roc del Vaquer 42.63333 1.48333 T CLF AD 00 0 2283 Europe/Andorra 1993-12-23
+3038860 Valls de la Coma Valls de la Coma 42.6 1.63333 L LCTY AD 00 0 1893 Europe/Andorra 1993-12-23
+3038861 Vall d'Incles Vall d'Incles 42.58386 1.66331 L LCTY AD 02 0 1867 Europe/Andorra 2010-01-11
+3038862 Vall de Soldeu Vall de Soldeu 42.55 1.68333 L LCTY AD 00 0 2254 Europe/Andorra 1993-12-23
+3038863 Riu de la Vall del Riu Riu de la Vall del Riu 42.56667 1.61667 H STM AD 00 0 1920 Europe/Andorra 1993-12-23
+3038864 Estany Gran de la Vall del Riu Estany Gran de la Vall del Riu 42.601 1.59368 H LK AD 00 0 2467 Europe/Andorra 2011-04-19
+3038865 Cascada de la Vall del Riu Cascada de la Vall del Riu 42.56667 1.61667 H FLLS AD 00 0 1920 Europe/Andorra 1993-12-23
+3038866 Canals de la Vall del Riu Canals de la Vall del Riu 42.58333 1.6 H RVN AD 00 0 1828 Europe/Andorra 1993-12-23
+3038867 Camà de la Vall del Riu Cami de la Vall del Riu 42.58333 1.61667 R TRL AD 00 0 1707 Europe/Andorra 1993-12-23
+3038868 Bosc de la Vall del Riu Bosc de la Vall del Riu 42.58333 1.61667 V FRST AD 00 0 1707 Europe/Andorra 1993-12-23
+3038869 Vall del Riu Vall del Riu 42.6 1.6 A ADMD AD 00 0 2143 Europe/Andorra 1993-12-23
+3038870 Coll de Vall Civera Coll de Vall Civera Coll de Valcibera,Coll de Vall Civera,Collado de Vall-Civera,Port de Vall Civera 42.48333 1.66667 T PASS AD 00 0 2524 Europe/Andorra 2011-11-05
+3038871 Obac de la Vall Obac de la Vall 42.46667 1.5 T SLP AD 00 0 1383 Europe/Andorra 1993-12-23
+3038872 Riu Valira d’Orient Riu Valira d'Orient Rio Balira del Orien,Riu Valira d'Orient,Riu Valira d’Orient,RÃo Balira del Orien 42.51667 1.53333 H STM AD 00 0 1460 Europe/Andorra 2011-11-05
+3038873 Riu Valira del Nord Riu Valira del Nord Riu Valira d'Ordino,Riu Valira del Nord,Riu Valira del Nort,Riu Valira d’Ordino,Valira del Nord,Valira del Norte 42.34645 1.44271 H STM AD 00 0 682 Europe/Andorra 2011-11-05
+3038874 Estanys de la Val del Riu Estanys de la Val del Riu 42.60138 1.59418 H LKS AD 00 0 2467 Europe/Andorra 2011-04-19
+3038875 Vaca Morta Vaca Morta 42.56667 1.76667 L LCTY AD 00 0 1674 Europe/Andorra 1993-12-23
+3038876 Riu d’ Urina Riu d' Urina 42.56667 1.58333 H STM AD 00 0 1919 Europe/Andorra 1993-12-23
+3038877 Serrat de la Uïna Serrat de la Uina 42.56667 1.51667 T RDGE AD 00 0 1500 Europe/Andorra 1993-12-23
+3038878 Obaga de la Tuta Obaga de la Tuta 42.48333 1.45 T SLP AD 00 0 1195 Europe/Andorra 1993-12-23
+3038879 Cova de la Tuta Cova de la Tuta 42.48333 1.45 S CAVE AD 00 0 1195 Europe/Andorra 1993-12-23
+3038880 Roca del Tut Roca del Tut 42.55 1.46667 T RK AD 00 0 1585 Europe/Andorra 1993-12-23
+3038881 Coll de Turer Coll de Turer 42.56667 1.46667 T PK AD 00 0 1673 Europe/Andorra 1993-12-23
+3038882 Font del Tudó Font del Tudo 42.43333 1.53333 H SPNG AD 00 0 2108 Europe/Andorra 1993-12-23
+3038883 Estany de les Truites Estany de les Truites 42.58333 1.45 H LK AD 00 0 2156 Europe/Andorra 1993-12-23
+3038884 Serra de Tristaina Serra de Tristaina Serra de Tristaina 42.65 1.48333 T RDGE AD 00 0 2341 Europe/Andorra 2011-11-05
+3038885 Riu de Tristaina Riu de Tristaina 42.61667 1.55 H STM AD 00 0 2007 Europe/Andorra 1993-12-23
+3038886 Pic de Tristaina Pic de Tristaina Pic de Triatagne,Pic de Tristagne,Pic de Tristaina,Pic des Tri-Stagnes,Tristaina 42.65265 1.49242 T PK AD AD,FR 00 0 2384 Europe/Andorra 2007-04-29
+3038887 Clot de Tres Torrents Clot de Tres Torrents 42.53333 1.53333 H RVN AD 00 0 1521 Europe/Andorra 1993-12-23
+3038888 Bony de Tres Corts Bony de Tres Corts 42.53333 1.53333 T SPUR AD 00 0 1521 Europe/Andorra 1993-12-23
+3038889 Canal dels Trèmols Canal dels Tremols 42.5 1.48333 H STM AD 00 0 1316 Europe/Andorra 1993-12-23
+3038890 Travenc Travenc 42.6 1.68333 L LCTY AD 00 0 2089 Europe/Andorra 1993-12-23
+3038891 Pleta de la Trava Pleta de la Trava 42.48333 1.61667 L GRAZ AD 00 0 2217 Europe/Andorra 1993-12-23
+3038892 Coll de la Trava Coll de la Trava 42.48333 1.46667 T SPUR AD 00 0 1148 Europe/Andorra 1993-12-23
+3038893 Canal de la Trava Canal de la Trava 42.56667 1.53333 H RVN AD 00 0 1669 Europe/Andorra 1993-12-23
+3038894 Bosc de la Trava Bosc de la Trava 42.48333 1.63333 V FRST AD 00 0 2296 Europe/Andorra 1993-12-23
+3038895 Font dels Traginers Font dels Traginers 42.43333 1.51667 H SPNG AD 00 0 2031 Europe/Andorra 1993-12-23
+3038896 Pla de les Toves Pla de les Toves 42.46667 1.45 T UPLD AD 00 0 1562 Europe/Andorra 1993-12-23
+3038897 Torrent del Tossalroi Torrent del Tossalroi 42.46667 1.51667 H STM AD 00 0 1985 Europe/Andorra 1993-12-23
+3038898 Tossal Gran Tossal Gran 42.48333 1.48333 L LCTY AD 00 0 981 Europe/Andorra 1993-12-23
+3038899 Tossalet i Vinyals Tossalet i Vinyals 42.48333 1.48333 L LCTY AD 00 0 981 Europe/Andorra 1993-12-23
+3038900 Bosc del Tossal de les Poselles Bosc del Tossal de les Poselles 42.53333 1.5 V FRST AD 00 0 1357 Europe/Andorra 1993-12-23
+3038901 Tossal Tossal 42.46667 1.48333 L LCTY AD 00 0 1134 Europe/Andorra 1993-12-23
+3038902 Tosquers Tosquers 42.56667 1.48333 T SLP AD 00 0 1508 Europe/Andorra 1993-12-23
+3038903 Canal del Tosquer Canal del Tosquer 42.56667 1.51667 H STM AD 00 0 1500 Europe/Andorra 1993-12-23
+3038904 Bosc del Tosquer Bosc del Tosquer 42.56667 1.53333 V FRST AD 00 0 1669 Europe/Andorra 1993-12-23
+3038905 Bosc del Tosquer Bosc del Tosquer 42.53333 1.6 V FRST AD 00 0 1888 Europe/Andorra 1993-12-23
+3038906 Bosc de la Tosca Bosc de la Tosca 42.43333 1.45 V FRST AD 00 0 877 Europe/Andorra 1993-12-23
+3038907 Tosa d’Incles Tosa d'Incles 42.58333 1.68333 A ADMD AD 00 0 2294 Europe/Andorra 1993-12-23
+3038908 Cap de Tosa d’Entor Cap de Tosa d'Entor 42.6 1.65 T PK AD 00 0 2131 Europe/Andorra 1993-12-23
+3038909 Tosa de les Mussoles Tosa de les Mussoles 42.61667 1.68333 L LCTY AD 00 0 2406 Europe/Andorra 1993-12-23
+3038910 Pic de la Tosa de Juclar Pic de la Tosa de Juclar 42.6 1.71667 T PK AD 00 0 2516 Europe/Andorra 1993-12-23
+3038911 Collada de la Tosa de Caraup Collada de la Tosa de Caraup 42.6 1.65 T SPUR AD 00 0 2131 Europe/Andorra 1993-12-23
+3038912 Planell de la Tosa Planell de la Tosa 42.53333 1.45 T UPLD AD 00 0 2130 Europe/Andorra 1993-12-23
+3038913 Canals de la Tosa Canals de la Tosa 42.58333 1.7 H RVN AD 00 0 2584 Europe/Andorra 1993-12-23
+3038914 Canal de la Tosa Canal de la Tosa 42.5 1.56667 H STM AD 00 0 1776 Europe/Andorra 1993-12-23
+3038915 Bosc de la Tosa Bosc de la Tosa 42.55 1.58333 V FRST AD 00 0 1499 Europe/Andorra 1993-12-23
+3038916 Canal Torta Canal Torta 42.56667 1.51667 H STM AD 00 0 1500 Europe/Andorra 1993-12-23
+3038917 Canal Torta Canal Torta 42.53333 1.53333 H STM AD 00 0 1521 Europe/Andorra 1993-12-23
+3038918 Torrent Tort Torrent Tort 42.53333 1.58333 H STM AD 00 0 1571 Europe/Andorra 1993-12-23
+3038919 Torretinyà Torretinya 42.45 1.51667 L LCTY AD 00 0 1790 Europe/Andorra 1993-12-23
+3038920 Prat d’en Torres Prat d'en Torres 42.6 1.51667 L GRAZ AD 00 0 1445 Europe/Andorra 1993-12-23
+3038921 Canals de Torrent Pregó Canals de Torrent Prego 42.48333 1.48333 H STM AD 00 0 981 Europe/Andorra 1993-12-23
+3038922 Canal de Torrentinyà Canal de Torrentinya 42.45 1.5 H STM AD 00 0 1614 Europe/Andorra 1993-12-23
+3038923 Torrentill Torrentill 42.46667 1.5 H STM AD 00 0 1383 Europe/Andorra 1993-12-23
+3038924 Camà de Torrent Forcat Cami de Torrent Forcat 42.46667 1.51667 R TRL AD 00 0 1985 Europe/Andorra 1993-12-23
+3038925 Canal del Torrent Cauber Canal del Torrent Cauber 42.6 1.51667 H RVN AD 00 0 1445 Europe/Andorra 1993-12-23
+3038926 Torre dels Soldats Torre dels Soldats Pic Monturull,Torre dels Soldats 42.45 1.58333 T PK AD 00 0 2537 Europe/Andorra 2011-11-05
+3038927 Torrapuis Torrapuis 42.53333 1.53333 L LCTY AD 00 0 1521 Europe/Andorra 1993-12-23
+3038928 Pic de Torradella Pic de Torradella 42.6 1.61667 T PK AD 00 0 2271 Europe/Andorra 1993-12-23
+3038929 Pala de la Torradella Pala de la Torradella 42.58333 1.61667 T SLP AD 00 0 1707 Europe/Andorra 1993-12-23
+3038930 Obaga de Torradella Obaga de Torradella 42.6 1.63333 T SLP AD 00 0 1893 Europe/Andorra 1993-12-23
+3038931 Canals de Torradella Canals de Torradella 42.6 1.63333 H STM AD 00 0 1893 Europe/Andorra 1993-12-23
+3038932 Borda del Torner Borda del Torner 42.58333 1.48333 S FRM AD 00 0 1809 Europe/Andorra 1993-12-23
+3038933 Planell de la Tora Planell de la Tora 42.55 1.6 T UPLD AD 00 0 2210 Europe/Andorra 1993-12-23
+3038934 Clots de la Tora Clots de la Tora 42.46667 1.58333 H RVN AD 00 0 2367 Europe/Andorra 1993-12-23
+3038935 Prat del Toni Prat del Toni 42.55 1.61667 L GRAZ AD 00 0 2206 Europe/Andorra 1993-12-23
+3038936 Molà del Tomàs Moli del Tomas 42.58333 1.65 S ML AD 00 0 1767 Europe/Andorra 1993-12-23
+3038937 Cortals de Tolse Cortals de Tolse 42.45 1.48333 S CRRL AD 00 0 1111 Europe/Andorra 1993-12-23
+3038938 Bosc de Tolse Bosc de Tolse 42.45 1.48333 V FRST AD 00 0 1111 Europe/Andorra 1993-12-23
+3038939 Tolse Tolse 42.45 1.48333 S HUTS AD 00 0 1111 Europe/Andorra 1993-12-23
+3038940 Basera dels Tolls de l’Olla Basera dels Tolls de l'Olla 42.48333 1.45 T CLF AD 00 0 1195 Europe/Andorra 1993-12-23
+3038941 Tolls de l’Olla Tolls de l'Olla 42.46667 1.56667 L LCTY AD 00 0 2365 Europe/Andorra 1993-12-23
+3038942 Torrent del Tirader Torrent del Tirader 42.53333 1.6 H STM AD 00 0 1888 Europe/Andorra 1993-12-23
+3038943 Canal del Timbarro Canal del Timbarro 42.5 1.46667 H STM AD 00 0 1678 Europe/Andorra 1993-12-23
+3038944 Terres de Serra Terres de Serra 42.48333 1.5 L LCTY AD 00 0 1631 Europe/Andorra 1993-12-23
+3038945 Terres de Sant Miguel Terres de Sant Miguel 42.5 1.58333 L LCTY AD 00 0 1888 Europe/Andorra 1993-12-23
+3038946 Terres del Torrent Pregó Terres del Torrent Prego 42.55 1.58333 L LCTY AD 00 0 1499 Europe/Andorra 1993-12-23
+3038947 Terres del Solà Terres del Sola 42.55 1.55 L LCTY AD 00 0 2097 Europe/Andorra 1993-12-23
+3038948 Terres de Jacques Terres de Jacques 42.56667 1.61667 L LCTY AD 00 0 1920 Europe/Andorra 1993-12-23
+3038949 Obaga de les Terres de Casamanya Obaga de les Terres de Casamanya 42.56667 1.55 T SLP AD 00 0 1996 Europe/Andorra 1993-12-23
+3038950 Canal del Terrer Roig Canal del Terrer Roig 42.58333 1.46667 H STM AD 00 0 1643 Europe/Andorra 1993-12-23
+3038951 Terrer Roig Terrer Roig 42.58333 1.45 L LCTY AD 00 0 2156 Europe/Andorra 1993-12-23
+3038952 Clots dels Terregalls Clots dels Terregalls 42.61667 1.61667 H STMH AD 00 0 2352 Europe/Andorra 1993-12-23
+3038953 Terregalls Terregalls 42.5 1.51667 L LCTY AD 00 0 1410 Europe/Andorra 1993-12-23
+3038954 Terra del Pou Terra del Pou 42.46667 1.48333 L LCTY AD 00 0 1134 Europe/Andorra 1993-12-23
+3038955 Terra Bogada Terra Bogada 42.46667 1.5 L LCTY AD 00 0 1383 Europe/Andorra 1993-12-23
+3038956 Canal del Teixó Canal del Teixo 42.55 1.5 H STM AD 00 0 1292 Europe/Andorra 1993-12-23
+3038957 Coma de Teix Coma de Teix 42.46667 1.46667 T SLP AD 00 0 1340 Europe/Andorra 1993-12-23
+3038958 Font de les Taules Font de les Taules 42.55 1.55 H SPNG AD 00 0 2097 Europe/Andorra 1993-12-23
+3038959 Coma Tarterosa Coma Tarterosa 42.48333 1.45 H RVN AD 00 0 1195 Europe/Andorra 1993-12-23
+3038960 Bosc de la Tarterosa Bosc de la Tarterosa 42.6 1.65 V FRST AD 00 0 2131 Europe/Andorra 1993-12-23
+3038961 Tarter Gran Tarter Gran 42.58333 1.45 L LCTY AD 00 0 2156 Europe/Andorra 1993-12-23
+3038962 Tartera Gran Tartera Gran 42.48333 1.46667 L LCTY AD 00 0 1148 Europe/Andorra 1993-12-23
+3038963 Pont del Tarter Pont del Tarter 42.58333 1.65 S BDG AD 00 0 1767 Europe/Andorra 1993-12-23
+3038964 Coll de la TÃ pia Coll de la Tapia 42.46667 1.48333 T PASS AD 00 0 1134 Europe/Andorra 1993-12-23
+3038965 Canal Tancada Canal Tancada 42.48333 1.55 H STM AD 00 0 2233 Europe/Andorra 1993-12-23
+3038966 Roc del Tampuent Roc del Tampuent 42.58333 1.48333 T RK AD 00 0 1809 Europe/Andorra 1993-12-23
+3038967 Basers de les Tallades Basers de les Tallades 42.5 1.46667 T CLF AD 00 0 1678 Europe/Andorra 1993-12-23
+3038968 Bosc de la Tallada Nova Bosc de la Tallada Nova 42.58333 1.48333 V FRST AD 00 0 1809 Europe/Andorra 1993-12-23
+3038969 Camà de la Tallada Cami de la Tallada 42.48333 1.56667 R TRL AD 00 0 2231 Europe/Andorra 1993-12-23
+3038970 Canal del Tabanell Canal del Tabanell 42.56667 1.51667 H STM AD 00 0 1500 Europe/Andorra 1993-12-23
+3038971 Bosc del Tabanell Bosc del Tabanell 42.58333 1.5 V FRST AD 00 0 1595 Europe/Andorra 1993-12-23
+3038972 Suriguera Suriguera 42.58333 1.61667 T SLP AD 00 0 1707 Europe/Andorra 1993-12-23
+3038973 Sudornar Sudornar 42.58333 1.45 T SLP AD 00 0 2156 Europe/Andorra 1993-12-23
+3038974 Font del Sucre Font del Sucre 42.51667 1.46667 H SPNG AD 00 0 1840 Europe/Andorra 1993-12-23
+3038975 Costa de la Sucarana Costa de la Sucarana 42.6 1.5 T SLP AD 00 0 1923 Europe/Andorra 1993-12-23
+3038976 Canya de la Sucarana Canya de la Sucarana 42.6 1.5 T GRGE AD 00 0 1923 Europe/Andorra 1993-12-23
+3038977 Borda del Sucarana Borda del Sucarana 42.55 1.58333 S HUTS AD 00 0 1499 Europe/Andorra 1993-12-23
+3038978 Riu de Sorteny Riu de Sorteny 42.62341 1.54869 H STM AD 00 0 1950 Europe/Andorra 2011-04-19
+3038979 Pla de Sorteny Pla de Sorteny 42.61952 1.58872 T UPLD AD 00 0 2524 Europe/Andorra 2011-04-19
+3038980 Marrades de Sorteny Marrades de Sorteny 42.61667 1.55 R TRL AD 00 0 2007 Europe/Andorra 1993-12-23
+3038981 Sorteny Sorteny 42.61667 1.58333 A ADMD AD 00 0 2374 Europe/Andorra 1993-12-23
+3038982 Riu de les Soronelles Riu de les Soronelles 42.53333 1.65 H STM AD 00 0 2508 Europe/Andorra 1993-12-23
+3038983 Collada de les Soronelles Collada de les Soronelles 42.53333 1.65 T PASS AD 00 0 2508 Europe/Andorra 1993-12-23
+3038984 Pic de les Sorobilles Pic de les Sorobilles 42.56667 1.53333 T PK AD 00 0 1669 Europe/Andorra 1993-12-23
+3038985 Riu de Sornàs Riu de Sornas 42.56667 1.53333 H STM AD 00 0 1669 Europe/Andorra 1993-12-23
+3038986 Clot de Sornàs Clot de Sornas 42.56667 1.55 H RVN AD 00 0 1996 Europe/Andorra 1993-12-23
+3038987 Sornàs Sornas Sornas,Sornàs 42.5654 1.5287 P PPL AD 05 0 1514 Europe/Andorra 2011-11-05
+3038988 Riu de Soriguera Riu de Soriguera Riu de Soriguera,Riu de Suriguera 42.58333 1.61667 H STM AD AD 00 0 1707 Europe/Andorra 2011-11-05
+3038989 Solana del Soriguer Solana del Soriguer 42.56667 1.55 T SLP AD 00 0 1996 Europe/Andorra 1993-12-23
+3038990 Clot Sord Clot Sord 42.6 1.65 T CRQ AD 00 0 2131 Europe/Andorra 1993-12-23
+3038991 Solà de Soquer Sola de Soquer 42.45 1.48333 T SLP AD 00 0 1111 Europe/Andorra 1993-12-23
+3038992 Riu de Soplanàs Riu de Soplanas Riu de Soplanars,Riu de Soplanas,Riu de Soplanàs 42.58333 1.63333 H STM AD AD 00 0 1722 Europe/Andorra 2011-11-05
+3038993 Borda de Som Borda de Som 42.56667 1.58333 S HUTS AD 00 0 1919 Europe/Andorra 1993-12-23
+3038994 Roc de Solobre Roc de Solobre 42.48333 1.51667 T RKS AD 00 0 2061 Europe/Andorra 1993-12-23
+3038995 Bosc de Solobre Bosc de Solobre 42.48333 1.5 V FRST AD 00 0 1631 Europe/Andorra 1993-12-23
+3038996 Bosc del Soleador Bosc del Soleador 42.6 1.51667 V FRST AD 00 0 1445 Europe/Andorra 1993-12-23
+3038997 Camà de Soldeu Cami de Soldeu 42.58333 1.66667 R TRL AD 00 0 2159 Europe/Andorra 1993-12-23
+3038998 Bosc de Soldeu Bosc de Soldeu Bois de Soldeu,Bosc de Soldeu,Bosque de Soldeu 42.57107 1.65402 V FRST AD 00 0 1988 Europe/Andorra 2011-11-05
+3038999 Soldeu Soldeu 42.57688 1.66769 P PPL AD 02 0 2159 Europe/Andorra 2007-04-16
+3039000 Solana del Solanyó Solana del Solanyo 42.53333 1.55 T SLP AD 00 0 1344 Europe/Andorra 1993-12-23
+3039001 Riu del Solanyò Riu del Solanyo 42.53333 1.55 H STM AD 00 0 1344 Europe/Andorra 1993-12-23
+3039002 Bosc del Solanyó Bosc del Solanyo 42.55 1.45 V FRST AD 00 0 1788 Europe/Andorra 1993-12-23
+3039003 Barranc del Solanyó Barranc del Solanyo 42.55 1.45 H STM AD 00 0 1788 Europe/Andorra 1993-12-23
+3039004 Solans Solans 42.53333 1.6 L LCTY AD 00 0 1888 Europe/Andorra 1993-12-23
+3039005 Solanet de RÃ mio Solanet de Ramio 42.5 1.56667 L LCTY AD 00 0 1776 Europe/Andorra 1993-12-23
+3039006 Terregalls del Solanet Terregalls del Solanet 42.63333 1.6 T RDGE AD 00 0 2635 Europe/Andorra 1993-12-23
+3039007 Bosc del Solanet Bosc del Solanet 42.55 1.48333 V FRST AD 00 0 1548 Europe/Andorra 1993-12-23
+3039008 Solanes de la Peguera Solanes de la Peguera 42.45 1.51667 A ADMD AD 00 0 1790 Europe/Andorra 1993-12-23
+3039009 Serra de les Solanelles Serra de les Solanelles 42.55 1.66667 T RDGE AD 00 0 2224 Europe/Andorra 1993-12-23
+3039010 Riu de les Solanelles Riu de les Solanelles 42.55 1.68333 H STM AD 00 0 2254 Europe/Andorra 1993-12-23
+3039011 Collet de les Solanelles Collet de les Solanelles 42.55 1.61667 T PASS AD 00 0 2206 Europe/Andorra 1993-12-23
+3039012 Collada de les Solanelles Collada de les Solanelles 42.55 1.66667 T PASS AD 00 0 2224 Europe/Andorra 1993-12-23
+3039013 Clot de les Solanelles Clot de les Solanelles 42.55 1.63333 H RVN AD 00 0 2336 Europe/Andorra 1993-12-23
+3039014 Canal de les Solanelles Canal de les Solanelles 42.55 1.63333 H STM AD 00 0 2336 Europe/Andorra 1993-12-23
+3039015 Cabana de les Solanelles Cabana de les Solanelles 42.53333 1.66667 S HUT AD 00 0 2489 Europe/Andorra 1993-12-23
+3039016 Solanelles Solanelles 42.55 1.66667 L LCTY AD 00 0 2224 Europe/Andorra 1993-12-23
+3039017 Barranc de la Solana del Pas de la Casa Barranc de la Solana del Pas de la Casa 42.53333 1.73333 H STM AD 00 0 2300 Europe/Andorra 1993-12-23
+3039018 Solana del Lloser d’Ordino Solana del Lloser d'Ordino 42.55 1.51667 L LCTY AD 00 0 1397 Europe/Andorra 1993-12-23
+3039019 Riu de la Solana del Forn Riu de la Solana del Forn 42.56154 1.67948 H STM AD 00 0 2094 Europe/Andorra 2011-04-19
+3039020 Obagot de la Solana del Forn Obagot de la Solana del Forn 42.55 1.66667 T SLP AD 00 0 2224 Europe/Andorra 1993-12-23
+3039021 Solana del Forn Solana del Forn 42.55 1.66667 A ADMD AD 00 0 2224 Europe/Andorra 1993-12-23
+3039022 Solana de l’Estall Serrer Solana de l'Estall Serrer 42.5 1.61667 A ADMD AD 00 0 2560 Europe/Andorra 1993-12-23
+3039023 Solana de les Aubes Solana de les Aubes 42.56667 1.56667 L LCTY AD 00 0 2089 Europe/Andorra 1993-12-23
+3039024 Solana de la Baronia Solana de la Baronia 42.53333 1.61667 A ADMD AD 00 0 2237 Europe/Andorra 1993-12-23
+3039025 Prats de la Solana Prats de la Solana 42.56667 1.78333 L GRAZ AD 00 0 1680 Europe/Andorra 1993-12-23
+3039026 Camà de la Solana Cami de la Solana 42.43333 1.45 R TRL AD 00 0 877 Europe/Andorra 1993-12-23
+3039027 Bosc de la Solana Bosc de la Solana 42.51667 1.46667 V FRST AD 00 0 1840 Europe/Andorra 1993-12-23
+3039028 Solà de Soldeu Sola de Soldeu 42.58333 1.66667 A ADMD AD 00 0 2159 Europe/Andorra 1993-12-23
+3039029 Serra del Solà de Sispony Serra del Sola de Sispony 42.53333 1.48333 T MT AD 00 0 1677 Europe/Andorra 1993-12-23
+3039030 Pic del Solà d’Erts Pic del Sola d'Erts 42.56667 1.5 T PK AD 00 0 1636 Europe/Andorra 1993-12-23
+3039031 Solà d’Erts Sola d'Erts 42.56667 1.5 A ADMD AD 00 0 1636 Europe/Andorra 1993-12-23
+3039032 Solà de Riambert Sola de Riambert 42.58333 1.53333 A ADMD AD 00 0 1924 Europe/Andorra 1993-12-23
+3039033 Serra del Solà de Rà mio Serra del Sola de Ramio 42.5 1.58333 T MT AD 00 0 1888 Europe/Andorra 1993-12-23
+3039034 Solà de Rà mio Sola de Ramio 42.5 1.58333 A ADMD AD 00 0 1888 Europe/Andorra 1993-12-23
+3039035 Bosc del Solà d’Envalira Bosc del Sola d'Envalira 42.55 1.68333 V FRST AD 00 0 2254 Europe/Andorra 1993-12-23
+3039036 Carena del Solà d’Engordany Carena del Sola d'Engordany 42.51667 1.55 T RDGE AD 00 0 1322 Europe/Andorra 1993-12-23
+3039037 Solá d’Engordany Sola d'Engordany 42.51667 1.53333 A ADMD AD 00 0 1460 Europe/Andorra 1993-12-23
+3039038 Solà d’Enclar Sola d'Enclar 42.51667 1.48333 A ADMD AD 00 0 1839 Europe/Andorra 1993-12-23
+3039039 Solà d’Encamp Sola d'Encamp 42.53333 1.58333 A ADMD AD 00 0 1571 Europe/Andorra 1993-12-23
+3039040 Cresta del Solà de Nadal Cresta del Sola de Nadal 42.51667 1.51667 T SPUR AD 00 0 1265 Europe/Andorra 1993-12-23
+3039041 Aspres del Solà de Nadal Aspres del Sola de Nadal 42.51667 1.51667 V VINS AD 00 0 1265 Europe/Andorra 1993-12-23
+3039042 Solà de Mossers Sola de Mossers 42.45 1.46667 A ADMD AD 00 0 935 Europe/Andorra 1993-12-23
+3039043 Solà de Mereig Sola de Mereig 42.56667 1.58333 L LCTY AD 00 0 1919 Europe/Andorra 1993-12-23
+3039044 Solà del Tarter Sola del Tarter 42.58333 1.65 A ADMD AD 00 0 1767 Europe/Andorra 1993-12-23
+3039045 Solà dels Sulls Sola dels Sulls 42.48333 1.56667 A ADMD AD 00 0 2231 Europe/Andorra 1993-12-23
+3039046 Solà dels Plans Sola dels Plans 42.58333 1.63333 A ADMD AD 00 0 1722 Europe/Andorra 1993-12-23
+3039047 Serra del Sola del Quart Mitger Serra del Sola del Quart Mitger 42.55 1.55 T RDGE AD 00 0 2097 Europe/Andorra 1993-12-23
+3039048 Solà del Quart Mitger Sola del Quart Mitger 42.55 1.53333 A ADMD AD 00 0 1593 Europe/Andorra 1993-12-23
+3039049 Solà del Pui Sola del Pui 42.55 1.51667 A ADMD AD 00 0 1397 Europe/Andorra 1993-12-23
+3039050 Cap del Solà de les Comes Cap del Sola de les Comes 42.58333 1.5 T PK AD 00 0 1595 Europe/Andorra 1993-12-23
+3039051 Canal del Solà de les Comes Canal del Sola de les Comes 42.56667 1.48333 H STM AD 00 0 1508 Europe/Andorra 1993-12-23
+3039052 Solà de la Moixella Sola de la Moixella 42.45 1.48333 A ADMD AD 00 0 1111 Europe/Andorra 1993-12-23
+3039053 Balmes del Solà de l’Allau Balmes del Sola de l'Allau 42.6 1.53333 T CLF AD 00 0 1695 Europe/Andorra 1993-12-23
+3039054 Solà de l’Aldosa Sola de l'Aldosa 42.58333 1.61667 A ADMD AD 00 0 1707 Europe/Andorra 1993-12-23
+3039055 Solà de la Farga Sola de la Farga 42.48333 1.6 A ADMD AD 00 0 2250 Europe/Andorra 1993-12-23
+3039056 Canals del Solà de Juclar Canals del Sola de Juclar 42.6 1.7 H RVN AD 00 0 2354 Europe/Andorra 1993-12-23
+3039057 Solà d’Arcavell Sola d'Arcavell Sola d'Arcabell,Sola d'Arcavell,Sola d’Arcabell,Solà d’Arcavell 42.43333 1.48333 A ADMD AD 00 0 1228 Europe/Andorra 2011-11-05
+3039058 Solà d’Andorra Sola d'Andorra 42.51667 1.5 A ADMD AD 00 0 1688 Europe/Andorra 1993-12-23
+3039059 Solà d’Aixovall Sola d'Aixovall 42.48333 1.48333 A ADMD AD 00 0 981 Europe/Andorra 1993-12-23
+3039060 Riu del Solà Riu del Sola 42.55 1.46667 H STM AD 00 0 1585 Europe/Andorra 1993-12-23
+3039061 Clot del Solà Clot del Sola 42.46667 1.46667 H RVN AD 00 0 1340 Europe/Andorra 1993-12-23
+3039062 Carrera del Solà Carrera del Sola 42.53333 1.58333 R TRL AD 00 0 1571 Europe/Andorra 1993-12-23
+3039063 Costa del Sodorn Costa del Sodorn 42.5 1.46667 T SLP AD 00 0 1678 Europe/Andorra 1993-12-23
+3039064 Pla del Socarrat Pla del Socarrat 42.55 1.6 T UPLD AD 00 0 2210 Europe/Andorra 1993-12-23
+3039065 Camà del Socarrat Cami del Socarrat 42.58333 1.63333 R TRL AD 00 0 1722 Europe/Andorra 1993-12-23
+3039066 Bosc del Socarrat Bosc del Socarrat 42.58333 1.65 V FRST AD 00 0 1767 Europe/Andorra 1993-12-23
+3039067 Vial de la Socarrada de Coll Carnisser Vial de la Socarrada de Coll Carnisser 42.58333 1.46667 R RD AD 00 0 1643 Europe/Andorra 1993-12-23
+3039068 Pala de Sobre l’Estany Pala de Sobre l'Estany 42.61667 1.71667 T CLF AD 00 0 2352 Europe/Andorra 1993-12-23
+3039069 Pala de Sobre les Basses Pala de Sobre les Basses 42.58333 1.7 T SLP AD 00 0 2584 Europe/Andorra 1993-12-23
+3039070 Basers de Sobre la Pleta Basers de Sobre la Pleta 42.6 1.46667 T CLF AD 00 0 2421 Europe/Andorra 1993-12-23
+3039071 Sobre dels Camps de la Cortinada Sobre dels Camps de la Cortinada 42.58333 1.5 A ADMD AD 00 0 1595 Europe/Andorra 1993-12-23
+3039072 Planells Sobirans Planells Sobirans 42.58333 1.46667 T UPLD AD 00 0 1643 Europe/Andorra 1993-12-23
+3039073 Riu del Sisqueró Riu del Sisquero 42.6 1.7 H STM AD 00 0 2354 Europe/Andorra 1993-12-23
+3039074 Camà del Sisquero Cami del Sisquero 42.6 1.68333 R TRL AD 00 0 2089 Europe/Andorra 1993-12-23
+3039075 Solà de Sispony Sola de Sispony 42.53333 1.48333 T SLP AD 00 0 1677 Europe/Andorra 1993-12-23
+3039076 Camà de Sispony Cami de Sispony 42.53333 1.46667 R TRL AD 00 0 1846 Europe/Andorra 1993-12-23
+3039077 Sispony Sispony 42.53355 1.51481 P PPL AD 04 0 1252 Europe/Andorra 2011-04-19
+3039078 Pletes del Siscaró Pletes del Siscaro 42.58333 1.7 L GRAZ AD 00 0 2584 Europe/Andorra 1993-12-23
+3039079 Estanys del Siscaro Estanys del Siscaro 42.58333 1.7 H LKS AD 00 0 2584 Europe/Andorra 1993-12-23
+3039080 Canals del Siscaró Canals del Siscaro 42.58333 1.7 H RVN AD 00 0 2584 Europe/Andorra 1993-12-23
+3039081 Pic de Siscarou Pic de Siscarou Pic de Siscarou,Pico de Siscarou,Siscaro,Siscaró 42.6 1.73333 T PK AD 00 0 2383 Europe/Andorra 2011-11-05
+3039082 Siscaró Siscaro 42.58333 1.71667 A ADMD AD 00 0 2553 Europe/Andorra 1993-12-23
+3039083 Marrades del Siscar Marrades del Siscar 42.58333 1.71667 R TRL AD 00 0 2553 Europe/Andorra 1993-12-23
+3039084 Canals del Siscar Canals del Siscar 42.6 1.71667 H RVN AD 00 0 2516 Europe/Andorra 1993-12-23
+3039085 Basses del Siscar Basses del Siscar 42.58333 1.71667 H LKS AD 00 0 2553 Europe/Andorra 1993-12-23
+3039086 Sincloset Sincloset 42.48333 1.5 T MT AD 00 0 1631 Europe/Andorra 1993-12-23
+3039087 Port de Siguer Port de Siguer Port de Siguer 42.65 1.56667 T PASS AD 00 0 2471 Europe/Andorra 2011-11-05
+3039088 Bosc del Sigarró Bosc del Sigarro 42.51667 1.6 V FRST AD 00 0 2085 Europe/Andorra 1993-12-23
+3039089 Canal de la Sicalma Canal de la Sicalma 42.5 1.48333 H STM AD 00 0 1316 Europe/Andorra 1993-12-23
+3039090 Portella de Satut Portella de Satut Port de Setut,Portella de Satut,Portella de Setut 42.46667 1.63333 T PK AD 00 0 2619 Europe/Andorra 2011-11-05
+3039091 Cabana de Setut Cabana de Setut 42.48333 1.63333 S HUT AD 00 0 2296 Europe/Andorra 1993-12-23
+3039092 Basses de Setut Basses de Setut 42.48333 1.65 H LKS AD 00 0 2658 Europe/Andorra 1993-12-23
+3039093 Setut Setut 42.46667 1.65 A ADMD AD 00 0 2700 Europe/Andorra 1993-12-23
+3039094 Carretera de Setúria Carretera de Seturia 42.55 1.48333 R RD AD 00 0 1548 Europe/Andorra 1993-12-23
+3039095 Camà de Setúria Cami de Seturia 42.55 1.46667 R TRL AD 00 0 1585 Europe/Andorra 1993-12-23
+3039096 Bordes de Setúria Bordes de Seturia 42.53288 1.43718 S HUTS AD 00 0 1972 Europe/Andorra 2011-04-19
+3039097 Setúria Seturia 42.55 1.43333 A ADMD AD 00 0 1949 Europe/Andorra 1993-12-23
+3039098 Tarteres de la Serrera Tarteres de la Serrera 42.61667 1.58333 T TAL AD 00 0 2374 Europe/Andorra 1993-12-23
+3039099 Riu de la Serrera Riu de la Serrera 42.61667 1.56667 H STM AD 00 0 2228 Europe/Andorra 1993-12-23
+3039100 Pleta de la Serrera Pleta de la Serrera 42.61667 1.58333 L GRAZ AD 00 0 2374 Europe/Andorra 1993-12-23
+3039101 Pic de la Serrera Pic de la Serrera Pic de Serrere,Pic de Serrère,Pic de la Serrera,Serrera 42.63333 1.6 T PK AD 00 0 2635 Europe/Andorra 2011-11-05
+3039102 Pas de la Serrera Pas de la Serrera 42.61667 1.58333 T PASS AD 00 0 2374 Europe/Andorra 1993-12-23
+3039103 Clots de la Serrera Clots de la Serrera 42.61667 1.6 H STMH AD 00 0 2528 Europe/Andorra 1993-12-23
+3039104 Aspres de la Serrera Aspres de la Serrera 42.61667 1.6 V VINS AD 00 0 2528 Europe/Andorra 1993-12-23
+3039105 Canal de Serrats Canal de Serrats 42.53333 1.5 H STM AD 00 0 1357 Europe/Andorra 1993-12-23
+3039106 Camà del Serrat Pla Cami del Serrat Pla 42.43333 1.46667 R TRL AD 00 0 1113 Europe/Andorra 1993-12-23
+3039107 Bosc del Serrat Llong Bosc del Serrat Llong 42.51667 1.48333 V FRST AD 00 0 1839 Europe/Andorra 1993-12-23
+3039108 Planell del Serrat del Tronc Planell del Serrat del Tronc 42.58333 1.61667 T UPLD AD 00 0 1707 Europe/Andorra 1993-12-23
+3039109 Cabana del Serrat de la Barracota Cabana del Serrat de la Barracota 42.48333 1.63333 S HUT AD 00 0 2296 Europe/Andorra 1993-12-23
+3039110 Pic de Serra Seca Pic de Serra Seca 42.51667 1.7 T PK AD 00 0 2435 Europe/Andorra 1993-12-23
+3039111 Canal de Serra Plana Canal de Serra Plana 42.48333 1.48333 H STM AD 00 0 981 Europe/Andorra 1993-12-23
+3039112 Riu de Serrana Riu de Serrana 42.55 1.51667 H STM AD 00 0 1397 Europe/Andorra 1993-12-23
+3039113 Pic de Serra Mitjana Pic de Serra Mitjana 42.47479 1.61523 T PK AD 00 0 2418 Europe/Andorra 2011-04-19
+3039114 Estany de Serra Mitjana Estany de Serra Mitjana 42.46667 1.6 H LK AD 00 0 2449 Europe/Andorra 1993-12-23
+3039115 Canal Ampla de Serra Mitjana Canal Ampla de Serra Mitjana 42.46667 1.61667 H STM AD 00 0 2448 Europe/Andorra 1993-12-23
+3039116 Canal de la Serradora Canal de la Serradora 42.48333 1.46667 H STM AD 00 0 1148 Europe/Andorra 1993-12-23
+3039117 Canal Serradora Canal Serradora 42.5 1.56667 H STM AD 00 0 1776 Europe/Andorra 1993-12-23
+3039118 Cap de la Serra dels Isards Cap de la Serra dels Isards 42.58333 1.58333 T PK AD 00 0 1993 Europe/Andorra 1993-12-23
+3039119 Serrat dels Serradells Serrat dels Serradells 42.61667 1.53333 T SPUR AD 00 0 1609 Europe/Andorra 1993-12-23
+3039120 Cortal de la Serra Cortal de la Serra 42.53333 1.5 S CRRL AD 00 0 1357 Europe/Andorra 1993-12-23
+3039121 Cap de la Serra Cap de la Serra 42.61667 1.6 T RDGE AD 00 0 2528 Europe/Andorra 1993-12-23
+3039122 Roc de la Senyoreta Roc de la Senyoreta 42.45 1.48333 T RK AD 00 0 1111 Europe/Andorra 1993-12-23
+3039123 Bosc de la Senyoreta Bosc de la Senyoreta 42.45 1.48333 V FRST AD 00 0 1111 Europe/Andorra 1993-12-23
+3039124 Senyal Negre Senyal Negre 42.65 1.55 T MT AD 00 0 2181 Europe/Andorra 1993-12-23
+3039125 Senyal de Missa Senyal de Missa 42.46667 1.48333 T PK AD 00 0 1134 Europe/Andorra 1993-12-23
+3039126 Roc de Senders Roc de Senders 42.5 1.53333 T RK AD 00 0 1574 Europe/Andorra 1993-12-23
+3039127 Sella Sella 42.56667 1.6 T CLF AD 00 0 1655 Europe/Andorra 1993-12-23
+3039128 Riu del Seig Riu del Seig 42.56667 1.61667 H STM AD 00 0 1920 Europe/Andorra 1993-12-23
+3039129 Canal del Seig Canal del Seig 42.61667 1.53333 H STM AD 00 0 1609 Europe/Andorra 1993-12-23
+3039130 Solà de Segudet Sola de Segudet 42.56667 1.53333 T SLP AD 00 0 1669 Europe/Andorra 1993-12-23
+3039131 Riu de Segudet Riu de Segudet 42.5583 1.54304 H STM AD 00 0 1722 Europe/Andorra 2011-04-19
+3039132 Segudet Segudet Segudet 42.55755 1.53858 P PPL AD 05 0 1556 Europe/Andorra 2011-11-05
+3039133 Estany Segon Estany Segon 42.61667 1.73333 H LK AD 00 0 2508 Europe/Andorra 1993-12-23
+3039134 Torrent del Segalars Torrent del Segalars 42.55 1.58333 H STM AD 00 0 1499 Europe/Andorra 1993-12-23
+3039135 Camà de Sedornet Cami de Sedornet 42.58333 1.51667 R TRL AD 00 0 1722 Europe/Andorra 1993-12-23
+3039136 Bordes de Sedornet Bordes de Sedornet 42.58333 1.51667 S HUTS AD 00 0 1722 Europe/Andorra 1993-12-23
+3039137 Costa Seda Costa Seda 42.48333 1.5 T SLP AD 00 0 1631 Europe/Andorra 1993-12-23
+3039138 Planells Secants Planells Secants 42.43333 1.53333 T UPLD AD 00 0 2108 Europe/Andorra 1993-12-23
+3039139 Riu Sec Riu Sec 42.51667 1.46667 H STM AD 00 0 1840 Europe/Andorra 1993-12-23
+3039140 Estany Sec Estany Sec 42.46667 1.61667 H LK AD 00 0 2448 Europe/Andorra 1993-12-23
+3039141 Borda del Savoiano Borda del Savoiano 42.56667 1.51667 S HUTS AD 00 0 1500 Europe/Andorra 1993-12-23
+3039142 Serra de la Sauvata Serra de la Sauvata 42.56667 1.58333 T RDGE AD 00 0 1919 Europe/Andorra 1993-12-23
+3039143 Costa de la Sauvata Costa de la Sauvata 42.56667 1.58333 T SLP AD 00 0 1919 Europe/Andorra 1993-12-23
+3039144 Roc del Sastre Roc del Sastre Roc del Sastra,Roc del Sastre 42.58333 1.61667 T SPUR AD AD 00 0 1707 Europe/Andorra 2011-11-05
+3039145 Pont Sassanat Pont Sassanat 42.5 1.55 S BDG AD 00 0 1566 Europe/Andorra 1993-12-23
+3039146 Saquet Saquet 42.55 1.6 L LCTY AD 00 0 2210 Europe/Andorra 1993-12-23
+3039147 Roc de Sant Vicenç Roc de Sant Vicenc 42.5 1.5 T RK AD 00 0 1135 Europe/Andorra 1993-12-23
+3039148 Collet de Sant Vicenç Collet de Sant Vicenc 42.5 1.48333 T PASS AD 00 0 1316 Europe/Andorra 1993-12-23
+3039149 Solà de Santserra Sola de Santserra 42.48333 1.46667 T SLP AD 00 0 1148 Europe/Andorra 1993-12-23
+3039150 Sant Romà de Vila Sant Roma de Vila 42.53333 1.56667 S CH AD 00 0 1418 Europe/Andorra 1993-12-23
+3039151 Sant Romà de les Bons Sant Roma de les Bons 42.53333 1.58333 S CH AD 00 0 1571 Europe/Andorra 1993-12-23
+3039152 Bosc de Sant Romà Bosc de Sant Roma 42.45 1.5 V FRST AD 00 0 1614 Europe/Andorra 1993-12-23
+3039153 Sant Romà Sant Roma 42.45 1.5 S CH AD 00 0 1614 Europe/Andorra 1993-12-23
+3039154 Sant Pere Sant Pere Sant Pere 42.57952 1.65362 P PPL AD 02 0 1767 Europe/Andorra 2011-11-05
+3039155 Sant Miquel d'Engolasters Sant Miquel d'Engolasters Sant Miquel d'Engolasters 42.51094 1.56008 S CH AD AD 07 0 1661 Europe/Andorra 2007-04-05
+3039156 Sant Miquel de Fontaneda Sant Miquel de Fontaneda Sant Miquel,Sant Miquel de Fontaneda 42.45 1.46667 S CH AD AD 00 0 935 Europe/Andorra 2011-11-05
+3039157 Solà de Sant Miquel Sola de Sant Miquel 42.58333 1.66667 T SLP AD 00 0 2159 Europe/Andorra 1993-12-23
+3039158 Roc de Sant Miquel Roc de Sant Miquel 42.58333 1.66667 T CLF AD 00 0 2159 Europe/Andorra 1993-12-23
+3039159 Drecera de Sant Martà Drecera de Sant Marti 42.48333 1.5 R TRL AD 00 0 1631 Europe/Andorra 1993-12-23
+3039160 Sant Martà Sant Marti 42.48333 1.5 T UPLD AD 00 0 1631 Europe/Andorra 1993-12-23
+3039161 Sant Martà Sant Marti 42.48333 1.48333 S RUIN AD 00 0 981 Europe/Andorra 1993-12-23
+3039162 Parròquia de Sant Julià de Lòria Parroquia de Sant Julia de Loria Parroquia de Sant Julia de Loria,Parroquia de Sant Julià de Lòria,Sant Julia,Sant Julia de Loria,Sant Julià ,Sant Julià de Lòria 42.46247 1.48247 A ADM1 AD 06 9448 966 Europe/Andorra 2010-08-13
+3039163 Sant Julià de Lòria Sant Julia de Loria San Julia,San Julià ,San-Dzhulija-de-Lorija,San-Khulija-de-Lorija,Sant Julia de Loria,Sant Julià de Lòria,sheng hu li ya-de luo li ya,Сан-ДжулиÑ-де-ЛориÑ,Сан-ХулиÑ-де-ЛориÑ,サン・ジュリア・デ・ãƒãƒªã‚¢æ•™åŒº,圣胡利娅-德洛里亚,圣胡利娅ï¼å¾·æ´›é‡Œäºš 42.46372 1.49129 P PPLA AD 06 8022 1045 Europe/Andorra 2008-10-15
+3039164 Riu de Sant Josep Riu de Sant Josep 42.56419 1.75244 H STM AD 00 0 1836 Europe/Andorra 2011-04-19
+3039165 Clot de Sant Josep Clot de Sant Josep 42.56667 1.7 T CRQ AD 00 0 2375 Europe/Andorra 1993-12-23
+3039166 Sant Joan de Caselles Sant Joan de Caselles San Joan de Casettas,Sant Joan de Casellas,Sant Joan de Caselles 42.56988 1.60922 P PPL AD 02 0 1724 Europe/Andorra 2011-11-05
+3039167 Serrat de Sant Jaume Serrat de Sant Jaume 42.53333 1.6 T RDGE AD 00 0 1888 Europe/Andorra 1993-12-23
+3039168 Sant Jaume Sant Jaume 42.58333 1.63333 S CH AD 00 0 1722 Europe/Andorra 1993-12-23
+3039169 Sant Jaume Sant Jaume Sant Jaume,Sant Joums 42.53333 1.6 S CH AD AD 00 0 1888 Europe/Andorra 2011-11-05
+3039170 Sant Esteve Sant Esteve 42.43333 1.48333 S CH AD 00 0 1228 Europe/Andorra 1993-12-23
+3039171 Sant Esteve Sant Esteve 42.43333 1.45 S CH AD 00 0 877 Europe/Andorra 1993-12-23
+3039172 Sant Cristòfol Sant Cristofol 42.45 1.5 S SHRN AD 00 0 1614 Europe/Andorra 1993-12-23
+3039173 Sant Cristòfol Sant Cristofol 42.53333 1.53333 S CH AD 00 0 1521 Europe/Andorra 1993-12-23
+3039174 Solà de Sant Cerni Sola de Sant Cerni 42.46667 1.5 T SLP AD 00 0 1383 Europe/Andorra 1993-12-23
+3039175 Eglèsia de Sant Cerni Eglesia de Sant Cerni 42.56667 1.6 S CH AD 00 0 1655 Europe/Andorra 1993-12-23
+3039176 Sant Cerni Sant Cerni 42.46981 1.50133 S CH AD 00 0 1383 Europe/Andorra 2011-04-19
+3039177 Sant Antoni de la Grella Sant Antoni de la Grella 42.53333 1.53333 S CH AD 00 0 1521 Europe/Andorra 1993-12-23
+3039178 Túnels de Sant Antoni Tunels de Sant Antoni 42.51667 1.51667 R TNLS AD 00 0 1265 Europe/Andorra 1993-12-23
+3039179 Pont de Sant Antoni Pont de Sant Antoni 42.51667 1.51667 S BDG AD 00 0 1265 Europe/Andorra 1993-12-23
+3039180 Pont de Santa Creu Pont de Santa Creu 42.56667 1.6 S BDG AD 00 0 1655 Europe/Andorra 1993-12-23
+3039181 Santa Coloma Santa Coloma Santa Coloma 42.5 1.5 P PPL AD 07 0 1135 Europe/Andorra 2011-11-05
+3039182 Santa Caterina Santa Caterina 42.55 1.51667 L LCTY AD 00 0 1397 Europe/Andorra 1993-12-23
+3039183 Cortal del Sansa Cortal del Sansa 42.5 1.51667 S CRRL AD 00 0 1410 Europe/Andorra 1993-12-23
+3039184 Portella de Sanfons Portella de Sanfons Portella de Sanfons 42.56667 1.43333 T PASS AD 00 0 2402 Europe/Andorra 2011-11-05
+3039185 Pic de Sanfons Pic de Sanfons Pic de Sanfons 42.58333 1.43333 T PK AD 00 0 2412 Europe/Andorra 2011-11-05
+3039186 Roc de la Salve Roc de la Salve 42.53333 1.6 T RK AD 00 0 1888 Europe/Andorra 1993-12-23
+3039187 Bosc de la Salvata Bosc de la Salvata 42.45 1.51667 V FRST AD 00 0 1790 Europe/Andorra 1993-12-23
+3039188 Solana del Saltader Solana del Saltader 42.56667 1.53333 T SLP AD 00 0 1669 Europe/Andorra 1993-12-23
+3039189 Clot del Saltader Clot del Saltader 42.56667 1.46667 H RVN AD 00 0 1673 Europe/Andorra 1993-12-23
+3039190 Roc del Salt Roc del Salt 42.58333 1.58333 T RK AD 00 0 1993 Europe/Andorra 1993-12-23
+3039191 Clot del Salt Clot del Salt 42.58333 1.6 H RVN AD 00 0 1828 Europe/Andorra 1993-12-23
+3039192 Rius de les Salses Rius de les Salses 42.63333 1.5 H STM AD 00 0 1979 Europe/Andorra 1993-12-23
+3039193 Pont de les Salines Pont de les Salines 42.61667 1.53333 S BDG AD 00 0 1609 Europe/Andorra 1993-12-23
+3039194 Costa de les Salines Costa de les Salines 42.61667 1.53333 T SLP AD 00 0 1609 Europe/Andorra 1993-12-23
+3039195 Bosc de les Salines Bosc de les Salines 42.61667 1.53333 V FRST AD 00 0 1609 Europe/Andorra 1993-12-23
+3039196 Basses de les Salamandres Basses de les Salamandres 42.6 1.66667 H LKS AD 00 0 1858 Europe/Andorra 1993-12-23
+3039197 Costa de la Salamandra Costa de la Salamandra 42.55 1.43333 T SLP AD 00 0 1949 Europe/Andorra 1993-12-23
+3039198 Costa Salamandra Costa Salamandra 42.5 1.48333 T SLP AD 00 0 1316 Europe/Andorra 1993-12-23
+3039199 Roca de la Sabina Roca de la Sabina 42.56667 1.46667 T SLP AD 00 0 1673 Europe/Andorra 1993-12-23
+3039200 Cortal del Sabater Cortal del Sabater 42.45 1.48333 S CRRL AD 00 0 1111 Europe/Andorra 1993-12-23
+3039201 Bosc del Sabater Bosc del Sabater 42.45 1.48333 V FRST AD 00 0 1111 Europe/Andorra 1993-12-23
+3039202 Borda del Sabater Borda del Sabater 42.45 1.48333 S FRM AD 00 0 1111 Europe/Andorra 1993-12-23
+3039203 Canal dels Rulls Canal dels Rulls 42.48333 1.46667 H STM AD 00 0 1148 Europe/Andorra 1993-12-23
+3039204 Canal de Ruixol Canal de Ruixol 42.58333 1.51667 H STM AD 00 0 1722 Europe/Andorra 1993-12-23
+3039205 Torrent del Ruïder Torrent del Ruider 42.58333 1.48333 H STM AD 00 0 1809 Europe/Andorra 1993-12-23
+3039206 Roc del Ruïder Roc del Ruider 42.58333 1.48333 T SPUR AD 00 0 1809 Europe/Andorra 1993-12-23
+3039207 Pala del Ruf Pala del Ruf 42.58333 1.45 T SLP AD 00 0 2156 Europe/Andorra 1993-12-23
+3039208 Basses del Ruf Basses del Ruf 42.58333 1.45 H LKS AD 00 0 2156 Europe/Andorra 1993-12-23
+3039209 Serrat de Rudielles Serrat de Rudielles 42.5 1.45 T MT AD 00 0 1840 Europe/Andorra 1993-12-23
+3039210 Canal de Rudielles Canal de Rudielles 42.5 1.45 H STM AD 00 0 1840 Europe/Andorra 1993-12-23
+3039211 Vial de Rubials Vial de Rubials 42.48333 1.45 R RD AD 00 0 1195 Europe/Andorra 1993-12-23
+3039212 Torrent de Rubials Torrent de Rubials 42.48333 1.45 H STM AD 00 0 1195 Europe/Andorra 1993-12-23
+3039213 Solana de Rubials Solana de Rubials 42.48333 1.45 T SLP AD 00 0 1195 Europe/Andorra 1993-12-23
+3039214 Rua del Terrer Roi Rua del Terrer Roi 42.43333 1.5 L LCTY AD 00 0 1804 Europe/Andorra 1993-12-23
+3039215 Bosc de Roures Bosc de Roures 42.6 1.51667 V FRST AD 00 0 1445 Europe/Andorra 1993-12-23
+3039216 Collet de Roques Negres Collet de Roques Negres 42.45 1.45 T PASS AD 00 0 1482 Europe/Andorra 1993-12-23
+3039217 Roques Negres Roques Negres 42.45 1.45 L LCTY AD 00 0 1482 Europe/Andorra 1993-12-23
+3039218 Serrat de Roques Grosses Serrat de Roques Grosses 42.58333 1.6 T RDGE AD 00 0 1828 Europe/Andorra 1993-12-23
+3039219 Canal de Roques Blanques Canal de Roques Blanques 42.5 1.48333 H STM AD 00 0 1316 Europe/Andorra 1993-12-23
+3039220 Fontanal de les Roques Fontanal de les Roques 42.53333 1.46667 H SPNG AD 00 0 1846 Europe/Andorra 1993-12-23
+3039221 Pleta de les Romes Pleta de les Romes 42.65 1.55 L GRAZ AD 00 0 2181 Europe/Andorra 1993-12-23
+3039222 Font Roja Font Roja 42.55 1.45 H SPNG AD 00 0 1788 Europe/Andorra 1993-12-23
+3039223 Font Roja Font Roja 42.48333 1.5 H SPNG AD 00 0 1631 Europe/Andorra 1993-12-23
+3039224 Bassa Roja Bassa Roja 42.6 1.66667 H LK AD 00 0 1858 Europe/Andorra 1993-12-23
+3039225 Grau Roig Grau Roig 42.58333 1.46667 T SLP AD 00 0 1643 Europe/Andorra 1993-12-23
+3039226 Borda de Roig Borda de Roig 42.56667 1.58333 S HUT AD 00 0 1919 Europe/Andorra 1993-12-23
+3039227 Fonts Roges Fonts Roges 42.56667 1.46667 H SPNG AD 00 0 1673 Europe/Andorra 1993-12-23
+3039228 Fonts Roges Fonts Roges 42.55 1.65 H SPNG AD 00 0 2432 Europe/Andorra 1993-12-23
+3039229 Canals Roges Canals Roges 42.58333 1.71667 H RVN AD 00 0 2553 Europe/Andorra 1993-12-23
+3039230 Basses Roges Basses Roges 42.46667 1.55 H LKS AD 00 0 2341 Europe/Andorra 1993-12-23
+3039231 Font Rodona Font Rodona 42.55 1.41667 H SPNG AD 00 0 2105 Europe/Andorra 1993-12-23
+3039232 Costa Rodona Costa Rodona 42.65 1.48333 T SLP AD 00 0 2341 Europe/Andorra 1993-12-23
+3039233 Costa Rodona Costa Rodona 42.58333 1.45 T SLP AD 00 0 2156 Europe/Andorra 1993-12-23
+3039234 Costa Rodona Costa Rodona 42.55 1.71667 T SLP AD 00 0 2192 Europe/Andorra 1993-12-23
+3039235 Boïga Rodona Boiga Rodona 42.43333 1.53333 V CULT AD 00 0 2108 Europe/Andorra 1993-12-23
+3039236 Bosc del Ródol Bosc del Rodol 42.48882 1.57683 V FRST AD 00 0 2246 Europe/Andorra 2011-04-19
+3039237 Turó Rodó Turo Rodo 42.56667 1.55 T PK AD 00 0 1996 Europe/Andorra 1993-12-23
+3039238 Roc Rodó Roc Rodo 42.56667 1.48333 T SPUR AD 00 0 1508 Europe/Andorra 1993-12-23
+3039239 Roc Rodó Roc Rodo 42.56667 1.43333 T SPUR AD 00 0 2402 Europe/Andorra 1993-12-23
+3039240 Pla de Rodó Pla de Rodo 42.55 1.43333 T UPLD AD 00 0 1949 Europe/Andorra 1993-12-23
+3039241 Estany Rodó Estany Rodo 42.51667 1.68333 H LK AD 00 0 2352 Europe/Andorra 1993-12-23
+3039242 Estany Rodó Estany Rodo 42.5 1.65 H LK AD 00 0 2542 Europe/Andorra 1993-12-23
+3039243 Bony Rodó Bony Rodo 42.61667 1.55 T SPUR AD 00 0 2007 Europe/Andorra 1993-12-23
+3039244 Rocs Tous Rocs Tous 42.55 1.58333 L LCTY AD 00 0 1499 Europe/Andorra 1993-12-23
+3039245 Rocs Negres Rocs Negres 42.53333 1.61667 A ADMD AD 00 0 2237 Europe/Andorra 1993-12-23
+3039246 Planell del Roc Gros Planell del Roc Gros 42.58333 1.48333 T UPLD AD 00 0 1809 Europe/Andorra 1993-12-23
+3039247 Bosc del Roc Gros Bosc del Roc Gros 42.58333 1.48333 V FRST AD 00 0 1809 Europe/Andorra 1993-12-23
+3039248 Serra del Roc del Rellotge Serra del Roc del Rellotge 42.61667 1.58333 T MT AD 00 0 2374 Europe/Andorra 1993-12-23
+3039249 Font del Roc del Porquer Font del Roc del Porquer 42.6 1.45 H SPNG AD 00 0 2174 Europe/Andorra 1993-12-23
+3039250 Canal del Roc de la Grael Canal del Roc de la Grael 42.51667 1.53333 H STM AD 00 0 1460 Europe/Andorra 1993-12-23
+3039251 Roca Podrida Roca Podrida 42.55 1.51667 L LCTY AD 00 0 1397 Europe/Andorra 1993-12-23
+3039252 Costa de Roca Negra Costa de Roca Negra 42.58333 1.58333 T SLP AD 00 0 1993 Europe/Andorra 1993-12-23
+3039253 Canal de Rocanegra Canal de Rocanegra 42.5 1.46667 H STM AD 00 0 1678 Europe/Andorra 1993-12-23
+3039254 Canal de Roca Major Canal de Roca Major 42.43333 1.5 H RVN AD 00 0 1804 Europe/Andorra 1993-12-23
+3039255 Planell de la Roca Grossa Planell de la Roca Grossa 42.56667 1.7 T UPLD AD 00 0 2375 Europe/Andorra 1993-12-23
+3039256 Planell de Roca Grossa Planell de Roca Grossa 42.55 1.66667 T UPLD AD 00 0 2224 Europe/Andorra 1993-12-23
+3039257 Canal de Rocafort Canal de Rocafort 42.46667 1.48333 H STM AD 00 0 1134 Europe/Andorra 1993-12-23
+3039258 Rocafort Rocafort 42.46667 1.48333 A ADMD AD 00 0 1134 Europe/Andorra 1993-12-23
+3039259 Solana de la Roca de la Sabina Solana de la Roca de la Sabina 42.56667 1.46667 T SLP AD 00 0 1673 Europe/Andorra 1993-12-23
+3039260 Canal de la Roca Blanca Canal de la Roca Blanca 42.51667 1.51667 H STM AD 00 0 1265 Europe/Andorra 1993-12-23
+3039261 Vial de la Roca Vial de la Roca 42.55 1.6 R RD AD 00 0 2210 Europe/Andorra 1993-12-23
+3039262 Pala de la Roca Pala de la Roca 42.55 1.61667 T SLP AD 00 0 2206 Europe/Andorra 1993-12-23
+3039263 Bosc de la Roca Bosc de la Roca 42.55 1.46667 V FRST AD 00 0 1585 Europe/Andorra 1993-12-23
+3039264 Pont del Riu Montaner Pont del Riu Montaner 42.53333 1.51667 S BDG AD 00 0 1361 Europe/Andorra 1993-12-23
+3039265 Camà del Riu del Seig Cami del Riu del Seig 42.56667 1.6 R TRL AD 00 0 1655 Europe/Andorra 1993-12-23
+3039266 Riu del Seig Riu del Seig 42.56667 1.61667 A ADMD AD 00 0 1920 Europe/Andorra 1993-12-23
+3039267 Forat del Riu dels Clots de Massat Forat del Riu dels Clots de Massat 42.55 1.68333 H RVN AD 00 0 2254 Europe/Andorra 1993-12-23
+3039268 Fonts del Riu de les Cebes Fonts del Riu de les Cebes 42.61667 1.58333 H SPNG AD 00 0 2374 Europe/Andorra 1993-12-23
+3039269 Costa del Riu de les Cebes Costa del Riu de les Cebes 42.61667 1.58333 T SLP AD 00 0 2374 Europe/Andorra 1993-12-23
+3039270 Collada del Riu de les Cebes Collada del Riu de les Cebes 42.61667 1.58333 T SPUR AD 00 0 2374 Europe/Andorra 1993-12-23
+3039271 Bony del Riu de les Cebes Bony del Riu de les Cebes 42.61667 1.58333 T RK AD 00 0 2374 Europe/Andorra 1993-12-23
+3039272 Prats del Riu Prats del Riu 42.46667 1.5 L GRAZ AD 00 0 1383 Europe/Andorra 1993-12-23
+3039273 Canal de Rita Canal de Rita 42.53333 1.6 H STM AD 00 0 1888 Europe/Andorra 1993-12-23
+3039274 Solà del Riguer Sola del Riguer 42.5 1.55 T SLP AD 00 0 1566 Europe/Andorra 1993-12-23
+3039275 Obaga del Riguer Obaga del Riguer 42.48333 1.53333 T SLP AD 00 0 2255 Europe/Andorra 1993-12-23
+3039276 Bordes de Rigoder Bordes de Rigoder 42.53333 1.61667 S HUTS AD 00 0 2237 Europe/Andorra 1993-12-23
+3039277 Bosc de les Ribes Bosc de les Ribes 42.55 1.55 V FRST AD 00 0 2097 Europe/Andorra 1993-12-23
+3039278 Riberal d’Envalira Riberal d'Envalira 42.53333 1.7 L LCTY AD 00 0 2357 Europe/Andorra 1993-12-23
+3039279 Canals de Ribera Canals de Ribera 42.43333 1.48333 H STM AD 00 0 1228 Europe/Andorra 1993-12-23
+3039280 Ribassot Ribassot 42.58333 1.48333 L LCTY AD 00 0 1809 Europe/Andorra 1993-12-23
+3039281 Torrent de Ribassols Torrent de Ribassols 42.58333 1.48333 H STM AD 00 0 1809 Europe/Andorra 1993-12-23
+3039282 Torrent Ribal Torrent Ribal 42.58333 1.48333 H STM AD 00 0 1809 Europe/Andorra 1993-12-23
+3039283 Tosa de Riba Escorjada Tosa de Riba Escorjada 42.55 1.65 T UPLD AD 00 0 2432 Europe/Andorra 1993-12-23
+3039284 Solanelles de Riba Escorjada Solanelles de Riba Escorjada 42.55 1.63333 T SLP AD 00 0 2336 Europe/Andorra 1993-12-23
+3039285 Planells de Riba Escorjada Planells de Riba Escorjada 42.56667 1.63333 T UPLD AD 00 0 2016 Europe/Andorra 1993-12-23
+3039286 Camà de Riba Escorjada Cami de Riba Escorjada 42.56667 1.63333 R TRL AD 00 0 2016 Europe/Andorra 1993-12-23
+3039287 Camà de Riba Escorjada Cami de Riba Escorjada 42.55 1.6 R TRL AD 00 0 2210 Europe/Andorra 1993-12-23
+3039288 Riba Escorjada Riba Escorjada 42.55 1.63333 A ADMD AD 00 0 2336 Europe/Andorra 1993-12-23
+3039289 Bosc de Riba Bosc de Riba 42.55 1.58333 V FRST AD 00 0 1499 Europe/Andorra 1993-12-23
+3039290 Bosc del Riambert Bosc del Riambert 42.56667 1.51667 V FRST AD 00 0 1500 Europe/Andorra 1993-12-23
+3039291 Riu de Rialb Riu de Rialb Riu de Rialb,Riu de Rialp 42.61667 1.53333 H STM AD AD 00 0 1609 Europe/Andorra 2011-11-05
+3039292 Portella de Rialb Portella de Rialb 42.63333 1.53333 T PASS AD 00 0 2072 Europe/Andorra 1993-12-23
+3039293 Basera de Rialb Basera de Rialb 42.65 1.56667 T CLF AD 00 0 2471 Europe/Andorra 1993-12-23
+3039294 Rialb Rialb 42.65 1.55 A ADMD AD 00 0 2181 Europe/Andorra 1993-12-23
+3039295 Pala de Rep Pala de Rep 42.55 1.6 T SLP AD 00 0 2210 Europe/Andorra 1993-12-23
+3039296 Coll del Rep Coll del Rep 42.45 1.46667 T PASS AD 00 0 935 Europe/Andorra 1993-12-23
+3039297 Cap de Rep Cap de Rep Cap de Rep,Cap de l' Ovella,Cap de l’ Ovella 42.54325 1.61092 T PK AD 00 0 2213 Europe/Andorra 2011-11-05
+3039298 Rep Rep 42.53333 1.58333 A ADMD AD 00 0 1571 Europe/Andorra 1993-12-23
+3039299 Roc del Rellotge Roc del Rellotge 42.61667 1.56667 T SPUR AD 00 0 2228 Europe/Andorra 1993-12-23
+3039300 Roc del Rellotge Roc del Rellotge 42.56667 1.61667 T RK AD 00 0 1920 Europe/Andorra 1993-12-23
+3039301 Font de les Reïneres Font de les Reineres 42.6 1.68333 H SPNG AD 00 0 2089 Europe/Andorra 1993-12-23
+3039302 Solana de la RegalÃssia Solana de la Regalissia 42.48333 1.41667 T SLP AD 00 0 1920 Europe/Andorra 1993-12-23
+3039303 Obaga de Redort Obaga de Redort 42.55 1.56667 T SLP AD 00 0 1828 Europe/Andorra 1993-12-23
+3039304 Redort Redort 42.56667 1.55 L LCTY AD 00 0 1996 Europe/Andorra 1993-12-23
+3039305 Clot de la Rectoria Clot de la Rectoria 42.51667 1.5 H RVN AD 00 0 1688 Europe/Andorra 1993-12-23
+3039306 Serrat del Rec d’Areny Serrat del Rec d'Areny 42.58333 1.46667 T SPUR AD 00 0 1643 Europe/Andorra 1993-12-23
+3039307 Bosc de Rèbols Bosc de Rebols 42.46667 1.51667 V FRST AD 00 0 1985 Europe/Andorra 1993-12-23
+3039308 Pont de la Rebollissa Pont de la Rebollissa 42.61667 1.53333 S BDG AD 00 0 1609 Europe/Andorra 1993-12-23
+3039309 Llanesques de les Rebes Llanesques de les Rebes 42.63333 1.61667 T CLF AD 00 0 2541 Europe/Andorra 1993-12-23
+3039310 Clot de les Rebes Clot de les Rebes 42.61667 1.61667 H RVN AD 00 0 2352 Europe/Andorra 1993-12-23
+3039311 Rebaixant del Maià Rebaixant del Maia 42.56667 1.73333 L LCTY AD 00 0 2096 Europe/Andorra 1993-12-23
+3039312 Canal de la Rata Canal de la Rata 42.58333 1.46667 H RVN AD 00 0 1643 Europe/Andorra 1993-12-23
+3039313 Port de Rat Port de Rat Port de Rat,Port de Rat du D'Auzat 42.62127 1.47371 T PASS AD FR,AD 07 0 2442 Europe/Andorra 2007-03-04
+3039314 Bosc de Rasets Bosc de Rasets 42.43333 1.53333 V FRST AD 00 0 2108 Europe/Andorra 1993-12-23
+3039315 Rasa de Perafita Rasa de Perafita 42.48333 1.58333 T UPLD AD 00 0 2349 Europe/Andorra 1993-12-23
+3039316 Costa Rasa Costa Rasa 42.46667 1.45 T SLP AD 00 0 1562 Europe/Andorra 1993-12-23
+3039317 Bosc de la Rasa Bosc de la Rasa 42.46667 1.53333 V FRST AD 00 0 2332 Europe/Andorra 1993-12-23
+3039318 Presa de Ransol Presa de Ransol 42.58333 1.63333 S DAM AD 00 0 1722 Europe/Andorra 1993-12-23
+3039319 Carretera de Ransol Carretera de Ransol 42.58333 1.65 R RD AD 00 0 1767 Europe/Andorra 1993-12-23
+3039320 Ransol Ransol 42.58137 1.63812 P PPL AD 02 0 1727 Europe/Andorra 2007-04-16
+3039321 Roca de RÃ mio Roca de Ramio 42.5 1.56667 T RK AD 00 0 1776 Europe/Andorra 1993-12-23
+3039322 RÃ mio Ramio 42.49702 1.57414 S HUTS AD 00 0 1776 Europe/Andorra 2011-04-19
+3039323 Canal del Ramer Canal del Ramer 42.56667 1.48333 H RVN AD 00 0 1508 Europe/Andorra 1993-12-23
+3039324 Canal de la Ramenada Canal de la Ramenada 42.5 1.51667 H STM AD 00 0 1410 Europe/Andorra 1993-12-23
+3039325 Camà Ral Cami Ral 42.55 1.58333 R TRL AD 00 0 1499 Europe/Andorra 1993-12-23
+3039326 Camà Ral Cami Ral 42.53333 1.58333 R TRL AD 00 0 1571 Europe/Andorra 1993-12-23
+3039327 Radonella Radonella 42.48333 1.45 L LCTY AD 00 0 1195 Europe/Andorra 1993-12-23
+3039328 Rádio Andorra Radio Andorra 42.5282 1.57019 S STNR AD 00 0 1418 Europe/Andorra 2011-04-19
+3039329 Racons Racons 42.56667 1.58333 A ADMD AD 00 0 1919 Europe/Andorra 1993-12-23
+3039330 Pic de la Raconada de la Maiana Pic de la Raconada de la Maiana Pic de la Raconada de la Maiana 42.46667 1.61667 T PK AD 00 0 2448 Europe/Andorra 2011-11-05
+3039331 Clots de la Raconada de la Maiana Clots de la Raconada de la Maiana 42.46667 1.6 T CRQS AD 00 0 2449 Europe/Andorra 1993-12-23
+3039332 Pic de Racofred Pic de Racofred Pic de Racofred,Pic de Racofret 42.6 1.45 T PK AD 00 0 2174 Europe/Andorra 2011-11-05
+3039333 Racó de l’Estany de Cabana Sorda Raco de l'Estany de Cabana Sorda 42.61667 1.66667 L LCTY AD 00 0 2536 Europe/Andorra 1993-12-23
+3039334 Pleta del Racó Pleta del Raco 42.61667 1.56667 L GRAZ AD 00 0 2228 Europe/Andorra 1993-12-23
+3039335 Pleta del Racó Pleta del Raco 42.58333 1.45 L GRAZ AD 00 0 2156 Europe/Andorra 1993-12-23
+3039336 Canal del Racó Canal del Raco 42.56667 1.48333 H RVN AD 00 0 1508 Europe/Andorra 1993-12-23
+3039337 Bassa del Racó Bassa del Raco 42.61667 1.5 H LK AD 00 0 2390 Europe/Andorra 1993-12-23
+3039338 Pleta de la Rabassa Pleta de la Rabassa 42.63333 1.55 L GRAZ AD 00 0 2053 Europe/Andorra 1993-12-23
+3039339 Carretera de la Rabassa Carretera de la Rabassa 42.43333 1.51667 R RD AD 00 0 2031 Europe/Andorra 1993-12-23
+3039340 Canya de la Rabassa Canya de la Rabassa 42.63333 1.55 S CAVE AD 00 0 2053 Europe/Andorra 1993-12-23
+3039341 Bosc de la Rabassa Bosc de la Rabassa 42.4379 1.51425 V FRST AD 00 0 1990 Europe/Andorra 2011-04-19
+3039342 Solana del Querol Solana del Querol 42.58333 1.53333 T SLP AD 00 0 1924 Europe/Andorra 1993-12-23
+3039343 Riu del Querol Riu del Querol 42.58333 1.66667 H STM AD 00 0 2159 Europe/Andorra 1993-12-23
+3039344 Riu del Querol Riu del Querol 42.58333 1.53333 H STM AD 00 0 1924 Europe/Andorra 1993-12-23
+3039345 Pleta del Querol Pleta del Querol 42.6 1.66667 L GRAZ AD 00 0 1858 Europe/Andorra 1993-12-23
+3039346 Estanyó del Querol Estanyo del Querol 42.61303 1.67019 H LK AD 00 0 2355 Europe/Andorra 2011-04-19
+3039347 Serrat de la Quera Serrat de la Quera 42.51667 1.51667 T RDGE AD 00 0 1265 Europe/Andorra 1993-12-23
+3039348 Canal Gran de la Quera Canal Gran de la Quera 42.45 1.46667 H STM AD 00 0 935 Europe/Andorra 1993-12-23
+3039349 Bosc de la Quera Bosc de la Quera 42.51667 1.51667 V FRST AD 00 0 1265 Europe/Andorra 1993-12-23
+3039350 Roc del Quer Roc del Quer 42.61667 1.55 T SPUR AD 00 0 2007 Europe/Andorra 1993-12-23
+3039351 Roc del Quer Roc del Quer 42.55 1.51667 T SPUR AD 00 0 1397 Europe/Andorra 1993-12-23
+3039352 Roc del Quer Roc del Quer 42.58333 1.48333 T RK AD 00 0 1809 Europe/Andorra 1993-12-23
+3039353 Roc del Quer Roc del Quer 42.52798 1.60146 T RK AD 00 0 1888 Europe/Andorra 2011-04-19
+3039354 Roc del Quer Roc del Quer 42.56667 1.6 T CLF AD 00 0 1655 Europe/Andorra 1993-12-23
+3039355 Roc de Quer Roc de Quer 42.48333 1.46667 T RK AD 00 0 1148 Europe/Andorra 1993-12-23
+3039356 Planell del Quer Planell del Quer 42.63333 1.56667 T UPLD AD 00 0 2394 Europe/Andorra 1993-12-23
+3039357 Canal del Quer Canal del Quer 42.63333 1.55 H RVN AD 00 0 2053 Europe/Andorra 1993-12-23
+3039358 Canal del Quer Canal del Quer 42.51667 1.6 H RVN AD 00 0 2085 Europe/Andorra 1993-12-23
+3039359 Bosc del Quer Bosc del Quer 42.51667 1.6 V FRST AD 00 0 2085 Europe/Andorra 1993-12-23
+3039360 Solà del Quart de Nagol Sola del Quart de Nagol 42.48333 1.51667 T SLP AD 00 0 2061 Europe/Andorra 1993-12-23
+3039361 Collet Purgat Collet Purgat 42.46667 1.48333 T PK AD 00 0 1134 Europe/Andorra 1993-12-23
+3039363 Pont de Puntal Pont de Puntal 42.61667 1.55 S BDG AD 00 0 2007 Europe/Andorra 1993-12-23
+3039364 Bosc de Puntal Bosc de Puntal 42.63333 1.55 V FRST AD 00 0 2053 Europe/Andorra 1993-12-23
+3039365 Puntal Puntal 42.63333 1.55 L LCTY AD 00 0 2053 Europe/Andorra 1993-12-23
+3039366 Vial dels Pujols Vial dels Pujols 42.48333 1.48333 R RD AD 00 0 981 Europe/Andorra 1993-12-23
+3039367 Tarteres dels Pujols Tarteres dels Pujols 42.48333 1.48333 T TAL AD 00 0 981 Europe/Andorra 1993-12-23
+3039368 Roc del Pujol Roc del Pujol 42.46667 1.5 T RK AD 00 0 1383 Europe/Andorra 1993-12-23
+3039369 Pujant de Donges Pujant de Donges 42.45 1.5 L LCTY AD 00 0 1614 Europe/Andorra 1993-12-23
+3039370 Puiol del Piu Puiol del Piu 42.56667 1.5 P PPL AD 04 0 1636 Europe/Andorra 1993-12-23
+3039371 Borda del Puigcernal Borda del Puigcernal 42.55 1.58333 S HUT AD 00 0 1499 Europe/Andorra 1993-12-23
+3039372 Pui d’Olivesa Pui d'Olivesa 42.45 1.48333 L LCTY AD 00 0 1111 Europe/Andorra 1993-12-23
+3039373 Pui d’Encamp Pui d'Encamp 42.53333 1.56667 L LCTY AD 00 0 1418 Europe/Andorra 1993-12-23
+3039374 Estany Primer Estany Primer 42.63721 1.49019 H LK AD 05 0 2254 Europe/Andorra 2010-01-12
+3039375 Estany Primer Estany Primer 42.61667 1.71667 H LK AD 00 0 2352 Europe/Andorra 1993-12-23
+3039376 Estany Primer Estany Primer 42.51667 1.68333 H LK AD 00 0 2352 Europe/Andorra 1993-12-23
+3039377 Canal de la Presa Canal de la Presa 42.58333 1.63333 H CNL AD 00 0 1722 Europe/Andorra 1993-12-23
+3039378 Canal de la Premsa Canal de la Premsa 42.46667 1.48333 H STM AD 00 0 1134 Europe/Andorra 1993-12-23
+3039379 Canal Pregona Canal Pregona 42.56667 1.48333 H STM AD 00 0 1508 Europe/Andorra 1993-12-23
+3039380 Canal Pregona Canal Pregona 42.55 1.5 H STM AD 00 0 1292 Europe/Andorra 1993-12-23
+3039381 Torrent Pregó Torrent Prego 42.53333 1.58333 H STM AD 00 0 1571 Europe/Andorra 1993-12-23
+3039382 Bosc dels Prats Sobirans Bosc dels Prats Sobirans 42.51667 1.46667 V FRST AD 00 0 1840 Europe/Andorra 1993-12-23
+3039383 Planells dels Prats Nous Planells dels Prats Nous 42.58333 1.48333 T UPLD AD 00 0 1809 Europe/Andorra 1993-12-23
+3039384 Bordes dels Prats Nous Bordes dels Prats Nous 42.58333 1.48333 S HUTS AD 00 0 1809 Europe/Andorra 1993-12-23
+3039385 Riu de Prats Riu de Prats 42.55 1.58333 H STM AD 00 0 1499 Europe/Andorra 1993-12-23
+3039386 Prats Prats 42.56003 1.59396 P PPL AD 02 0 1677 Europe/Andorra 2007-04-16
+3039387 Solana de Prat Primer Solana de Prat Primer 42.48333 1.55 T SLP AD 00 0 2233 Europe/Andorra 1993-12-23
+3039388 Planell de Prat Primer Planell de Prat Primer 42.48333 1.55 T UPLD AD 00 0 2233 Europe/Andorra 1993-12-23
+3039389 Obaga de Prat Primer Obaga de Prat Primer 42.48333 1.55 T SLP AD 00 0 2233 Europe/Andorra 1993-12-23
+3039390 Font de Prat Primer Font de Prat Primer 42.48333 1.55 H SPNG AD 00 0 2233 Europe/Andorra 1993-12-23
+3039391 Collada de Prat Primer Collada de Prat Primer 42.46667 1.55 T PASS AD 00 0 2341 Europe/Andorra 1993-12-23
+3039392 Clots de Prat Primer Clots de Prat Primer 42.48333 1.55 H RVN AD 00 0 2233 Europe/Andorra 1993-12-23
+3039393 Prat Primer Prat Primer 42.48333 1.55 A ADMD AD 00 0 2233 Europe/Andorra 1993-12-23
+3039394 Collada de Prat Porceller Collada de Prat Porceller Collada de Prat Porceller 42.46667 1.45 T PASS AD 00 0 1562 Europe/Andorra 2011-11-05
+3039395 Font del Prat de Roca Font del Prat de Roca 42.56667 1.58333 H SPNG AD 00 0 1919 Europe/Andorra 1993-12-23
+3039396 Font del Prat dels Pollins Font del Prat dels Pollins 42.56667 1.58333 H SPNG AD 00 0 1919 Europe/Andorra 1993-12-23
+3039397 Basers del Prat del Quart Basers del Prat del Quart 42.61667 1.63333 T CLF AD 00 0 2331 Europe/Andorra 1993-12-23
+3039398 Font del Prat del Jep Font del Prat del Jep Font del Prat del Gep,Font del Prat del Jep 42.56667 1.58333 H SPNG AD AD 00 0 1919 Europe/Andorra 2011-11-05
+3039399 Torrent del Prat del Gaspar Torrent del Prat del Gaspar 42.53333 1.56667 H STM AD 00 0 1418 Europe/Andorra 1993-12-23
+3039400 Bosc del Prat de l’Estel Bosc del Prat de l'Estel 42.53333 1.46667 V FRST AD 00 0 1846 Europe/Andorra 1993-12-23
+3039401 Riu del Prat del Comellar Riu del Prat del Comellar 42.58333 1.65 H STM AD 00 0 1767 Europe/Andorra 1993-12-23
+3039402 Solana del Prat del Bosc Solana del Prat del Bosc 42.58333 1.46667 T SLP AD 00 0 1643 Europe/Andorra 1993-12-23
+3039403 Riu del Prat del Bosc Riu del Prat del Bosc 42.55 1.48333 H STM AD 00 0 1548 Europe/Andorra 1993-12-23
+3039404 Pont del Prat del Bosc Pont del Prat del Bosc 42.53333 1.46667 S BDG AD 00 0 1846 Europe/Andorra 1993-12-23
+3039405 Bosc del Prat del Bosc Bosc del Prat del Bosc 42.53333 1.46667 V FRST AD 00 0 1846 Europe/Andorra 1993-12-23
+3039406 Obagues del Prat de la Posella Obagues del Prat de la Posella 42.48333 1.45 T SLP AD 00 0 1195 Europe/Andorra 1993-12-23
+3039407 Basera del Prat de la Farga Basera del Prat de la Farga 42.48333 1.45 T CLF AD 00 0 1195 Europe/Andorra 1993-12-23
+3039408 Basers del Prat de la Creu Basers del Prat de la Creu 42.6 1.63333 T CLF AD 00 0 1893 Europe/Andorra 1993-12-23
+3039409 Obaga dels Pradets Obaga dels Pradets 42.48333 1.43333 T SLP AD 00 0 1938 Europe/Andorra 1993-12-23
+3039410 Roc dels Pous Roc dels Pous 42.55 1.61667 T RK AD 00 0 2206 Europe/Andorra 1993-12-23
+3039411 Bosc dels Pous Bosc dels Pous 42.55 1.48333 V FRST AD 00 0 1548 Europe/Andorra 1993-12-23
+3039412 Serrat del Pouet Serrat del Pouet 42.55 1.51667 T RDGE AD 00 0 1397 Europe/Andorra 1993-12-23
+3039413 Canal del Pouet Canal del Pouet 42.56667 1.53333 H STM AD 00 0 1669 Europe/Andorra 1993-12-23
+3039414 Costa del Pou Costa del Pou 42.58333 1.58333 T SLP AD 00 0 1993 Europe/Andorra 1993-12-23
+3039415 Bosc de les Poselletes Bosc de les Poselletes 42.55 1.45 V FRST AD 00 0 1788 Europe/Andorra 1993-12-23
+3039416 Bony de la Posella Bony de la Posella 42.58333 1.48333 T SPUR AD 00 0 1809 Europe/Andorra 1993-12-23
+3039417 Posada dels Pastors Posada dels Pastors 42.58333 1.48333 L LCTY AD 00 0 1809 Europe/Andorra 1993-12-23
+3039418 Font de la Posada Font de la Posada 42.46667 1.45 H SPNG AD 00 0 1562 Europe/Andorra 1993-12-23
+3039419 Serrat de la Posa Serrat de la Posa 42.55 1.66667 T RDGE AD 00 0 2224 Europe/Andorra 1993-12-23
+3039420 Turó del Port Vell Turo del Port Vell 42.65 1.56667 T PK AD 00 0 2471 Europe/Andorra 1993-12-23
+3039421 Pic del Port Vell Pic del Port Vell Pic del Port Vell 42.57205 1.44341 T PK AD 00 0 2655 2305 Europe/Andorra 2011-02-09
+3039422 Canal del Port Vell Canal del Port Vell 42.56667 1.45 H STM AD 00 0 2137 Europe/Andorra 1993-12-23
+3039423 Clot de Port Negre Clot de Port Negre 42.46667 1.56667 H RVN AD 00 0 2365 Europe/Andorra 1993-12-23
+3039424 Basers de les Portes Basers de les Portes 42.48333 1.5 T CLF AD 00 0 1631 Europe/Andorra 1993-12-23
+3039425 Portella de la Portelleta Portella de la Portelleta 42.46667 1.65 T PASS AD 00 0 2700 Europe/Andorra 1993-12-23
+3039426 Tossa Plana de Lles Tossa Plana de Lles Pic de la Portelleta,Tosal Plane,Tossa Plana de Lles 42.46667 1.66667 T PK AD 00 0 2559 Europe/Andorra 2011-11-05
+3039427 Font de la Portelleta Font de la Portelleta 42.46667 1.66667 H SPNG AD 00 0 2559 Europe/Andorra 1993-12-23
+3039428 Collada de la Portelleta Collada de la Portelleta Collada de la Portelleta 42.46667 1.66667 T PASS AD 00 0 2559 Europe/Andorra 2011-11-05
+3039429 Riu de les Portelles Riu de les Portelles 42.61667 1.63333 H STM AD 00 0 2331 Europe/Andorra 1993-12-23
+3039430 Clots de la Portella de Setut Clots de la Portella de Setut 42.46667 1.63333 T CRQS AD 00 0 2619 Europe/Andorra 1993-12-23
+3039431 Pleta de la Portella Pleta de la Portella 42.56667 1.71667 L GRAZ AD 00 0 2219 Europe/Andorra 1993-12-23
+3039432 Collada de la Portella Collada de la Portella 42.46667 1.63333 T PASS AD 00 0 2619 Europe/Andorra 1993-12-23
+3039433 Riu del Port Dret Riu del Port Dret 42.6 1.46667 H STM AD 00 0 2421 Europe/Andorra 1993-12-23
+3039434 Estany del Port Dret Estany del Port Dret 42.6 1.46667 H LK AD 00 0 2421 Europe/Andorra 1993-12-23
+3039435 Costa del Port Dret Costa del Port Dret 42.58333 1.7 T SLP AD 00 0 2584 Europe/Andorra 1993-12-23
+3039436 Clots del Port Dret Clots del Port Dret 42.56667 1.68333 H RVN AD 00 0 2340 Europe/Andorra 1993-12-23
+3039437 Camà del Port Dret Cami del Port Dret 42.56667 1.66667 R TRL AD 00 0 1938 Europe/Andorra 1993-12-23
+3039439 Camà del Port de Setut Cami del Port de Setut 42.46667 1.63333 R TRL AD 00 0 2619 Europe/Andorra 1993-12-23
+3039440 Basses del Port de Rat Basses del Port de Rat 42.61667 1.48333 H LKS AD 05 0 2470 Europe/Andorra 2010-01-12
+3039441 Font del Port de Cabús Font del Port de Cabus 42.55 1.41667 H SPNG AD 00 0 2105 Europe/Andorra 1993-12-23
+3039442 Planades del Port Planades del Port 42.56667 1.45 T UPLD AD 00 0 2137 Europe/Andorra 1993-12-23
+3039443 Costa del Port Costa del Port 42.56667 1.45 T SLP AD 00 0 2137 Europe/Andorra 1993-12-23
+3039444 Costa del Port Costa del Port 42.53333 1.71667 T SLP AD 00 0 2400 Europe/Andorra 1993-12-23
+3039445 Clots del Port Clots del Port 42.46667 1.58333 T CRQS AD 00 0 2367 Europe/Andorra 1993-12-23
+3039446 Clot del Port Clot del Port 42.48333 1.65 H RVN AD 00 0 2658 Europe/Andorra 1993-12-23
+3039447 Canal del Port Canal del Port 42.56667 1.45 H STM AD 00 0 2137 Europe/Andorra 1993-12-23
+3039448 Camà del Port Cami del Port 42.48333 1.58333 R TRL AD 00 0 2349 Europe/Andorra 1993-12-23
+3039449 Roc del Porquer Roc del Porquer 42.58333 1.45 T SPUR AD 00 0 2156 Europe/Andorra 1993-12-23
+3039450 Oratori del Pont d’Aixovall Oratori del Pont d'Aixovall 42.48333 1.5 S AMTH AD 00 0 1631 Europe/Andorra 1993-12-23
+3039451 Canal del Pont Canal del Pont 42.5 1.55 H STM AD 00 0 1566 Europe/Andorra 1993-12-23
+3039452 Riu Pollós Riu Pollos 42.58333 1.46667 H STM AD 00 0 1643 Europe/Andorra 1993-12-23
+3039453 Bosc de la Pollentia Bosc de la Pollentia 42.53333 1.5 V FRST AD 00 0 1357 Europe/Andorra 1993-12-23
+3039454 Roc del Poll Roc del Poll 42.61667 1.53333 T RK AD 00 0 1609 Europe/Andorra 1993-12-23
+3039455 Roc de Podoïna Roc de Podoina 42.45 1.5 T RK AD 00 0 1614 Europe/Andorra 1993-12-23
+3039456 Canal del Pletiu Canal del Pletiu 42.5 1.58333 H STM AD 00 0 1888 Europe/Andorra 1993-12-23
+3039457 Serrat de les Pletes Serrat de les Pletes 42.48333 1.43333 T SPUR AD 00 0 1938 Europe/Andorra 1993-12-23
+3039458 Serrat de la Pleta Vella Serrat de la Pleta Vella 42.6 1.55 T RDGE AD 00 0 2298 Europe/Andorra 1993-12-23
+3039459 Canal de Pleta Mosquera Canal de Pleta Mosquera 42.61667 1.51667 H STM AD 00 0 1716 Europe/Andorra 1993-12-23
+3039460 Canal de la Pleta dels Llacs Canal de la Pleta dels Llacs 42.6 1.63333 H STM AD 00 0 1893 Europe/Andorra 1993-12-23
+3039461 Solana de la Pleta del Perro Solana de la Pleta del Perro 42.53333 1.61667 T SLP AD 00 0 2237 Europe/Andorra 1993-12-23
+3039462 Canals de la Pleta del Llomar Canals de la Pleta del Llomar 42.61667 1.56667 H RVN AD 00 0 2228 Europe/Andorra 1993-12-23
+3039463 Bony de la Pleta de Jan Bony de la Pleta de Jan 42.61667 1.63333 T MT AD 00 0 2331 Europe/Andorra 1993-12-23
+3039464 Roc de la Pleta Roc de la Pleta 42.6 1.46667 T RK AD 00 0 2421 Europe/Andorra 1993-12-23
+3039465 Costa de la Pleta Costa de la Pleta 42.58333 1.45 T SLP AD 00 0 2156 Europe/Andorra 1993-12-23
+3039466 Bosc de la Pleta Bosc de la Pleta 42.55 1.45 V FRST AD 00 0 1788 Europe/Andorra 1993-12-23
+3039467 Barraca de la Pleta Barraca de la Pleta 42.56667 1.71667 S HUT AD 00 0 2219 Europe/Andorra 1993-12-23
+3039468 Camà dels Plans Cami dels Plans 42.58333 1.61667 R TRL AD 00 0 1707 Europe/Andorra 1993-12-23
+3039469 Camà dels Plans Cami dels Plans 42.53333 1.51667 R TRL AD 00 0 1361 Europe/Andorra 1993-12-23
+3039470 Bosc dels Plans Bosc dels Plans 42.58333 1.63333 V FRST AD 00 0 1722 Europe/Andorra 1993-12-23
+3039471 Bordes dels Plans Bordes dels Plans 42.53333 1.51667 S FRM AD 00 0 1361 Europe/Andorra 1993-12-23
+3039472 Obaga dels Plannels de la RegalÃssia Obaga dels Plannels de la Regalissia 42.48333 1.41667 T SLP AD 00 0 1920 Europe/Andorra 1993-12-23
+3039473 Planes de Fels Planes de Fels 42.58333 1.53333 L LCTY AD 00 0 1924 Europe/Andorra 1993-12-23
+3039474 Solana de les Planes Solana de les Planes 42.56667 1.53333 T SLP AD 00 0 1669 Europe/Andorra 1993-12-23
+3039475 Riu de les Planes Riu de les Planes 42.63333 1.5 H STM AD 00 0 1979 Europe/Andorra 1993-12-23
+3039476 Pleta de les Planes Pleta de les Planes 42.65 1.5 L GRAZ AD 00 0 2455 Europe/Andorra 1993-12-23
+3039477 Pic de l' Albeille Pic de l' Albeille Pic de les Planes 42.6457 1.49929 T RDGE AD FR,AD 07 0 2542 Europe/Andorra 2007-03-04
+3039478 Les Planes Les Planes 42.56667 1.55 T UPLD AD 00 0 1996 Europe/Andorra 1993-12-23
+3039479 Collet de les Planes Collet de les Planes 42.56667 1.53333 T SPUR AD 00 0 1669 Europe/Andorra 1993-12-23
+3039480 Collada de les Planes Collada de les Planes 42.65 1.5 T PASS AD 00 0 2455 Europe/Andorra 1993-12-23
+3039481 Bosc de les Planes Bosc de les Planes 42.51667 1.6 V FRST AD 00 0 2085 Europe/Andorra 1993-12-23
+3039482 Bony de les Planes Bony de les Planes 42.55 1.51667 T SPUR AD 00 0 1397 Europe/Andorra 1993-12-23
+3039483 Serrat dels Planells Grans Serrat dels Planells Grans 42.53333 1.53333 T RDGE AD 00 0 1521 Europe/Andorra 1993-12-23
+3039484 Cabana dels Planells de Rialb Cabana dels Planells de Rialb 42.65 1.55 S HUT AD 00 0 2181 Europe/Andorra 1993-12-23
+3039485 Planells de Rialb Planells de Rialb 42.65 1.55 L LCTY AD 00 0 2181 Europe/Andorra 1993-12-23
+3039486 Riu dels Planells de Caraup Riu dels Planells de Caraup 42.6 1.63333 H STM AD 00 0 1893 Europe/Andorra 1993-12-23
+3039487 Planells d’ArcalÃs Planells d'Arcalis 42.63333 1.5 L LCTY AD 00 0 1979 Europe/Andorra 1993-12-23
+3039488 Serrat del Planell Lluent Serrat del Planell Lluent 42.56667 1.51667 T RDGE AD 00 0 1500 Europe/Andorra 1993-12-23
+3039489 Bony del Planell Gran Bony del Planell Gran 42.63333 1.55 T SPUR AD 00 0 2053 Europe/Andorra 1993-12-23
+3039490 Bosc de Planavilla Bosc de Planavilla 42.55 1.68333 V FRST AD 00 0 2254 Europe/Andorra 1993-12-23
+3039491 Planavilla Planavilla 42.55 1.68333 L CLG AD 00 0 2254 Europe/Andorra 1993-12-23
+3039492 Bosc de la Planassa Bosc de la Planassa 42.55 1.5 V FRST AD 00 0 1292 Europe/Andorra 1993-12-23
+3039493 Bosc de Plana en Blanca Bosc de Plana en Blanca 42.55 1.56667 V FRST AD 00 0 1828 Europe/Andorra 1993-12-23
+3039494 Tarteres de Plana de Gral Tarteres de Plana de Gral 42.58333 1.48333 T TAL AD 00 0 1809 Europe/Andorra 1993-12-23
+3039495 Tosa Plana Tosa Plana 42.46667 1.6 T UPLD AD 00 0 2449 Europe/Andorra 1993-12-23
+3039496 Torrent de la Plana Torrent de la Plana 42.53333 1.6 H STM AD 00 0 1888 Europe/Andorra 1993-12-23
+3039497 Serra Plana Serra Plana 42.58333 1.6 T SPUR AD 00 0 1828 Europe/Andorra 1993-12-23
+3039498 Serra Plana Serra Plana 42.56667 1.48333 T MT AD 00 0 1508 Europe/Andorra 1993-12-23
+3039499 Sierra Plana Sierra Plana Serra Plana,Sierra Plana 42.48333 1.43333 T MT AD 00 0 1938 Europe/Andorra 2011-11-05
+3039500 Cortal de la Plana Cortal de la Plana 42.48333 1.53333 S HUT AD 00 0 2255 Europe/Andorra 1993-12-23
+3039501 Coll de la Plana Coll de la Plana 42.45 1.5 T SPUR AD 00 0 1614 Europe/Andorra 1993-12-23
+3039502 Camà de la Plana Cami de la Plana 42.48333 1.55 R TRL AD 00 0 2233 Europe/Andorra 1993-12-23
+3039503 Bosquet de la Plana Bosquet de la Plana 42.5 1.53333 V FRST AD 00 0 1574 Europe/Andorra 1993-12-23
+3039504 Bosc de la Plana Bosc de la Plana 42.55 1.55 V FRST AD 00 0 2097 Europe/Andorra 1993-12-23
+3039505 Bordes de la Plana Bordes de la Plana 42.53333 1.6 S HUTS AD 00 0 1888 Europe/Andorra 1993-12-23
+3039506 Borda de la Plana Borda de la Plana 42.55 1.55 S HUTS AD 00 0 2097 Europe/Andorra 1993-12-23
+3039507 Barranc de la Plana Barranc de la Plana 42.55 1.55 H STM AD 00 0 2097 Europe/Andorra 1993-12-23
+3039508 Serrat del Pla Morell Serrat del Pla Morell 42.53333 1.53333 T RDGE AD 00 0 1521 Europe/Andorra 1993-12-23
+3039509 Torrent de Plamanera Torrent de Plamanera 42.53333 1.56667 H STM AD 00 0 1418 Europe/Andorra 1993-12-23
+3039510 Bosc del Pla de Rodó Bosc del Pla de Rodo 42.55 1.43333 V FRST AD 00 0 1949 Europe/Andorra 1993-12-23
+3039511 Bosc del Pla de Miretes Bosc del Pla de Miretes 42.53333 1.48333 V FRST AD 00 0 1677 Europe/Andorra 1993-12-23
+3039512 Pic del Pla de l’Ingla Pic del Pla de l'Ingla 42.48333 1.63333 T PK AD 00 0 2296 Europe/Andorra 1993-12-23
+3039513 Pla de l’Ingla Pla de l'Ingla 42.48333 1.63333 A ADMD AD 00 0 2296 Europe/Andorra 1993-12-23
+3039514 Riu del Pla de l’Estany Riu del Pla de l'Estany 42.58333 1.46667 H STM AD 00 0 1643 Europe/Andorra 1993-12-23
+3039515 Pleta del Pla de l’Estany Pleta del Pla de l'Estany 42.58333 1.46667 L GRAZ AD 00 0 1643 Europe/Andorra 1993-12-23
+3039516 Pic des Bareytes Pic des Bareytes Pic del Pla de l'Estany,Pic del Pla de l’Estany,Pic des Bareytes 42.6 1.46667 T PK AD 00 0 2421 Europe/Andorra 2011-11-05
+3039517 Estret del Pla de l’Estany Estret del Pla de l'Estany 42.6 1.45 T PASS AD 00 0 2174 Europe/Andorra 1993-12-23
+3039518 Pla de l’Estany Pla de l'Estany 42.6 1.45 A ADMD AD 00 0 2174 Europe/Andorra 1993-12-23
+3039519 Camà del Pla de les Pedres Cami del Pla de les Pedres 42.53333 1.68333 R TRL AD 00 0 2322 Europe/Andorra 1993-12-23
+3039520 Camà del Pla del Bosc Cami del Pla del Bosc 42.53333 1.61667 R TRL AD 00 0 2237 Europe/Andorra 1993-12-23
+3039521 Bosc del Pla de la Cot Bosc del Pla de la Cot 42.53333 1.46667 V FRST AD 00 0 1846 Europe/Andorra 1993-12-23
+3039522 Grau de les Places Grau de les Places 42.55 1.46667 T SLP AD 00 0 1585 Europe/Andorra 1993-12-23
+3039523 Pleta de Pixolell Pleta de Pixolell 42.58333 1.63333 L GRAZ AD 00 0 1722 Europe/Andorra 1993-12-23
+3039524 Costes de Pixolell Costes de Pixolell 42.58333 1.63333 T SLP AD 00 0 1722 Europe/Andorra 1993-12-23
+3039525 Pont de la Pixistella Pont de la Pixistella 42.56667 1.5 S BDG AD 00 0 1636 Europe/Andorra 1993-12-23
+3039526 Obac de la Pixistella Obac de la Pixistella 42.55 1.5 T SLP AD 00 0 1292 Europe/Andorra 1993-12-23
+3039527 Canal de la Pixistella Canal de la Pixistella 42.55 1.5 H STM AD 00 0 1292 Europe/Andorra 1993-12-23
+3039528 Bosc de la Pixistella Bosc de la Pixistella 42.55 1.48333 V FRST AD 00 0 1548 Europe/Andorra 1993-12-23
+3039529 Font Pixadera Font Pixadera 42.5 1.56667 H SPNG AD 00 0 1776 Europe/Andorra 1993-12-23
+3039530 Roca del Pisó Roca del Piso 42.53333 1.63333 T RK AD 00 0 2360 Europe/Andorra 1993-12-23
+3039531 Borda del Pirot Borda del Pirot 42.58333 1.65 S HUT AD 00 0 1767 Europe/Andorra 1993-12-23
+3039532 Pirineu Pirineu 42.51667 1.55 L LCTY AD 00 0 1322 Europe/Andorra 1993-12-23
+3039533 Bosc de la Pinosa de Llumeneres Bosc de la Pinosa de Llumeneres 42.46667 1.51667 V FRST AD 00 0 1985 Europe/Andorra 1993-12-23
+3039534 Bosc de la Pinosa Bosc de la Pinosa 42.6 1.68333 V FRST AD 00 0 2089 Europe/Andorra 1993-12-23
+3039535 Bosc de la Pinosa Bosc de la Pinosa 42.45 1.5 V FRST AD 00 0 1614 Europe/Andorra 1993-12-23
+3039536 Serrat Pinós Serrat Pinos 42.55 1.68333 T MT AD 00 0 2254 Europe/Andorra 1993-12-23
+3039537 Collada de Pimes Collada de Pimes 42.42951 1.54658 T PASS AD 00 0 2186 Europe/Andorra 2011-04-19
+3039538 Canal del Pi Gros Canal del Pi Gros 42.5 1.46667 H STM AD 00 0 1678 Europe/Andorra 1993-12-23
+3039539 Borda del Piedro Borda del Piedro 42.58333 1.63333 S HUT AD 00 0 1722 Europe/Andorra 1993-12-23
+3039540 Bosc del Pi de Montsalla Bosc del Pi de Montsalla 42.53333 1.48333 V FRST AD 00 0 1677 Europe/Andorra 1993-12-23
+3039541 Camà del Pi de la Creu Cami del Pi de la Creu 42.55 1.6 R TRL AD 00 0 2210 Europe/Andorra 1993-12-23
+3039542 Canal dels Picons Canal dels Picons 42.56667 1.5 H STM AD 00 0 1636 Europe/Andorra 1993-12-23
+3039543 Bosc del Picó Bosc del Pico 42.5 1.55 V FRST AD 00 0 1566 Europe/Andorra 1993-12-23
+3039544 Basers del Pic de la Cabaneta Basers del Pic de la Cabaneta 42.61667 1.6 T CLF AD 00 0 2528 Europe/Andorra 1993-12-23
+3039545 Font Picadora Font Picadora 42.56667 1.56667 H SPNG AD 00 0 2089 Europe/Andorra 1993-12-23
+3039546 Canal de la Pica Canal de la Pica 42.5 1.5 H STM AD 00 0 1135 Europe/Andorra 1993-12-23
+3039547 Bony de la Pica Bony de la Pica Bony de la Pica,Pic d' Os,Pic d’ Ós,Pico de Ancla,Pico de Anclá 42.5 1.45 T MT AD 00 0 1840 Europe/Andorra 2011-11-05
+3039548 Basses del Pic Basses del Pic 42.61667 1.61667 H LKS AD 00 0 2352 Europe/Andorra 1993-12-23
+3039549 Bosc del Peu dels Pessons Bosc del Peu dels Pessons 42.51667 1.68333 V FRST AD 00 0 2352 Europe/Andorra 1993-12-23
+3039550 Font dels Pets Font dels Pets 42.58333 1.48333 H SPNG AD 00 0 1809 Europe/Andorra 1993-12-23
+3039551 Coll Petit Coll Petit Coll Petit,Collado Pequeno,Collado Pequeño 42.56498 1.44248 T PASS AD 00 0 2408 Europe/Andorra 2011-11-05
+3039552 Riu dels Pessons Riu dels Pessons 42.51667 1.7 H STM AD 00 0 2435 Europe/Andorra 1993-12-23
+3039553 Pic dels Pessons Pic dels Pessons Pic de Pessons,Pic dels Pessons,Pic des Pessons 42.50832 1.6585 T PK AD 00 0 2727 Europe/Andorra 2011-11-05
+3039554 Collada dels Pessons Collada dels Pessons 42.5 1.65 T PASS AD 00 0 2542 Europe/Andorra 1993-12-23
+3039555 Pleta dels Pescadors Pleta dels Pescadors 42.48333 1.65 L GRAZ AD 00 0 2658 Europe/Andorra 1993-12-23
+3039556 Pesada de Pal Pesada de Pal 42.56667 1.48333 L LCTY AD 00 0 1508 Europe/Andorra 1993-12-23
+3039557 Pont de Pesada Pont de Pesada 42.56667 1.48333 S BDG AD 00 0 1508 Europe/Andorra 1993-12-23
+3039558 Canal de Pesada Canal de Pesada 42.56667 1.48333 H STM AD 00 0 1508 Europe/Andorra 1993-12-23
+3039559 Basera de Pesada Basera de Pesada 42.56667 1.48333 T CLF AD 00 0 1508 Europe/Andorra 1993-12-23
+3039560 Pesada Pesada 42.56667 1.48333 T SLP AD 00 0 1508 Europe/Andorra 1993-12-23
+3039561 Roc de Persoma Roc de Persoma 42.48333 1.48333 T RK AD 00 0 981 Europe/Andorra 1993-12-23
+3039562 Plana Perdiguera Plana Perdiguera 42.55 1.45 T UPLD AD 00 0 1788 Europe/Andorra 1993-12-23
+3039563 Pic de Percanela Pic de Percanela 42.58915 1.49666 T PK AD 00 0 2089 Europe/Andorra 2011-04-19
+3039564 Bordes de Percanela Bordes de Percanela 42.5825 1.48809 S FRM AD 00 0 2019 Europe/Andorra 2011-04-19
+3039565 Percanela Percanela Coma de Percanela,Loma de Percanela,Percanela 42.58333 1.48333 A ADMD AD AD 00 0 1809 Europe/Andorra 2011-11-05
+3039566 Camà de Per Baix Cami de Per Baix 42.55 1.68333 R TRL AD 00 0 2254 Europe/Andorra 1993-12-23
+3039567 Riu de Perafita Riu de Perafita 42.49733 1.55811 H STM AD 00 0 1566 Europe/Andorra 2011-04-19
+3039568 Pleta de Perafita Pleta de Perafita 42.48333 1.58333 L GRAZ AD 00 0 2349 Europe/Andorra 1993-12-23
+3039569 Planells de Perafita Planells de Perafita 42.48333 1.58333 T UPLD AD 00 0 2349 Europe/Andorra 1993-12-23
+3039570 Estanys de Perafita Estanys de Perafita 42.47027 1.58958 H LKS AD 00 0 2518 Europe/Andorra 2011-04-19
+3039571 Costa de Perafita Costa de Perafita 42.48333 1.58333 T SLP AD 00 0 2349 Europe/Andorra 1993-12-23
+3039572 Camà de Perafita Cami de Perafita 42.5 1.56667 R TRL AD 00 0 1776 Europe/Andorra 1993-12-23
+3039573 Cabana de Perafita Cabana de Perafita 42.48333 1.58333 S HUT AD 00 0 2349 Europe/Andorra 1993-12-23
+3039574 Perafita Perafita 42.46667 1.58333 A ADMD AD 00 0 2367 Europe/Andorra 1993-12-23
+3039575 Canal de la Pera Canal de la Pera 42.56667 1.48333 H RVN AD 00 0 1508 Europe/Andorra 1993-12-23
+3039576 Roc de la Penya Roc de la Penya 42.53333 1.55 T RK AD 00 0 1344 Europe/Andorra 1993-12-23
+3039577 Costa Pentinada Costa Pentinada 42.48333 1.53333 T SLP AD 00 0 2255 Europe/Andorra 1993-12-23
+3039578 Riu de la Peguera Riu de la Peguera 42.45 1.51667 H STM AD 00 0 1790 Europe/Andorra 1993-12-23
+3039579 Conreu de la Peguera Conreu de la Peguera 42.45 1.53333 V CULT AD 00 0 1859 Europe/Andorra 1993-12-23
+3039580 Carretera de la Peguera Carretera de la Peguera 42.46667 1.55 R RD AD 00 0 2341 Europe/Andorra 1993-12-23
+3039581 Bosc de la Peguera Bosc de la Peguera 42.46321 1.52655 V FRST AD 00 0 2068 Europe/Andorra 2011-04-19
+3039582 Bordes de la Peguera Bordes de la Peguera 42.45 1.53333 S HUTS AD 00 0 1859 Europe/Andorra 1993-12-23
+3039583 Serrat de les Pedrusques Serrat de les Pedrusques 42.6 1.5 T SPUR AD 00 0 1923 Europe/Andorra 1993-12-23
+3039584 Torrent Pedrós Torrent Pedros 42.45 1.48333 H STM AD 00 0 1111 Europe/Andorra 1993-12-23
+3039585 Bosc de Pedres Blanques Bosc de Pedres Blanques 42.53333 1.48333 V FRST AD 00 0 1677 Europe/Andorra 1993-12-23
+3039586 Pla de les Pedres Pla de les Pedres 42.55 1.66667 T UPLD AD 00 0 2224 Europe/Andorra 1993-12-23
+3039587 Pont Pedregat Pont Pedregat 42.58333 1.48333 S BDG AD 00 0 1809 Europe/Andorra 1993-12-23
+3039588 Canal de Pedra Plana Canal de Pedra Plana 42.51667 1.5 H STM AD 00 0 1688 Europe/Andorra 1993-12-23
+3039589 Corral de Pedra Corral de Pedra 42.56667 1.7 L GRAZ AD 00 0 2375 Europe/Andorra 1993-12-23
+3039590 Corral de Pedra Corral de Pedra 42.56667 1.65 L GRAZ AD 00 0 1988 Europe/Andorra 1993-12-23
+3039591 Canal de la Peca Rodona Canal de la Peca Rodona 42.53333 1.48333 H STM AD 00 0 1677 Europe/Andorra 1993-12-23
+3039592 Bosc de Paulelles Bosc de Paulelles 42.53333 1.53333 V FRST AD 00 0 1521 Europe/Andorra 1993-12-23
+3039593 Borda de Paulelles Borda de Paulelles 42.53333 1.55 S HUT AD 00 0 1344 Europe/Andorra 1993-12-23
+3039594 Passos dels Estanys Passos dels Estanys 42.6 1.6 L LCTY AD 00 0 2143 Europe/Andorra 1993-12-23
+3039595 Passos de la Tarterosa Passos de la Tarterosa 42.6 1.65 L LCTY AD 00 0 2131 Europe/Andorra 1993-12-23
+3039596 Canal del Passatorrents Canal del Passatorrents 42.43333 1.48333 H STM AD 00 0 1228 Europe/Andorra 1993-12-23
+3039597 Coll Passader Coll Passader 42.55 1.5 T PK AD 00 0 1292 Europe/Andorra 1993-12-23
+3039598 Riu del Pas Mal Riu del Pas Mal 42.53333 1.65 H STM AD 00 0 2508 Europe/Andorra 1993-12-23
+3039599 Costa del Pas del Monjo Costa del Pas del Monjo 42.63333 1.56667 T SLP AD 00 0 2394 Europe/Andorra 1993-12-23
+3039600 Pas del Monjo Pas del Monjo 42.63333 1.55 L LCTY AD 00 0 2053 Europe/Andorra 1993-12-23
+3039601 Bosc del Pas de la Clau Bosc del Pas de la Clau 42.51667 1.61667 V FRST AD 00 0 2254 Europe/Andorra 1993-12-23
+3039602 Solana del Pas de la Casa Solana del Pas de la Casa 42.53333 1.73333 T SLP AD 00 0 2300 Europe/Andorra 1993-12-23
+3039603 Riu del Pas de la Casa Riu del Pas de la Casa Riu del Pas de la Casa 42.56667 1.75 H STMX AD 00 0 1923 Europe/Andorra 2011-11-05
+3039604 Pas de la Casa Pas de la Casa Pas de la Kasa,ÐŸÐ°Ñ Ð´Ðµ ла КаÑа 42.54277 1.73361 P PPL AD 03 2363 2050 2230 Europe/Andorra 2008-06-09
+3039605 Pas de la Casa Pas de la Casa 42.53333 1.71667 A ADMD AD 00 0 2400 Europe/Andorra 1993-12-23
+3039606 Partida d’Ensucaranes Partida d'Ensucaranes 42.51667 1.55 L LCTY AD 00 0 1322 Europe/Andorra 1993-12-23
+3039607 Partida de l’Any de la Part Partida de l'Any de la Part 42.55 1.53333 A ADMD AD 00 0 1593 Europe/Andorra 1993-12-23
+3039608 Partida de la Grella Partida de la Grella 42.51667 1.51667 A ADMD AD 00 0 1265 Europe/Andorra 1993-12-23
+3039609 Borda de les Pardines Borda de les Pardines 42.53333 1.6 S FRM AD 00 0 1888 Europe/Andorra 1993-12-23
+3039610 Tossal de la Pardina Tossal de la Pardina 42.5 1.48333 T SPUR AD 00 0 1316 Europe/Andorra 1993-12-23
+3039611 Bosc del Pardal Bosc del Pardal 42.55 1.5 V FRST AD 00 0 1292 Europe/Andorra 1993-12-23
+3039612 Riu de la Palomera Riu de la Palomera 42.56667 1.78333 H STM AD 00 0 1680 Europe/Andorra 1993-12-23
+3039613 Cap de la Palomera Cap de la Palomera Cap de la Palomera 42.58333 1.78333 T PK AD 00 0 1694 Europe/Andorra 2011-11-05
+3039614 Pont de Palomer Pont de Palomer 42.56667 1.48333 S BDG AD 00 0 1508 Europe/Andorra 1993-12-23
+3039615 Pic de Palomer Pic de Palomer 42.56667 1.48333 T PK AD 00 0 1508 Europe/Andorra 1993-12-23
+3039616 Obaga de Palomer Obaga de Palomer 42.56667 1.48333 T SLP AD 00 0 1508 Europe/Andorra 1993-12-23
+3039617 Canal de Palomer Canal de Palomer 42.56667 1.48333 H STM AD 00 0 1508 Europe/Andorra 1993-12-23
+3039618 Callissa de Palomer Callissa de Palomer 42.56667 1.48333 T GRGE AD 00 0 1508 Europe/Andorra 1993-12-23
+3039619 Palomer Palomer 42.56667 1.48333 A ADMD AD 00 0 1508 Europe/Andorra 1993-12-23
+3039620 Feixa Pallola Feixa Pallola 42.43333 1.46667 V CULT AD 00 0 1113 Europe/Andorra 1993-12-23
+3039621 Serrat Pallero Serrat Pallero 42.45 1.45 T SPUR AD 00 0 1482 Europe/Andorra 1993-12-23
+3039622 Prat de Paleta Prat de Paleta 42.48333 1.6 L GRAZ AD 00 0 2250 Europe/Andorra 1993-12-23
+3039623 Serrat de la Palanqueta Serrat de la Palanqueta 42.55 1.6 T RDGE AD 00 0 2210 Europe/Andorra 1993-12-23
+3039624 Riu de la Palanqueta Riu de la Palanqueta 42.55 1.6 H STM AD 00 0 2210 Europe/Andorra 1993-12-23
+3039625 Pont de les Palanques Pont de les Palanques 42.55 1.51667 S BDG AD 00 0 1397 Europe/Andorra 1993-12-23
+3039626 Planell de la Palanca Planell de la Palanca 42.55 1.68333 T UPLD AD 00 0 2254 Europe/Andorra 1993-12-23
+3039627 Pic de la Pala de Coll Carnisser Pic de la Pala de Coll Carnisser 42.6 1.48333 T PK AD 00 0 2441 Europe/Andorra 1993-12-23
+3039628 Pic de la Pala Alta Pic de la Pala Alta 42.6 1.63333 T PK AD 00 0 1893 Europe/Andorra 1993-12-23
+3039629 Solà de Pal Sola de Pal 42.55 1.46667 T SLP AD 00 0 1585 Europe/Andorra 1993-12-23
+3039630 Riu de Pal Riu de Pal 42.56159 1.49544 H STM AD 00 0 1430 Europe/Andorra 2011-04-19
+3039631 Pont de Pal Pont de Pal 42.55 1.46667 S BDG AD 00 0 1585 Europe/Andorra 1993-12-23
+3039632 Carretera de Pal Carretera de Pal 42.55 1.48333 R RD AD 00 0 1548 Europe/Andorra 1993-12-23
+3039633 Bosc de Pal Bosc de Pal 42.53333 1.46667 V FRST AD 00 0 1846 Europe/Andorra 1993-12-23
+3039634 Pal Pal Pal 42.55 1.48333 P PPL AD 04 0 1548 Europe/Andorra 2011-11-05
+3039635 Serra de Padern Serra de Padern 42.53333 1.55 T RDGE AD 00 0 1344 Europe/Andorra 1993-12-23
+3039636 Riu de Padern Riu de Padern 42.52834 1.52213 H STM AD 00 0 1361 Europe/Andorra 2011-04-19
+3039637 Pic de Padern Pic de Padern 42.52429 1.54697 T PK AD 00 0 1290 Europe/Andorra 2011-04-19
+3039638 Bosc de Padern Bosc de Padern 42.53333 1.53333 V FRST AD 00 0 1521 Europe/Andorra 1993-12-23
+3039639 Coll Pa Coll Pa 42.55 1.43333 T PK AD 00 0 1949 Europe/Andorra 1993-12-23
+3039640 Coll Pa Coll Pa 42.48333 1.56667 T PASS AD 00 0 2231 Europe/Andorra 1993-12-23
+3039641 Canal de l’ Ovella Morta Canal de l' Ovella Morta 42.48333 1.58333 H STM AD 00 0 2349 Europe/Andorra 1993-12-23
+3039642 Riu de l’ Ovella Riu de l' Ovella 42.53333 1.6 H STM AD 00 0 1888 Europe/Andorra 1993-12-23
+3039643 Port de l’ Ovella Port de l' Ovella Port de L'Ovella,Port de L’Ovella,Port de l' Ovella,Port de l’ Ovella 42.55 1.43333 T PASS AD 00 0 1949 Europe/Andorra 2011-11-05
+3039644 Bosc de l’ Ovella Bosc de l' Ovella 42.53333 1.6 V FRST AD 00 0 1888 Europe/Andorra 1993-12-23
+3039645 Font de l’ Óssa Font de l' Ossa 42.51667 1.48333 H SPNG AD 00 0 1839 Europe/Andorra 1993-12-23
+3039646 Cova de l’ Óssa Cova de l' Ossa 42.46667 1.48333 S CAVE AD 00 0 1134 Europe/Andorra 1993-12-23
+3039647 Cova de l’ Óssa Cova de l' Ossa 42.45 1.48333 S CAVE AD 00 0 1111 Europe/Andorra 1993-12-23
+3039648 Canya de l’ Óssa Canya de l' Ossa 42.56667 1.51667 S CAVE AD 00 0 1500 Europe/Andorra 1993-12-23
+3039649 Canal de l’ Óssa Canal de l' Ossa 42.5 1.63333 H STM AD 00 0 2545 Europe/Andorra 1993-12-23
+3039650 Canal de l’ Óssa Canal de l' Ossa 42.58333 1.46667 H RVN AD 00 0 1643 Europe/Andorra 1993-12-23
+3039651 Carretera d’ Ós de CivÃs Carretera d' Os de Civis 42.48333 1.46667 R RD AD 00 0 1148 Europe/Andorra 1993-12-23
+3039652 Canal de l’ Osca de Migdia Canal de l' Osca de Migdia 42.46667 1.46667 H STM AD 00 0 1340 Europe/Andorra 1993-12-23
+3039653 Clots de l’ Ós Clots de l' Os 42.58333 1.68333 H RVN AD 00 0 2294 Europe/Andorra 1993-12-23
+3039654 Clot de l’ Ós Clot de l' Os 42.58333 1.66667 H RVN AD 00 0 2159 Europe/Andorra 1993-12-23
+3039655 Tosa d’ Ortafà Tosa d' Ortafa 42.56667 1.71667 T UPLD AD 00 0 2219 Europe/Andorra 1993-12-23
+3039656 Tarteres d’ Ortafà Tarteres d' Ortafa 42.56667 1.71667 T TAL AD 00 0 2219 Europe/Andorra 1993-12-23
+3039657 Font d’ Ortafà Font d' Ortafa 42.56667 1.71667 H SPNG AD 00 0 2219 Europe/Andorra 1993-12-23
+3039658 Collet d’ Ortafà Collet d' Ortafa 42.56667 1.7 T PASS AD 00 0 2375 Europe/Andorra 1993-12-23
+3039659 Clots d’ Ortafà Clots d' Ortafa 42.55 1.71667 H RVN AD 00 0 2192 Europe/Andorra 1993-12-23
+3039660 Canals d’ Ortafà Canals d' Ortafa 42.56667 1.7 H RVN AD 00 0 2375 Europe/Andorra 1993-12-23
+3039661 Ortafà Ortafa 42.56667 1.71667 A ADMD AD 00 0 2219 Europe/Andorra 1993-12-23
+3039662 Bony de l’ Orri Vell Bony de l' Orri Vell 42.53333 1.63333 T SPUR AD 00 0 2360 Europe/Andorra 1993-12-23
+3039663 Riu dels Orris Riu dels Orris 42.48333 1.63333 H STM AD 00 0 2296 Europe/Andorra 1993-12-23
+3039664 Prats dels Orris Prats dels Orris 42.53333 1.63333 L GRAZ AD 00 0 2360 Europe/Andorra 1993-12-23
+3039665 Pleta dels Orris Pleta dels Orris 42.53333 1.63333 L GRAZ AD 00 0 2360 Europe/Andorra 1993-12-23
+3039666 Barraca de l’ Orri de Rusca Barraca de l' Orri de Rusca 42.55 1.68333 S HUT AD 00 0 2254 Europe/Andorra 1993-12-23
+3039667 Bosc de l’ Orri del Call Bosc de l' Orri del Call 42.6 1.65 V FRST AD 00 0 2131 Europe/Andorra 1993-12-23
+3039668 Serrat de l’ Orri de Gastó Serrat de l' Orri de Gasto 42.48333 1.46667 T SPUR AD 00 0 1148 Europe/Andorra 1993-12-23
+3039669 Serrat de l’ Orri Serrat de l' Orri 42.58333 1.66667 T SLP AD 00 0 2159 Europe/Andorra 1993-12-23
+3039670 Pont de l’ Orri Pont de l' Orri 42.58333 1.66667 S BDG AD 00 0 2159 Europe/Andorra 1993-12-23
+3039671 Obaga de l’ Orri Obaga de l' Orri 42.46667 1.45 T SLP AD 00 0 1562 Europe/Andorra 1993-12-23
+3039672 Borda de l’ Orri Borda de l' Orri 42.55 1.43333 S HUT AD 00 0 1949 Europe/Andorra 1993-12-23
+3039673 Solana dels Oriols Solana dels Oriols 42.56667 1.48333 T SLP AD 00 0 1508 Europe/Andorra 1993-12-23
+3039674 Cap dels Oriols Cap dels Oriols 42.56667 1.46667 T PK AD 00 0 1673 Europe/Andorra 1993-12-23
+3039675 Pont d'Ordino Pont d'Ordino 42.5492 1.52373 S BDG AD 07 0 1397 Europe/Andorra 2007-04-04
+3039676 Parròquia d'Ordino Parroquia d'Ordino Ordino,Parroquia d'Ordino,Parròquia d'Ordino 42.59758 1.52573 A ADM1 AD 05 3467 1695 Europe/Andorra 2008-03-17
+3039677 Coll d'Ordino Coll d'Ordino Coll d'Ordino,Port d'Ordino 42.55615 1.57147 T PASS AD AD 07 0 1883 1879 Europe/Andorra 2007-04-04
+3039678 Ordino Ordino Ordino,ao er di nuo,orudino jiao qu,Ордино,オルディノ教区,奥尔迪诺 42.55623 1.53319 P PPLA AD 05 3066 1340 Europe/Andorra 2009-12-11
+3039679 Font de les Ordigues Font de les Ordigues 42.51667 1.56667 H SPNG AD 00 0 1759 Europe/Andorra 1993-12-23
+3039680 Font de l’ Ordigal Font de l' Ordigal 42.46667 1.46667 H SPNG AD 00 0 1340 Europe/Andorra 1993-12-23
+3039681 Roc de l’ Oral Roc de l' Oral 42.53333 1.56667 T CLF AD 00 0 1418 Europe/Andorra 1993-12-23
+3039682 Planells d’ Olio Planells d' Olio 42.53333 1.6 T UPLD AD 00 0 1888 Europe/Andorra 1993-12-23
+3039683 Obagueta de Cantà Obagueta de Canti 42.56667 1.51667 L LCTY AD 00 0 1500 Europe/Andorra 1993-12-23
+3039684 Riu de les Obagues Riu de les Obagues 42.58333 1.63333 H STM AD 00 0 1722 Europe/Andorra 1993-12-23
+3039685 Canal de les Obagues Canal de les Obagues 42.58333 1.48333 H STM AD 00 0 1809 Europe/Andorra 1993-12-23
+3039686 Bosc de les Obagues Bosc de les Obagues 42.58333 1.63333 V FRST AD 00 0 1722 Europe/Andorra 1993-12-23
+3039687 Bosc de l’ Obaga Sobirana Bosc de l' Obaga Sobirana 42.55 1.48333 V FRST AD 00 0 1548 Europe/Andorra 1993-12-23
+3039688 Canal de l’ Obaga Fosca Canal de l' Obaga Fosca 42.48333 1.43333 H STM AD 00 0 1938 Europe/Andorra 1993-12-23
+3039689 Clots de l’ Obaga de Torradella Clots de l' Obaga de Torradella 42.6 1.63333 H RVN AD 00 0 1893 Europe/Andorra 1993-12-23
+3039690 Serra de l’ Obaga d’Enclar Serra de l' Obaga d'Enclar 42.51246 1.477 T MT AD 00 0 2069 Europe/Andorra 2011-04-19
+3039691 Obaga d’Enclar Obaga d'Enclar 42.5 1.46667 A ADMD AD 00 0 1678 Europe/Andorra 1993-12-23
+3039692 Canal de l’ Obaga de l’Óssa Canal de l' Obaga de l'Ossa 42.55 1.48333 H STM AD 00 0 1548 Europe/Andorra 1993-12-23
+3039693 Bosc de l’ Obaga de l’Óssa Bosc de l' Obaga de l'Ossa 42.55 1.48333 V FRST AD 00 0 1548 Europe/Andorra 1993-12-23
+3039694 Obaga de l’Estall Serrer Obaga de l'Estall Serrer 42.48333 1.6 A ADMD AD 00 0 2250 Europe/Andorra 1993-12-23
+3039695 Obaga de la Gonarda Obaga de la Gonarda 42.55 1.53333 A ADMD AD 00 0 1593 Europe/Andorra 1993-12-23
+3039696 Obaga de Juclar Obaga de Juclar 42.61667 1.7 L LCTY AD 00 0 2285 Europe/Andorra 1993-12-23
+3039697 Obaga de Juberri Obaga de Juberri 42.43333 1.48333 A ADMD AD 00 0 1228 Europe/Andorra 1993-12-23
+3039698 Bosc de l’ Obaga de Gali Bosc de l' Obaga de Gali 42.55 1.48333 V FRST AD 00 0 1548 Europe/Andorra 1993-12-23
+3039699 Obaga de Fontverd Obaga de Fontverd 42.48333 1.58333 A ADMD AD 00 0 2349 Europe/Andorra 1993-12-23
+3039700 Obaga d’Ansalonga Obaga d'Ansalonga 42.56667 1.51667 A ADMD AD 00 0 1500 Europe/Andorra 1993-12-23
+3039701 Obaga d’Andorra Obaga d'Andorra 42.48333 1.51667 A ADMD AD 00 0 2061 Europe/Andorra 1993-12-23
+3039702 Camà de l’ Obaga Cami de l' Obaga 42.55 1.55 R TRL AD 00 0 2097 Europe/Andorra 1993-12-23
+3039703 Serrat dels Obacs Serrat dels Obacs 42.6 1.5 T SLP AD 00 0 1923 Europe/Andorra 1993-12-23
+3039704 Fonts dels Obacs Fonts dels Obacs 42.6 1.5 H SPNG AD 00 0 1923 Europe/Andorra 1993-12-23
+3039705 Obac d’Incles Obac d'Incles 42.58333 1.68333 A ADMD AD 00 0 2294 Europe/Andorra 1993-12-23
+3039706 Obac de Soldeu Obac de Soldeu 42.56667 1.66667 A ADMD AD 00 0 1938 Europe/Andorra 1993-12-23
+3039707 Obac de Sispony Obac de Sispony 42.51667 1.48333 A ADMD AD 00 0 1839 Europe/Andorra 1993-12-23
+3039708 Bosc de l’ Obac de Salla Bosc de l' Obac de Salla 42.55 1.5 V FRST AD 00 0 1292 Europe/Andorra 1993-12-23
+3039709 Obac d’Envalira Obac d'Envalira 42.55 1.68333 A ADMD AD 00 0 2254 Europe/Andorra 1993-12-23
+3039710 Obac d’Encamp Obac d'Encamp 42.51667 1.6 A ADMD AD 00 0 2085 Europe/Andorra 1993-12-23
+3039711 Obac del Tarter Obac del Tarter 42.56667 1.63333 A ADMD AD 00 0 2016 Europe/Andorra 1993-12-23
+3039712 Obac dels Cortals Obac dels Cortals 42.51667 1.61667 A ADMD AD 00 0 2254 Europe/Andorra 1993-12-23
+3039713 Obac de les Escaldes i Engordany Obac de les Escaldes i Engordany 42.5 1.53333 L LCTY AD 00 0 1574 Europe/Andorra 2007-04-05
+3039714 Obac de la Cebollera Obac de la Cebollera 42.61667 1.58333 L LCTY AD 00 0 2374 Europe/Andorra 1993-12-23
+3039715 Pont de l’ Obac de Fontaneda Pont de l' Obac de Fontaneda 42.45 1.46667 S BDG AD 00 0 935 Europe/Andorra 1993-12-23
+3039716 Obac de Canillo Obac de Canillo 42.56667 1.63333 A ADMD AD 00 0 2016 Europe/Andorra 1993-12-23
+3039717 Obac d’Anyós Obac d'Anyos 42.53333 1.53333 A ADMD AD 00 0 1521 Europe/Andorra 1993-12-23
+3039718 Serrat de l’ Obac Serrat de l' Obac 42.48333 1.5 T MT AD 00 0 1631 Europe/Andorra 1993-12-23
+3039719 Rec de l’ Obac Rec de l' Obac 42.5 1.53333 H CNL AD 00 0 1574 Europe/Andorra 1993-12-23
+3039720 Prats de l’ Obac Prats de l' Obac 42.53333 1.61667 L GRAZ AD 00 0 2237 Europe/Andorra 1993-12-23
+3039721 Font de l’ Obac Font de l' Obac 42.5 1.56667 H SPNG AD 00 0 1776 Europe/Andorra 1993-12-23
+3039722 Coll d’ Obac Coll d' Obac 42.5 1.46667 T PK AD 00 0 1678 Europe/Andorra 1993-12-23
+3039723 Torrent dels Nyerros Torrent dels Nyerros 42.48333 1.46667 H STM AD 00 0 1148 Europe/Andorra 1993-12-23
+3039724 Carretera General Número Un Carretera General Numero Un 42.5 1.53333 R RD AD 00 0 1574 Europe/Andorra 1993-12-23
+3039725 Carretera General Número Tres Carretera General Numero Tres 42.61667 1.48333 R RD AD 00 0 2470 Europe/Andorra 1993-12-23
+3039726 Carretera General Número Duo Carretera General Numero Duo 42.53333 1.73333 R RD AD 00 0 2300 Europe/Andorra 1993-12-23
+3039727 Pleta Nova Pleta Nova 42.61667 1.51667 L GRAZ AD 00 0 1716 Europe/Andorra 1993-12-23
+3039728 Obaga de Nou Fonts Obaga de Nou Fonts 42.46667 1.53333 T SLP AD 00 0 2332 Europe/Andorra 1993-12-23
+3039729 Nou Fonts Nou Fonts 42.46667 1.53333 T RDGE AD 00 0 2332 Europe/Andorra 1993-12-23
+3039730 Estany de la Nou Estany de la Nou 42.47539 1.5756 H LK AD 00 0 2349 Europe/Andorra 2011-04-19
+3039731 Pic d’ Ascobes Pic d' Ascobes Pic d' Ascobes,Pic de Noe,Pic de Noé,Pic d’ Ascobes 42.61667 1.73333 T PK AD 00 0 2508 Europe/Andorra 2011-11-05
+3039732 Basera del Niu de l’Aliga Basera del Niu de l'Aliga 42.5 1.45 T CLF AD 00 0 1840 Europe/Andorra 1993-12-23
+3039733 Collades de Nier Collades de Nier 42.61667 1.53333 T PASS AD 00 0 1609 Europe/Andorra 1993-12-23
+3039734 Bosc de les Neres Bosc de les Neres 42.53333 1.56667 V FRST AD 00 0 1418 Europe/Andorra 1993-12-23
+3039735 Bony de les Neres Bony de les Neres Bony de las Neras,Bony de les Neres,Bony de los Neros,Pic de las Neras 42.54761 1.56693 T MT AD 00 0 1828 Europe/Andorra 2011-11-05
+3039736 Roques Negres Roques Negres 42.5 1.46667 T RKS AD 00 0 1678 Europe/Andorra 1993-12-23
+3039737 Rocs Negres Rocs Negres 42.55 1.61667 T RKS AD 00 0 2206 Europe/Andorra 1993-12-23
+3039738 Canals Negres Canals Negres 42.56667 1.68333 H RVN AD 00 0 2340 Europe/Andorra 1993-12-23
+3039739 Serrat Negre Serrat Negre 42.58333 1.48333 T SPUR AD 00 0 1809 Europe/Andorra 1993-12-23
+3039740 Riu Negre Riu Negre 42.45 1.48333 H STM AD 00 0 1111 Europe/Andorra 1993-12-23
+3039741 Port de Comallempla Port de Comallempla Port Negre,Port de Comallempla 42.56667 1.45 T PASS AD 00 0 2137 Europe/Andorra 2011-11-05
+3039742 Pic Negre Pic Negre Pic Negre 42.56667 1.45 T PK AD 00 0 2137 Europe/Andorra 2011-11-05
+3039743 Pic Negre Pic Negre Pic Negre 42.45 1.56667 T PK AD 00 0 2558 Europe/Andorra 2011-11-05
+3039744 Forat Negre Forat Negre 42.5 1.5 H RVN AD 00 0 1135 Europe/Andorra 1993-12-23
+3039745 Estany Negre Estany Negre 42.58333 1.43333 H LK AD 00 0 2412 Europe/Andorra 1993-12-23
+3039746 Bosc Negre Bosc Negre 42.56667 1.55 V FRST AD 00 0 1996 Europe/Andorra 1993-12-23
+3039747 Bosc Negre Bosc Negre 42.53333 1.6 V FRST AD 00 0 1888 Europe/Andorra 1993-12-23
+3039748 Bosc Negre Bosc Negre 42.51667 1.48333 V FRST AD 00 0 1839 Europe/Andorra 1993-12-23
+3039749 Bosc Negre Bosc Negre 42.5 1.56667 V FRST AD 00 0 1776 Europe/Andorra 1993-12-23
+3039750 Bosc Negre Bosc Negre 42.48333 1.51667 V FRST AD 00 0 2061 Europe/Andorra 1993-12-23
+3039751 Bony Negre Bony Negre 42.56667 1.46667 T SPUR AD 00 0 1673 Europe/Andorra 1993-12-23
+3039752 Roca Negra Roca Negra 42.58333 1.58333 T RK AD 00 0 1993 Europe/Andorra 1993-12-23
+3039753 Torrent del Nedó Torrent del Nedo 42.46667 1.5 H STM AD 00 0 1383 Europe/Andorra 1993-12-23
+3039754 Font de la Navina Font de la Navina 42.55 1.56667 H SPNG AD 00 0 1828 Europe/Andorra 1993-12-23
+3039755 Llosers de Naudà Llosers de Naudi 42.56667 1.56667 S MNQR AD 00 0 2089 Europe/Andorra 1993-12-23
+3039756 Carretera de Nagol Carretera de Nagol 42.46667 1.48333 R RD AD 00 0 1134 Europe/Andorra 1993-12-23
+3039757 Nagol Nagol Nagol 42.47146 1.50314 P PPL AD 06 0 1383 Europe/Andorra 2011-11-05
+3039758 Solà de Nadal Sola de Nadal 42.51667 1.51667 T SLP AD 00 0 1265 Europe/Andorra 1993-12-23
+3039759 Obaga de les Mussoles Obaga de les Mussoles 42.55 1.63333 T SLP AD 00 0 2336 Europe/Andorra 1993-12-23
+3039760 Pla Mussola Pla Mussola 42.53333 1.56667 T UPLD AD 00 0 1418 Europe/Andorra 1993-12-23
+3039761 Camà de la Muntanya Cami de la Muntanya 42.5 1.56667 R TRL AD 00 0 1776 Europe/Andorra 1993-12-23
+3039762 Pleta de les Mules Pleta de les Mules 42.43333 1.53333 L GRAZ AD 00 0 2108 Europe/Andorra 1993-12-23
+3039763 Canal del Mulassar Canal del Mulassar 42.56667 1.51667 H STM AD 00 0 1500 Europe/Andorra 1993-12-23
+3039764 Bosc del Mulassar Bosc del Mulassar 42.56667 1.53333 V FRST AD 00 0 1669 Europe/Andorra 1993-12-23
+3039765 Basers del Motxo Basers del Motxo 42.6 1.63333 T CLF AD 00 0 1893 Europe/Andorra 1993-12-23
+3039766 Riu de Mossers Riu de Mossers 42.45 1.46667 H STM AD 00 0 935 Europe/Andorra 1993-12-23
+3039767 Pleta Mosquera Pleta Mosquera 42.63333 1.51667 L GRAZ AD 00 0 1894 Europe/Andorra 1993-12-23
+3039768 Mosquera Mosquera 42.55 1.58333 P PPL AD 03 0 1499 Europe/Andorra 1993-12-23
+3039769 Tosa de Moscatosa Tosa de Moscatosa 42.55 1.71667 T UPLD AD 00 0 2192 Europe/Andorra 1993-12-23
+3039770 Clots de Moscatosa Clots de Moscatosa 42.55 1.7 H RVN AD 00 0 2358 Europe/Andorra 1993-12-23
+3039771 Pont de Mos Pont de Mos 42.58333 1.63333 S BDG AD 00 0 1722 Europe/Andorra 1993-12-23
+3039772 Plana Mortalla Plana Mortalla 42.58333 1.55 T UPLD AD 00 0 2357 Europe/Andorra 1993-12-23
+3039773 Estany Mort Estany Mort 42.63333 1.61667 H LK AD 00 0 2541 Europe/Andorra 1993-12-23
+3039774 Estany Mort Estany Mort 42.58333 1.71667 H LK AD 00 0 2553 Europe/Andorra 1993-12-23
+3039775 Canya dels Moros Canya dels Moros 42.55 1.51667 S CAVE AD 00 0 1397 Europe/Andorra 1993-12-23
+3039776 Pleta de Moretó Pleta de Moreto 42.55 1.68333 L GRAZ AD 00 0 2254 Europe/Andorra 1993-12-23
+3039777 Planell de Moretó Planell de Moreto 42.55 1.68333 T UPLD AD 00 0 2254 Europe/Andorra 1993-12-23
+3039778 Bosc de Moretó Bosc de Moreto 42.55 1.7 V FRST AD 00 0 2358 Europe/Andorra 1993-12-23
+3039779 Estany Moreno Estany Moreno 42.51667 1.63333 H LK AD 00 0 2379 Europe/Andorra 1993-12-23
+3039780 Canal de Mora Canal de Mora 42.56667 1.58333 H STM AD 00 0 1919 Europe/Andorra 1993-12-23
+3039781 Tosal de la Truita Tosal de la Truita Pic de Monturull,Pic de Perafita,Tosal de la Truita 42.46667 1.58333 T PK AD 00 0 2367 Europe/Andorra 2011-11-05
+3039782 Riu de Montuell Riu de Montuell 42.51667 1.58333 H STM AD 00 0 1994 Europe/Andorra 1993-12-23
+3039783 Cap de Montuell Cap de Montuell 42.51667 1.61667 T PK AD 00 0 2254 Europe/Andorra 1993-12-23
+3039784 Roc de Montmantell Roc de Montmantell 42.59695 1.47085 T RDGE AD 00 0 2421 Europe/Andorra 2011-04-19
+3039785 Riu de Montmantell Riu de Montmantell 42.6 1.46667 H STM AD 00 0 2421 Europe/Andorra 1993-12-23
+3039786 Pleta de Montmantell Pleta de Montmantell 42.6 1.46667 L GRAZ AD 00 0 2421 Europe/Andorra 1993-12-23
+3039787 Obaga de Montmantell Obaga de Montmantell 42.6 1.46667 T SLP AD 00 0 2421 Europe/Andorra 1993-12-23
+3039788 Font de Montmantell Font de Montmantell 42.6 1.46667 H SPNG AD 00 0 2421 Europe/Andorra 1993-12-23
+3039789 Estanys de Montmantell Estanys de Montmantell 42.6 1.46667 H LKS AD 00 0 2421 Europe/Andorra 1993-12-23
+3039790 Collada de Montmantell Collada de Montmantell 42.6 1.46667 T PASS AD 00 0 2421 Europe/Andorra 1993-12-23
+3039791 Camà de Montmantell Cami de Montmantell 42.6 1.46667 R TRL AD 00 0 2421 Europe/Andorra 1993-12-23
+3039792 Montmantell Montmantell 42.6 1.46667 A ADMD AD 00 0 2421 Europe/Andorra 1993-12-23
+3039793 Pic de Montmalús Pic de Montmalus 42.50902 1.6861 T PK AD 00 0 2445 Europe/Andorra 2011-04-19
+3039794 Estany de Montmalús Estany de Montmalus 42.5 1.68333 H LK AD 00 0 2425 Europe/Andorra 1993-12-23
+3039795 Collada de Montmalús Collada de Montmalus 42.51667 1.7 T PASS AD 00 0 2435 Europe/Andorra 1993-12-23
+3039796 Montmalús Montmalus 42.5 1.7 A ADMD AD 00 0 2323 Europe/Andorra 1993-12-23
+3039797 Torrent de Montllobar Torrent de Montllobar 42.45 1.51667 H STM AD 00 0 1790 Europe/Andorra 1993-12-23
+3039798 Font de Montllobar Font de Montllobar 42.45 1.51667 H SPNG AD 00 0 1790 Europe/Andorra 1993-12-23
+3039799 Montllobar Montllobar 42.45 1.51667 L LCTY AD 00 0 1790 Europe/Andorra 1993-12-23
+3039800 Riu de Montaup Riu de Montaup 42.56667 1.6 H STM AD 00 0 1655 Europe/Andorra 1993-12-23
+3039801 Prats de Montaup Prats de Montaup 42.56667 1.58333 L GRAZ AD 00 0 1919 Europe/Andorra 1993-12-23
+3039802 Collet de Montaup Collet de Montaup 42.56667 1.58333 T SPUR AD 00 0 1919 Europe/Andorra 1993-12-23
+3039803 Carrera de Montaup Carrera de Montaup 42.56667 1.6 R RD AD 00 0 1655 Europe/Andorra 1993-12-23
+3039804 Barranc de Montaup Barranc de Montaup 42.56667 1.6 H STM AD 00 0 1655 Europe/Andorra 1993-12-23
+3039805 Montaup Montaup 42.58333 1.58333 A ADMD AD 00 0 1993 Europe/Andorra 1993-12-23
+3039806 Riu Montaner Riu Montaner 42.52965 1.52042 H STM AD 00 0 1361 Europe/Andorra 2011-04-19
+3039807 Collada de Montaner Collada de Montaner Col de Montaner,Col de Montanér,Coll de Montane,Coll de Montané,Collada de Montaner 42.51798 1.46716 T PASS AD 00 0 1840 Europe/Andorra 2011-11-05
+3039808 Riu de Montalarà Riu de Montalari 42.53333 1.58333 H STM AD 00 0 1571 Europe/Andorra 1993-12-23
+3039809 Bordes de Montalarà Bordes de Montalari 42.55 1.58333 S HUTS AD 00 0 1499 Europe/Andorra 1993-12-23
+3039810 Mónjol de Cabana Sorda Monjol de Cabana Sorda 42.61667 1.68333 T SLP AD 00 0 2406 Europe/Andorra 1993-12-23
+3039811 Canal del Monjo Canal del Monjo 42.48333 1.5 H STM AD 00 0 1631 Europe/Andorra 1993-12-23
+3039812 Tossal Momó Tossal Momo 42.53333 1.46667 T PK AD 00 0 1846 Europe/Andorra 1993-12-23
+3039813 Pleta dels Moltons Pleta dels Moltons 42.55 1.73333 L GRAZ AD 00 0 2100 Europe/Andorra 1993-12-23
+3039814 Obaga de la Mollerra Obaga de la Mollerra 42.6 1.51667 T SLP AD 00 0 1445 Europe/Andorra 1993-12-23
+3039815 Pont de Molleres Pont de Molleres 42.55 1.58333 S BDG AD 00 0 1499 Europe/Andorra 1993-12-23
+3039816 Canal de les Molleres Canal de les Molleres 42.51667 1.56667 H STM AD 00 0 1759 Europe/Andorra 1993-12-23
+3039817 Canal de les Molleres Canal de les Molleres 42.5 1.55 H STM AD 00 0 1566 Europe/Andorra 1993-12-23
+3039818 Bosc de les Molleres Bosc de les Molleres 42.51667 1.56667 V FRST AD 00 0 1759 Europe/Andorra 1993-12-23
+3039819 Molleres Molleres 42.55103 1.58958 P PPL AD 02 0 1640 Europe/Andorra 2011-04-19
+3039820 Molleres Molleres 42.55 1.58333 L LCTY AD 00 0 1499 Europe/Andorra 1993-12-23
+3039821 Bosc de la Mollera Bosc de la Mollera 42.6 1.51667 V FRST AD 00 0 1445 Europe/Andorra 1993-12-23
+3039822 Bordes de la Mollera Bordes de la Mollera 42.6 1.51667 S HUTS AD 00 0 1445 Europe/Andorra 1993-12-23
+3039823 Torrent de la Molina Torrent de la Molina 42.45 1.51667 H STM AD 00 0 1790 Europe/Andorra 1993-12-23
+3039824 Riu de la Molina Riu de la Molina 42.53333 1.6 H STM AD 00 0 1888 Europe/Andorra 1993-12-23
+3039825 Obaga de la Molina Obaga de la Molina 42.56667 1.48333 T SLP AD 00 0 1508 Europe/Andorra 1993-12-23
+3039826 Obaga de la Molina Obaga de la Molina 42.45 1.51667 T SLP AD 00 0 1790 Europe/Andorra 1993-12-23
+3039827 Grau de la Molina Grau de la Molina 42.53333 1.6 H RVN AD 00 0 1888 Europe/Andorra 1993-12-23
+3039828 Canal de la Molina Canal de la Molina 42.48333 1.56667 H STM AD 00 0 2231 Europe/Andorra 1993-12-23
+3039829 Canal de la Molina Canal de la Molina 42.48333 1.46667 H STM AD 00 0 1148 Europe/Andorra 1993-12-23
+3039830 Camà de la Molina Cami de la Molina 42.53333 1.6 R TRL AD 00 0 1888 Europe/Andorra 1993-12-23
+3039831 Bordes de la Molina Bordes de la Molina 42.51667 1.58333 S HUT AD 00 0 1994 Europe/Andorra 1993-12-23
+3039832 Plana Moleta Plana Moleta 42.56667 1.53333 T UPLD AD 00 0 1669 Europe/Andorra 1993-12-23
+3039833 Roc de les Moles Roc de les Moles 42.53333 1.51667 T RK AD 00 0 1361 Europe/Andorra 1993-12-23
+3039834 Pont de les Moles Pont de les Moles 42.6 1.53333 S BDG AD 00 0 1695 Europe/Andorra 1993-12-23
+3039835 Canal de les Moles Canal de les Moles 42.56667 1.61667 H RVN AD 00 0 1920 Europe/Andorra 1993-12-23
+3039836 Pont de la Mola Pont de la Mola 42.56667 1.66667 S BDG AD 00 0 1938 Europe/Andorra 1993-12-23
+3039837 Roc del Moixó Roc del Moixo 42.56667 1.5 T RK AD 00 0 1636 Europe/Andorra 1993-12-23
+3039838 Borda del Moixellaire Borda del Moixellaire 42.45 1.45 S HUTS AD 00 0 1482 Europe/Andorra 1993-12-23
+3039839 Torrent de la Moixella Torrent de la Moixella 42.43333 1.48333 H STM AD 00 0 1228 Europe/Andorra 1993-12-23
+3039840 Riu de la Moixella Riu de la Moixella 42.45 1.48333 H STM AD 00 0 1111 Europe/Andorra 1993-12-23
+3039841 Bosc de la Moixella Bosc de la Moixella 42.45 1.46667 V FRST AD 00 0 935 Europe/Andorra 1993-12-23
+3039842 Serra Mitjana Serra Mitjana 42.46667 1.61667 T RDGE AD 00 0 2448 Europe/Andorra 1993-12-23
+3039843 Serra Mitjana Serra Mitjana 42.46667 1.58333 T MT AD 00 0 2367 Europe/Andorra 1993-12-23
+3039844 Bony de Mitgeu Bony de Mitgeu 42.55 1.53333 T SPUR AD 00 0 1593 Europe/Andorra 1993-12-23
+3039845 Collet de la Mira Collet de la Mira 42.56667 1.53333 T SPUR AD 00 0 1669 Europe/Andorra 1993-12-23
+3039846 Serrat dels Miquelets Serrat dels Miquelets 42.55 1.6 T RDGE AD 00 0 2210 Europe/Andorra 1993-12-23
+3039847 Font dels Miquelets Font dels Miquelets 42.58333 1.43333 H SPNG AD 00 0 2412 Europe/Andorra 1993-12-23
+3039848 Pont de les Mines Pont de les Mines 42.6 1.53333 S BDG AD 00 0 1695 Europe/Andorra 1993-12-23
+3039849 Tosa del Mig Tosa del Mig 42.58333 1.7 T UPLD AD 00 0 2584 Europe/Andorra 1993-12-23
+3039850 Serra del Mig Serra del Mig 42.58333 1.71667 T RDGE AD 00 0 2553 Europe/Andorra 1993-12-23
+3039851 Roc del Mig Roc del Mig 42.56667 1.71667 T RK AD 00 0 2219 Europe/Andorra 1993-12-23
+3039852 Estany del Mig Estany del Mig 42.63999 1.48612 H LK AD 07 0 2254 Europe/Andorra 2007-03-04
+3039853 Coma del Mig Coma del Mig 42.65 1.53333 T CRQ AD 00 0 2564 Europe/Andorra 1993-12-23
+3039854 Collada del Mig Collada del Mig 42.61667 1.55 T SPUR AD 00 0 2007 Europe/Andorra 1993-12-23
+3039855 Clots del Mig Clots del Mig 42.56667 1.55 H RVN AD 00 0 1996 Europe/Andorra 1993-12-23
+3039856 Carrera del Mig Carrera del Mig 42.56667 1.61667 R TRL AD 00 0 1920 Europe/Andorra 1993-12-23
+3039857 Basers del Mig Basers del Mig 42.58333 1.7 T CLF AD 00 0 2584 Europe/Andorra 1993-12-23
+3039858 Clots de Més Amunt de la Pleta Clots de Mes Amunt de la Pleta 42.6 1.48333 T TAL AD 00 0 2441 Europe/Andorra 1993-12-23
+3039859 Pleta de Més Amunt Pleta de Mes Amunt 42.51667 1.63333 L GRAZ AD 00 0 2379 Europe/Andorra 1993-12-23
+3039860 Estany de Més Amunt Estany de Mes Amunt 42.6457 1.48659 H LK AD 07 0 2530 Europe/Andorra 2007-03-04
+3039861 Carretera Meritxell Carretera Meritxell 42.55 1.58333 R RD AD 00 0 1499 Europe/Andorra 1993-12-23
+3039862 Meritxell Meritxell Sanctuaire de Meritxeli,Sanctuaire de Meritxell,Santuari de Meritxell 42.55403 1.59087 P PPL AD AD 02 0 1640 Europe/Andorra 2007-04-16
+3039863 Rec de Mereig Rec de Mereig 42.56667 1.58333 H CNL AD 00 0 1919 Europe/Andorra 1993-12-23
+3039864 Pont de Mereig Pont de Mereig 42.55 1.6 S BDG AD 00 0 2210 Europe/Andorra 1993-12-23
+3039865 Planells de Mereig Planells de Mereig 42.56667 1.58333 T UPLD AD 00 0 1919 Europe/Andorra 1993-12-23
+3039866 Bosc de Mereig Bosc de Mereig 42.56667 1.58333 V FRST AD 00 0 1919 Europe/Andorra 1993-12-23
+3039867 Bordes de Mereig Bordes de Mereig 42.56302 1.58293 S FRMS AD 00 0 1637 Europe/Andorra 2011-04-19
+3039868 Mereig Mereig 42.56667 1.58333 A ADMD AD 00 0 1919 Europe/Andorra 1993-12-23
+3039869 Font de la Mentirosa Font de la Mentirosa 42.43333 1.51667 H SPNG AD 00 0 2031 Europe/Andorra 1993-12-23
+3039870 Estany dels Meners de la Coma Estany dels Meners de la Coma 42.61667 1.61667 H LK AD 00 0 2352 Europe/Andorra 1993-12-23
+3039871 Riu dels Meners Riu dels Meners 42.61667 1.63333 H STM AD 00 0 2331 Europe/Andorra 1993-12-23
+3039872 Font dels Meners Font dels Meners 42.61667 1.6 H SPNG AD 00 0 2528 Europe/Andorra 1993-12-23
+3039873 Font dels Meners Font dels Meners 42.46667 1.48333 H SPNG AD 00 0 1134 Europe/Andorra 1993-12-23
+3039874 Collada dels Meners Collada dels Meners 42.61667 1.6 T PASS AD 00 0 2528 Europe/Andorra 1993-12-23
+3039875 Pic de la Menera Pic de la Menera 42.51667 1.71667 T PK AD 00 0 2591 Europe/Andorra 1993-12-23
+3039876 Clots de la Menera Clots de la Menera 42.51667 1.71667 H RVN AD 00 0 2591 Europe/Andorra 1993-12-23
+3039877 Bosc del MenadÃs Bosc del Menadis 42.45 1.46667 V FRST AD 00 0 935 Europe/Andorra 1993-12-23
+3039878 Meligar d’Emportona Meligar d'Emportona 42.53333 1.66667 L LCTY AD 00 0 2489 Europe/Andorra 1993-12-23
+3039879 Serrat de Meligar Serrat de Meligar 42.55 1.45 T RDGE AD 00 0 1788 Europe/Andorra 1993-12-23
+3039880 Estany del Meligar Estany del Meligar 42.51667 1.66667 H LK AD 00 0 2410 Europe/Andorra 1993-12-23
+3039881 Roc del Melic Roc del Melic 42.58333 1.58333 T RK AD 00 0 1993 Europe/Andorra 1993-12-23
+3039882 Pic de Medécourbe Pic de Medecourbe Pic de Madecourbe,Pic de Medecorba,Pic de Medecourbe,Pic de Medécourbe 42.6037 1.44264 T PK AD 00 0 2914 2658 Europe/Andorra 2011-02-09
+3039883 Camà dels Matxos Cami dels Matxos 42.5 1.56667 R TRL AD 00 0 1776 Europe/Andorra 1993-12-23
+3039884 Basera Mateu Basera Mateu 42.5 1.5 T CLF AD 00 0 1135 Europe/Andorra 1993-12-23
+3039885 Serrat dels Matets Serrat dels Matets 42.56667 1.5 T SPUR AD 00 0 1636 Europe/Andorra 1993-12-23
+3039886 Bosc del Matet Bosc del Matet 42.61667 1.53333 V FRST AD 00 0 1609 Europe/Andorra 1993-12-23
+3039887 Bosc de les Matelles Bosc de les Matelles 42.51667 1.48333 V FRST AD 00 0 1839 Europe/Andorra 1993-12-23
+3039888 Clot de la Mata Clot de la Mata 42.56667 1.68333 T SLP AD 00 0 2340 Europe/Andorra 1993-12-23
+3039889 Canals de la Mata Canals de la Mata 42.61667 1.58333 H RVN AD 00 0 2374 Europe/Andorra 1993-12-23
+3039890 Canal de la Mata Canal de la Mata 42.51667 1.51667 H STM AD 00 0 1265 Europe/Andorra 1993-12-23
+3039891 Bosc de la Mata Bosc de la Mata 42.6 1.68333 V FRST AD 00 0 2089 Europe/Andorra 1993-12-23
+3039892 Bosc de la Mata Bosc de la Mata 42.6 1.61667 V FRST AD 00 0 2271 Europe/Andorra 1993-12-23
+3039893 Massolina Massolina 42.5 1.61667 H RVN AD 00 0 2560 Europe/Andorra 1993-12-23
+3039894 Riu de Massat Riu de Massat 42.556 1.68641 H STM AD 00 0 2083 Europe/Andorra 2011-04-19
+3039895 Cortal del Masover Cortal del Masover 42.53333 1.53333 S CRRL AD 00 0 1521 Europe/Andorra 1993-12-23
+3039896 Mas de Ribafeta Mas de Ribafeta 42.56936 1.48837 P PPL AD 04 0 1655 Europe/Andorra 2011-04-19
+3039897 Pont del Mas d’En Soler Pont del Mas d'En Soler 42.56667 1.51667 S BDG AD 00 0 1500 Europe/Andorra 1993-12-23
+3039898 Devesa del Mas d’Alins Devesa del Mas d'Alins 42.45 1.45 L GRAZ AD 00 0 1482 Europe/Andorra 1993-12-23
+3039899 Carretera del Mas d’Alins Carretera del Mas d'Alins 42.45 1.46667 R RD AD 00 0 935 Europe/Andorra 1993-12-23
+3039900 Borda del Mas d’Alins Borda del Mas d'Alins 42.43333 1.45 S HUTS AD 00 0 877 Europe/Andorra 1993-12-23
+3039901 Mas d’Alins Mas d'Alins 42.44126 1.44944 P PPL AD 06 0 1197 Europe/Andorra 2011-04-19
+3039902 Mas d’Alins Mas d'Alins 42.45 1.45 A ADMD AD 00 0 1482 Europe/Andorra 1993-12-23
+3039903 Solà del Mas Sola del Mas 42.45 1.5 T SLP AD 00 0 1614 Europe/Andorra 1993-12-23
+3039904 Obac del Mas Obac del Mas 42.56667 1.5 T SLP AD 00 0 1636 Europe/Andorra 1993-12-23
+3039905 Camà del Mas Cami del Mas 42.45 1.5 R TRL AD 00 0 1614 Europe/Andorra 1993-12-23
+3039906 Bordes del Mas Bordes del Mas 42.45 1.5 S HUTS AD 00 0 1614 Europe/Andorra 1993-12-23
+3039907 Allau del Mas Allau del Mas 42.56667 1.48333 H STM AD 00 0 1508 Europe/Andorra 1993-12-23
+3039908 Borda del Marticella Borda del Marticella 42.58333 1.65 S HUT AD 00 0 1767 Europe/Andorra 1993-12-23
+3039909 Cortal del Martà Cortal del Marti 42.53333 1.53333 S CRRL AD 00 0 1521 Europe/Andorra 1993-12-23
+3039910 Collet Martà Collet Marti 42.5 1.48333 T SPUR AD 00 0 1316 Europe/Andorra 1993-12-23
+3039911 Collet Martà Collet Marti 42.46667 1.46667 T PK AD 00 0 1340 Europe/Andorra 1993-12-23
+3039912 Borda del Martà Borda del Marti 42.56667 1.6 S HUT AD 00 0 1655 Europe/Andorra 1993-12-23
+3039913 Marrades Negres Marrades Negres 42.56667 1.7 T TAL AD 00 0 2375 Europe/Andorra 1993-12-23
+3039914 Marrades Negres Marrades Negres 42.56667 1.55 H STM AD 00 0 1996 Europe/Andorra 1993-12-23
+3039915 Camà de les Marrades Cami de les Marrades 42.55 1.5 R TRL AD 00 0 1292 Europe/Andorra 1993-12-23
+3039916 Bony de les Marrades Bony de les Marrades 42.53333 1.5 T PK AD 00 0 1357 Europe/Andorra 1993-12-23
+3039917 Roc de Maria Roc de Maria 42.5 1.48333 T RK AD 00 0 1316 Europe/Andorra 1993-12-23
+3039918 Canal de Maria Canal de Maria 42.56667 1.48333 H STM AD 00 0 1508 Europe/Andorra 1993-12-23
+3039919 Pont de la Margineda Pont de la Margineda 42.4838 1.49042 S BDG AD 00 0 991 Europe/Andorra 2011-04-19
+3039920 Coll de la Manyiga Coll de la Manyiga 42.46667 1.53333 T SPUR AD 00 0 2332 Europe/Andorra 1993-12-23
+3039921 Coll de la Manyiga Coll de la Manyiga 42.46667 1.48333 T PASS AD 00 0 1134 Europe/Andorra 1993-12-23
+3039922 Cortals de Manyat Cortals de Manyat 42.48333 1.51667 S HUTS AD 00 0 2061 Europe/Andorra 1993-12-23
+3039923 Manyat Manyat 42.47591 1.51661 L LCTY AD 00 0 1892 Europe/Andorra 2011-04-19
+3039924 Riu del Manegor Riu del Manegor 42.6 1.68333 H STM AD 00 0 2089 Europe/Andorra 1993-12-23
+3039925 Pleta del Manegor Pleta del Manegor 42.61667 1.7 L GRAZ AD 00 0 2285 Europe/Andorra 1993-12-23
+3039926 Bosc de la Mandurana Bosc de la Mandurana 42.56667 1.61667 V FRST AD 00 0 1920 Europe/Andorra 1993-12-23
+3039927 Borda del Mandicó Borda del Mandico 42.51667 1.55 S HUT AD 00 0 1322 Europe/Andorra 1993-12-23
+3039928 Pont del Mamó Pont del Mamo 42.55 1.48333 S BDG AD 00 0 1548 Europe/Andorra 1993-12-23
+3039929 Font de Mallol Font de Mallol 42.55 1.55 H SPNG AD 00 0 2097 Europe/Andorra 1993-12-23
+3039930 Canals Males Canals Males 42.46667 1.48333 H STM AD 00 0 1134 Europe/Andorra 1993-12-23
+3039931 Canals Males Canals Males 42.58333 1.46667 H RVN AD 00 0 1643 Europe/Andorra 1993-12-23
+3039932 Canal Mala Canal Mala 42.45 1.5 H RVN AD 00 0 1614 Europe/Andorra 1993-12-23
+3039933 Roca Major Roca Major 42.43333 1.5 T PK AD 00 0 1804 Europe/Andorra 1993-12-23
+3039934 Clot dels Mais Clot dels Mais 42.56667 1.61667 H RVN AD 00 0 1920 Europe/Andorra 1993-12-23
+3039935 Planada dels Maians Planada dels Maians 42.55 1.61667 T UPLD AD 00 0 2206 Europe/Andorra 1993-12-23
+3039936 Pic dels Maians Pic dels Maians 42.55 1.61667 T PK AD 00 0 2206 Europe/Andorra 1993-12-23
+3039937 Costa dels Maians Costa dels Maians 42.55 1.61667 T SLP AD 00 0 2206 Europe/Andorra 1993-12-23
+3039938 Canal dels Maians Canal dels Maians 42.5 1.51667 H STM AD 00 0 1410 Europe/Andorra 1993-12-23
+3039939 Bosc dels Maians Bosc dels Maians 42.48333 1.51667 V FRST AD 00 0 2061 Europe/Andorra 1993-12-23
+3039940 Bony dels Maians Bony dels Maians 42.53333 1.61667 T SPUR AD 00 0 2237 Europe/Andorra 1993-12-23
+3039941 Pic de la Maiana Pic de la Maiana 42.4821 1.60014 T PK AD 00 0 2250 Europe/Andorra 2011-04-19
+3039942 Collada de la Maiana Collada de la Maiana 42.48333 1.6 T PASS AD 00 0 2250 Europe/Andorra 1993-12-23
+3039943 Tosa del Maià Tosa del Maia 42.55 1.71667 T UPLD AD 00 0 2192 Europe/Andorra 1993-12-23
+3039944 Pleta del Maià Pleta del Maia 42.56667 1.73333 L GRAZ AD 00 0 2096 Europe/Andorra 1993-12-23
+3039945 Pic del Maià Pic del Maia Pic Mata,Pic del Maia,Pic del Maià 42.55 1.71667 T PK AD AD 00 0 2192 Europe/Andorra 2011-11-05
+3039946 Obagot del Maià Obagot del Maia 42.56667 1.73333 T SLP AD 00 0 2096 Europe/Andorra 1993-12-23
+3039947 Riu Madriu Riu Madriu Madriu,Riu Madriu 42.49697 1.57954 H STM AD 00 0 1888 Europe/Andorra 2011-11-05
+3039948 Basers de Madona Basers de Madona 42.61667 1.63333 T CLF AD 00 0 2331 Europe/Andorra 1993-12-23
+3039949 Canal de Luixent Passader Canal de Luixent Passader 42.5 1.5 H STM AD 00 0 1135 Europe/Andorra 1993-12-23
+3039950 L’Ovella L'Ovella 42.56667 1.6 L LCTY AD 00 0 1655 Europe/Andorra 1993-12-23
+3039951 Los Travessers Los Travessers 42.56667 1.43333 L LCTY AD 00 0 2402 Europe/Andorra 1993-12-23
+3039952 L’Orri Amagat L'Orri Amagat 42.6 1.6 L LCTY AD 00 0 2143 Europe/Andorra 1993-12-23
+3039953 L’Obagueta L'Obagueta 42.53333 1.55 L LCTY AD 00 0 1344 Europe/Andorra 1993-12-23
+3039954 Roc dels Llumeners Roc dels Llumeners 42.58333 1.46667 T RK AD 00 0 1643 Europe/Andorra 1993-12-23
+3039955 Canal dels Llumeners Canal dels Llumeners 42.58333 1.46667 H RVN AD 00 0 1643 Europe/Andorra 1993-12-23
+3039956 Riu de Llumeneres Riu de Llumeneres 42.46591 1.49579 H STM AD 00 0 1232 Europe/Andorra 2011-04-19
+3039957 Plana de Llumeneres Plana de Llumeneres 42.46667 1.51667 T UPLD AD 00 0 1985 Europe/Andorra 1993-12-23
+3039958 Cortal de Llumeneres Cortal de Llumeneres 42.46667 1.5 S CRRL AD 00 0 1383 Europe/Andorra 1993-12-23
+3039959 Llumeneres Llumeneres Llumeneres 42.46667 1.51667 P PPL AD 06 0 1985 Europe/Andorra 2011-11-05
+3039960 Canals del Lloset Canals del Lloset 42.53333 1.58333 H STM AD 00 0 1571 Europe/Andorra 1993-12-23
+3039961 Canal del Lloset Canal del Lloset 42.55 1.5 H STM AD 00 0 1292 Europe/Andorra 1993-12-23
+3039962 Bordes del Lloset Bordes del Lloset 42.55 1.6 S HUT AD 00 0 2210 Europe/Andorra 1993-12-23
+3039963 Lloset Lloset 42.53333 1.6 A ADMD AD 00 0 1888 Europe/Andorra 1993-12-23
+3039964 Costa del Lloser de Naudà Costa del Lloser de Naudi 42.56667 1.56667 T SLP AD 00 0 2089 Europe/Andorra 1993-12-23
+3039965 Solana del Lloser Solana del Lloser 42.46667 1.45 T SLP AD 00 0 1562 Europe/Andorra 1993-12-23
+3039966 Roc del Lloser Roc del Lloser 42.58333 1.51667 T RK AD 00 0 1722 Europe/Andorra 1993-12-23
+3039967 Canal del Lloser Canal del Lloser 42.51667 1.51667 H STM AD 00 0 1265 Europe/Andorra 1993-12-23
+3039968 Tossal de la Llosada Tossal de la Llosada Pic Llosada,Tossal de la Llosada 42.54862 1.64567 T PK AD 00 0 2422 Europe/Andorra 2011-11-05
+3039969 Tosa de la Llosada Tosa de la Llosada 42.55 1.63333 T UPLD AD 00 0 2336 Europe/Andorra 1993-12-23
+3039970 Riu de la Llosada Riu de la Llosada 42.53333 1.6 H STM AD 00 0 1888 Europe/Andorra 1993-12-23
+3039971 Obaga de la Llosada Obaga de la Llosada 42.53333 1.61667 T SLP AD 00 0 2237 Europe/Andorra 1993-12-23
+3039972 Emprius de la Llosada Emprius de la Llosada 42.53333 1.61667 L CMN AD 00 0 2237 Europe/Andorra 1993-12-23
+3039973 Basers de la Llosada Basers de la Llosada 42.55 1.63333 T CLF AD 00 0 2336 Europe/Andorra 1993-12-23
+3039974 Riu Llosà Riu Llosa 42.45 1.46667 H STM AD 00 0 935 Europe/Andorra 1993-12-23
+3039975 Grau de la Llosa Grau de la Llosa 42.61667 1.55 T SLP AD 00 0 2007 Europe/Andorra 1993-12-23
+3039976 Collet de la Llosa Collet de la Llosa 42.56667 1.5 T PASS AD 00 0 1636 Europe/Andorra 1993-12-23
+3039977 Clots de la Llosa Clots de la Llosa 42.61667 1.61667 H RVN AD 00 0 2352 Europe/Andorra 1993-12-23
+3039978 Canal de la Llosa Canal de la Llosa 42.56667 1.5 H STM AD 00 0 1636 Europe/Andorra 1993-12-23
+3039979 Llorts Llorts Llors,Llorta,Lors 42.59625 1.52658 P PPL AD AD 05 0 1695 Europe/Andorra 2007-04-16
+3039980 Canal de les Llongues Canal de les Llongues 42.55 1.51667 H STM AD 00 0 1397 Europe/Andorra 1993-12-23
+3039981 Bosc de les Llongues Bosc de les Llongues 42.55 1.51667 V FRST AD 00 0 1397 Europe/Andorra 1993-12-23
+3039982 Costa dels Llomassos Costa dels Llomassos 42.58333 1.45 T SLP AD 00 0 2156 Europe/Andorra 1993-12-23
+3039983 Canal dels Llomassos Canal dels Llomassos 42.55 1.46667 H STM AD 00 0 1585 Europe/Andorra 1993-12-23
+3039984 Pleta del Llomar Pleta del Llomar 42.61667 1.56667 L GRAZ AD 00 0 2228 Europe/Andorra 1993-12-23
+3039985 Clot del Llomar Clot del Llomar 42.53333 1.48333 H RVN AD 00 0 1677 Europe/Andorra 1993-12-23
+3039986 Camà de la Llobatera Cami de la Llobatera 42.55 1.48333 R TRL AD 00 0 1548 Europe/Andorra 1993-12-23
+3039987 Canal Llisa Canal Llisa 42.56667 1.51667 H STM AD 00 0 1500 Europe/Andorra 1993-12-23
+3039988 Canal Llisa Canal Llisa 42.53333 1.6 H STM AD 00 0 1888 Europe/Andorra 1993-12-23
+3039989 Torrent Llimois Torrent Llimois 42.48333 1.43333 H STM AD 00 0 1938 Europe/Andorra 1993-12-23
+3039990 Solana dels Llimois Solana dels Llimois 42.5 1.43333 T SLP AD 00 0 1654 Europe/Andorra 1993-12-23
+3039991 Bosc de Llevai Bosc de Llevai 42.53333 1.55 V FRST AD 00 0 1344 Europe/Andorra 1993-12-23
+3039992 Basers de la Llessa Basers de la Llessa 42.48333 1.5 T CLF AD 00 0 1631 Europe/Andorra 1993-12-23
+3039993 Planell de la Llentiga Planell de la Llentiga 42.6 1.51667 T UPLD AD 00 0 1445 Europe/Andorra 1993-12-23
+3039994 Barranc del Llempo Barranc del Llempo 42.55 1.51667 H STM AD 00 0 1397 Europe/Andorra 1993-12-23
+3039995 Casa Llècsia Casa Llecsia 42.56667 1.6 S HSE AD 00 0 1655 Europe/Andorra 1993-12-23
+3039996 Borda del Llècsia Borda del Llecsia 42.58333 1.6 S HUT AD 00 0 1828 Europe/Andorra 1993-12-23
+3039997 Solana dels Llaurers Solana dels Llaurers 42.48333 1.43333 T SLP AD 00 0 1938 Europe/Andorra 1993-12-23
+3039998 Obaga dels Llaurers Obaga dels Llaurers 42.48333 1.43333 T SLP AD 00 0 1938 Europe/Andorra 1993-12-23
+3039999 Bony dels Llaurers Bony dels Llaurers 42.48333 1.43333 T PK AD 00 0 1938 Europe/Andorra 1993-12-23
+3040000 Roc Llarg Roc Llarg 42.55 1.45 T SPUR AD 00 0 1788 Europe/Andorra 1993-12-23
+3040001 Pont del Llarg Pont del Llarg 42.6 1.68333 S BDG AD 00 0 2089 Europe/Andorra 1993-12-23
+3040002 Fontanal Llarg Fontanal Llarg 42.53333 1.46667 H SPNG AD 00 0 1846 Europe/Andorra 1993-12-23
+3040003 Casa Llarg Casa Llarg 42.55 1.58333 S HSE AD 00 0 1499 Europe/Andorra 1993-12-23
+3040004 Canal del Llarg Canal del Llarg 42.5 1.48333 H STM AD 00 0 1316 Europe/Andorra 1993-12-23
+3040005 Solana dels Llampells Solana dels Llampells 42.51667 1.46667 T SLP AD 00 0 1840 Europe/Andorra 1993-12-23
+3040006 Torrent de la Llampa Torrent de la Llampa 42.56667 1.6 H STM AD 00 0 1655 Europe/Andorra 1993-12-23
+3040007 Riu dels Llacs Riu dels Llacs 42.55 1.43333 H STM AD 00 0 1949 Europe/Andorra 1993-12-23
+3040008 Pleta dels Llacs Pleta dels Llacs 42.6 1.63333 L GRAZ AD 00 0 1893 Europe/Andorra 1993-12-23
+3040009 Pic dels Llacs Pic dels Llacs Pic dels Llacs 42.53333 1.41667 T PK AD 00 0 1948 Europe/Andorra 2011-11-05
+3040010 Pales dels Llacs Pales dels Llacs 42.6 1.61667 T CLF AD 00 0 2271 Europe/Andorra 1993-12-23
+3040011 Font dels Llacs Font dels Llacs 42.55 1.43333 H SPNG AD 00 0 1949 Europe/Andorra 1993-12-23
+3040012 Bosc dels Llacs Bosc dels Llacs 42.55 1.41667 V FRST AD 00 0 2105 Europe/Andorra 1993-12-23
+3040013 L’Hospital L'Hospital 42.48333 1.55 A ADMD AD 00 0 2233 Europe/Andorra 1993-12-23
+3040014 L’Hortó L'Horto 42.58333 1.63333 L LCTY AD 00 0 1722 Europe/Andorra 1993-12-23
+3040015 L’Hortó L'Horto 42.56667 1.51667 L LCTY AD 00 0 1500 Europe/Andorra 1993-12-23
+3040016 L’Hortell L'Hortell 42.61667 1.51667 L LCTY AD 00 0 1716 Europe/Andorra 1993-12-23
+3040017 Les Tres Oles Les Tres Oles 42.51667 1.55 H RVN AD 00 0 1322 Europe/Andorra 1993-12-23
+3040018 Les Tres Fonts Les Tres Fonts 42.5 1.46667 H SPNG AD 00 0 1678 Europe/Andorra 1993-12-23
+3040019 Les Tarteres Les Tarteres 42.45 1.48333 L LCTY AD 00 0 1111 Europe/Andorra 1993-12-23
+3040020 L’Estanyassa L'Estanyassa 42.58333 1.65 L LCTY AD 00 0 1767 Europe/Andorra 1993-12-23
+3040021 Les Tallades Les Tallades 42.61667 1.55 A ADMD AD 00 0 2007 Europe/Andorra 1993-12-23
+3040022 L’Estall L'Estall 42.5 1.58333 L LCTY AD 00 0 1888 Europe/Andorra 1993-12-23
+3040023 Les Sorobilles Les Sorobilles 42.56667 1.53333 T CLF AD 00 0 1669 Europe/Andorra 1993-12-23
+3040024 Les Solanelles Les Solanelles 42.55 1.6 L LCTY AD 00 0 2210 Europe/Andorra 1993-12-23
+3040025 Les Sobiranes Les Sobiranes 42.61667 1.55 L LCTY AD 00 0 2007 Europe/Andorra 1993-12-23
+3040026 Les Salses Les Salses 42.63333 1.5 T SLP AD 00 0 1979 Europe/Andorra 1993-12-23
+3040027 Les Salines Les Salines 42.60952 1.53697 P PPL AD 05 0 1793 Europe/Andorra 2007-04-16
+3040028 Les Ribaltes Les Ribaltes 42.53333 1.53333 L LCTY AD 00 0 1521 Europe/Andorra 1993-12-23
+3040029 Les Rebes Les Rebes 42.61667 1.61667 T UPLD AD 00 0 2352 Europe/Andorra 1993-12-23
+3040030 Les Queroles Les Queroles 42.6 1.53333 L LCTY AD 00 0 1695 Europe/Andorra 1993-12-23
+3040031 Les Portes Les Portes 42.48333 1.48333 L LCTY AD 00 0 981 Europe/Andorra 1993-12-23
+3040032 Les Planes de Sornàs Les Planes de Sornas 42.56667 1.53333 L LCTY AD 00 0 1669 Europe/Andorra 1993-12-23
+3040033 Les Planes Les Planes 42.63333 1.5 L LCTY AD 00 0 1979 Europe/Andorra 1993-12-23
+3040034 Les Planes Les Planes 42.53333 1.6 A ADMD AD 00 0 1888 Europe/Andorra 1993-12-23
+3040035 Les Planades Les Planades 42.6 1.68333 L LCTY AD 00 0 2089 Europe/Andorra 1993-12-23
+3040036 Les Pedrusques Les Pedrusques 42.51667 1.63333 T SLP AD 00 0 2379 Europe/Andorra 1993-12-23
+3040037 Les Pedrasses Les Pedrasses 42.55 1.51667 L LCTY AD 00 0 1397 Europe/Andorra 1993-12-23
+3040038 Les Pardines Les Pardines 42.58333 1.48333 T SLP AD 00 0 1809 Europe/Andorra 1993-12-23
+3040039 Les Pardines Les Pardines 42.43333 1.46667 S HUTS AD 00 0 1113 Europe/Andorra 1993-12-23
+3040040 Les Obagues Les Obagues 42.58333 1.48333 L LCTY AD 00 0 1809 Europe/Andorra 1993-12-23
+3040041 Les Neres Les Neres 42.55 1.56667 A ADMD AD 00 0 1828 Europe/Andorra 1993-12-23
+3040042 Les Molleres Les Molleres 42.55 1.53333 L LCTY AD 00 0 1593 Europe/Andorra 1993-12-23
+3040043 Les Majobarnes Les Majobarnes 42.55 1.48333 L LCTY AD 00 0 1548 Europe/Andorra 1993-12-23
+3040044 Les Llanasques Les Llanasques 42.58333 1.58333 L LCTY AD 00 0 1993 Europe/Andorra 1993-12-23
+3040045 Les Forques Les Forques 42.55 1.53333 L LCTY AD 00 0 1593 Europe/Andorra 1993-12-23
+3040046 Les Fonts Les Fonts 42.6 1.6 T UPLD AD 00 0 2143 Europe/Andorra 1993-12-23
+3040047 Les Fonts Les Fonts 42.6 1.48333 L LCTY AD 00 0 2441 Europe/Andorra 1993-12-23
+3040048 Les Feixes Les Feixes 42.55 1.43333 L LCTY AD 00 0 1949 Europe/Andorra 1993-12-23
+3040049 Les Feixes Les Feixes 42.53333 1.46667 L LCTY AD 00 0 1846 Europe/Andorra 1993-12-23
+3040050 Les Fargues Les Fargues 42.48333 1.6 S ANS AD 00 0 2250 Europe/Andorra 1993-12-23
+3040051 les Escaldes les Escaldes Ehskal'des-Ehndzhordani,Escaldes,Escaldes-Engordany,Les Escaldes,esukarudesu=engorudani jiao qu,lai sai si ka er de-en ge er da,ÐÑкальдеÑ-Ðнджордани,エスカルデスï¼ã‚¨ãƒ³ã‚´ãƒ«ãƒ€ãƒ‹æ•™åŒº,èŠå¡žæ–¯å¡çˆ¾å¾·-æ©æˆˆçˆ¾é”,èŠå¡žæ–¯å¡çˆ¾å¾·ï¼æ©æˆˆçˆ¾é” 42.50729 1.53414 P PPLA AD 08 15853 1350 Europe/Andorra 2008-10-15
+3040052 Les Deveses Les Deveses 42.53333 1.65 A ADMD AD 00 0 2508 Europe/Andorra 1993-12-23
+3040053 Les Costes Les Costes 42.51667 1.55 A ADMD AD 00 0 1322 Europe/Andorra 1993-12-23
+3040054 Les Costeres Les Costeres 42.53333 1.53333 L LCTY AD 00 0 1521 Europe/Andorra 1993-12-23
+3040055 Les Comelletes Les Comelletes 42.48333 1.46667 L LCTY AD 00 0 1148 Europe/Andorra 1993-12-23
+3040056 Les Comarques Les Comarques 42.55 1.51667 L LCTY AD 00 0 1397 Europe/Andorra 1993-12-23
+3040057 Les Colleroles Les Colleroles 42.58333 1.6 T SLP AD 00 0 1828 Europe/Andorra 1993-12-23
+3040058 Les Codolles Les Codolles 42.53333 1.51667 L LCTY AD 00 0 1361 Europe/Andorra 1993-12-23
+3040059 L’Escobar L'Escobar 42.61667 1.68333 L LCTY AD 00 0 2406 Europe/Andorra 1993-12-23
+3040060 Les Claperes Les Claperes 42.55 1.5 L LCTY AD 00 0 1292 Europe/Andorra 1993-12-23
+3040061 Les Carboneres Les Carboneres 42.48333 1.46667 L LCTY AD 00 0 1148 Europe/Andorra 1993-12-23
+3040062 Les Canyorques Les Canyorques 42.58333 1.43333 T SLP AD 00 0 2412 Europe/Andorra 1993-12-23
+3040063 Les Canals Les Canals 42.58333 1.58333 L LCTY AD 00 0 1993 Europe/Andorra 1993-12-23
+3040064 Les Canaletes Les Canaletes 42.6 1.45 T RKS AD 00 0 2174 Europe/Andorra 1993-12-23
+3040065 Les Canadilles Les Canadilles 42.48333 1.48333 H STM AD 00 0 981 Europe/Andorra 1993-12-23
+3040066 Les Bordes Les Bordes 42.58333 1.63333 S HUTS AD 00 0 1722 Europe/Andorra 1993-12-23
+3040067 Les Bons Les Bons Els Bons 42.53873 1.58649 P PPL AD AD 03 0 1490 Europe/Andorra 2007-04-16
+3040068 Les Bartigues Les Bartigues 42.6 1.53333 L LCTY AD 00 0 1695 Europe/Andorra 1993-12-23
+3040069 Les Barreres Les Barreres 42.55 1.6 L LCTY AD 00 0 2210 Europe/Andorra 1993-12-23
+3040070 Les Barreres Les Barreres 42.53333 1.53333 L LCTY AD 00 0 1521 Europe/Andorra 1993-12-23
+3040071 Les Bagelles Les Bagelles 42.46667 1.5 L LCTY AD 00 0 1383 Europe/Andorra 1993-12-23
+3040072 Les Aubes Les Aubes 42.51667 1.55 L LCTY AD 00 0 1322 Europe/Andorra 1993-12-23
+3040073 Les Aspades Les Aspades 42.56667 1.55 L LCTY AD 00 0 1996 Europe/Andorra 1993-12-23
+3040074 Les Angleves Les Angleves 42.53333 1.53333 L LCTY AD 00 0 1521 Europe/Andorra 1993-12-23
+3040075 Les Allaus Les Allaus 42.63333 1.53333 L LCTY AD 00 0 2072 Europe/Andorra 1993-12-23
+3040076 Les Agols Les Agols 42.51667 1.6 A ADMD AD 00 0 2085 Europe/Andorra 1993-12-23
+3040077 Les Abelletes Les Abelletes 42.53333 1.73333 L LCTY AD 00 0 2300 Europe/Andorra 1993-12-23
+3040078 L’Ensegur L'Ensegur 42.58333 1.53333 A ADMD AD 00 0 1924 Europe/Andorra 1993-12-23
+3040079 L’Avetar L'Avetar 42.6 1.68333 L LCTY AD 00 0 2089 Europe/Andorra 1993-12-23
+3040080 Planell de Laverdú Planell de Laverdu 42.63333 1.53333 T UPLD AD 00 0 2072 Europe/Andorra 1993-12-23
+3040081 Laverdú Laverdu 42.63333 1.53333 L LCTY AD 00 0 2072 Europe/Andorra 1993-12-23
+3040082 La Vaquerissa La Vaquerissa 42.55 1.45 L LCTY AD 00 0 1788 Europe/Andorra 1993-12-23
+3040083 L’Ausany L'Ausany 42.61667 1.53333 L LCTY AD 00 0 1609 Europe/Andorra 1993-12-23
+3040084 La Uïna La Uina 42.55 1.51667 A ADMD AD 00 0 1397 Europe/Andorra 1993-12-23
+3040085 La Trava La Trava 42.58333 1.61667 L LCTY AD 00 0 1707 Europe/Andorra 1993-12-23
+3040086 La Trava La Trava 42.56667 1.53333 L GRAZ AD 00 0 1669 Europe/Andorra 1993-12-23
+3040087 La Tosa La Tosa 42.56667 1.46667 L LCTY AD 00 0 1673 Europe/Andorra 1993-12-23
+3040088 L’Assalador L'Assalador 42.5 1.43333 L GRAZ AD 00 0 1654 Europe/Andorra 1993-12-23
+3040089 L’Asparró L'Asparro 42.48333 1.5 T PK AD 00 0 1631 Europe/Andorra 1993-12-23
+3040090 La Solaneta La Solaneta 42.53333 1.53333 L LCTY AD 00 0 1521 Europe/Andorra 1993-12-23
+3040091 La Solanella La Solanella 42.46667 1.5 L LCTY AD 00 0 1383 Europe/Andorra 1993-12-23
+3040092 La Solana La Solana 42.58333 1.76667 A ADMD AD 00 0 1945 Europe/Andorra 1993-12-23
+3040093 La Serreta La Serreta 42.58333 1.61667 T SPUR AD 00 0 1707 Europe/Andorra 1993-12-23
+3040094 La Serradora La Serradora 42.46667 1.46667 L LCTY AD 00 0 1340 Europe/Andorra 1993-12-23
+3040095 La Serra La Serra 42.45204 1.49609 S HUTS AD 00 0 1270 Europe/Andorra 2011-04-19
+3040096 La Senyoreta La Senyoreta 42.45 1.48333 A ADMD AD 00 0 1111 Europe/Andorra 1993-12-23
+3040097 L’Artiga L'Artiga 42.56946 1.60243 L LCTY AD 00 0 1655 Europe/Andorra 2011-04-19
+3040098 L’Artic L'Artic 42.5 1.46667 L LCTY AD 00 0 1678 Europe/Andorra 1993-12-23
+3040099 La Rovira La Rovira 42.45 1.46667 L LCTY AD 00 0 935 Europe/Andorra 1993-12-23
+3040100 La Roca La Roca 42.55 1.58333 L LCTY AD 00 0 1499 Europe/Andorra 1993-12-23
+3040101 L’Armiana L'Armiana 42.58333 1.6 A ADMD AD 00 0 1828 Europe/Andorra 1993-12-23
+3040102 La Riberola La Riberola 42.45 1.48333 L LCTY AD 00 0 1111 Europe/Andorra 1993-12-23
+3040103 La Rabassa La Rabassa 42.63333 1.55 A ADMD AD 00 0 2053 Europe/Andorra 1993-12-23
+3040104 La Rabassa La Rabassa Bois de la Rabassa,Bois de la Rabossa,La Rabassa 42.43333 1.51667 A ADMD AD AD 00 0 2031 Europe/Andorra 2011-11-05
+3040105 La Quera La Quera 42.51667 1.51667 L LCTY AD 00 0 1265 Europe/Andorra 1993-12-23
+3040106 La Presó La Preso 42.61667 1.56667 L LCTY AD 00 0 2228 Europe/Andorra 1993-12-23
+3040107 La Posa La Posa 42.53333 1.6 L LCTY AD 00 0 1888 Europe/Andorra 1993-12-23
+3040108 La Portelleta La Portelleta 42.48333 1.65 L LCTY AD 00 0 2658 Europe/Andorra 1993-12-23
+3040109 La Portella La Portella 42.55218 1.62761 T PK AD 00 0 2364 Europe/Andorra 2011-04-19
+3040110 La Portella La Portella 42.45 1.5 T PK AD 00 0 1614 Europe/Andorra 1993-12-23
+3040111 La Portella La Portella 42.56667 1.71667 A ADMD AD 00 0 2219 Europe/Andorra 1993-12-23
+3040112 La Polguera La Polguera 42.56667 1.58333 L LCTY AD 00 0 1919 Europe/Andorra 1993-12-23
+3040113 La Pleta La Pleta 42.55 1.43333 S HUTS AD 00 0 1949 Europe/Andorra 1993-12-23
+3040114 La Planada La Planada 42.6 1.6 T UPLD AD 00 0 2143 Europe/Andorra 1993-12-23
+3040115 La Plana La Plana 42.51667 1.51667 T UPLD AD 00 0 1265 Europe/Andorra 1993-12-23
+3040116 La Plana La Plana 42.5 1.55 L LCTY AD 00 0 1566 Europe/Andorra 1993-12-23
+3040117 La Pinatella La Pinatella 42.53333 1.6 L LCTY AD 00 0 1888 Europe/Andorra 1993-12-23
+3040118 La Peracaus La Peracaus 42.56667 1.6 L LCTY AD 00 0 1655 Europe/Andorra 1993-12-23
+3040119 La Pera La Pera 42.56667 1.46667 L LCTY AD 00 0 1673 Europe/Andorra 1993-12-23
+3040120 La Peguera La Peguera 42.45 1.53333 A ADMD AD 00 0 1859 Europe/Andorra 1993-12-23
+3040121 La Pedregosa La Pedregosa 42.58333 1.61667 L LCTY AD 00 0 1707 Europe/Andorra 1993-12-23
+3040122 La Passera La Passera 42.6 1.53333 H STM AD 00 0 1695 Europe/Andorra 1993-12-23
+3040123 La Palomera La Palomera 42.58333 1.78333 L LCTY AD 00 0 1694 Europe/Andorra 1993-12-23
+3040124 L’Angonella L'Angonella 42.6 1.5 A ADMD AD 00 0 1923 Europe/Andorra 1993-12-23
+3040125 L’Andorrana L'Andorrana 42.55 1.43333 L LCTY AD 00 0 1949 Europe/Andorra 1993-12-23
+3040126 La Muga La Muga 42.48333 1.65 L LCTY AD 00 0 2658 Europe/Andorra 1993-12-23
+3040127 La Molina La Molina 42.45 1.51667 L LCTY AD 00 0 1790 Europe/Andorra 1993-12-23
+3040128 La Molina La Molina 42.51667 1.6 A ADMD AD 00 0 2085 Europe/Andorra 1993-12-23
+3040129 La Moixella La Moixella 42.43333 1.46667 S HUTS AD 00 0 1113 Europe/Andorra 1993-12-23
+3040130 La Mentirosa La Mentirosa 42.43333 1.51667 L LCTY AD 00 0 2031 Europe/Andorra 1993-12-23
+3040131 Parròquia de la Massana Parroquia de la Massana La Massana,Parroquia de la Massana,Parròquia de la Massana,la Massana 42.56667 1.48333 A ADM1 AD 04 8953 1508 Europe/Andorra 2008-03-17
+3040132 la Massana la Massana La Macana,La Massana,La Maçana,La-Massana,la Massana,ma sa na,Ла-МаÑÑана,ラ・マサナ教区,马è¨çº³ 42.54499 1.51483 P PPLA AD 04 7211 1257 Europe/Andorra 2008-10-15
+3040133 La Margineda La Margineda 42.48333 1.5 A ADMD AD 00 0 1631 Europe/Andorra 1993-12-23
+3040134 La Mandurana La Mandurana 42.56667 1.61667 A ADMD AD 00 0 1920 Europe/Andorra 1993-12-23
+3040135 L’Alzinar L'Alzinar 42.48333 1.5 L LCTY AD 00 0 1631 Europe/Andorra 1993-12-23
+3040136 La Lomera La Lomera 42.46667 1.48333 L LCTY AD 00 0 1134 Europe/Andorra 1993-12-23
+3040137 La Llosada La Llosada 42.55 1.63333 A ADMD AD 00 0 2336 Europe/Andorra 1993-12-23
+3040138 Serrat de La Llonga Serrat de La Llonga 42.56667 1.51667 T RDGE AD 00 0 1500 Europe/Andorra 1993-12-23
+3040139 La Llonga La Llonga 42.56667 1.51667 A ADMD AD 00 0 1500 Europe/Andorra 1993-12-23
+3040140 l'Aldosa l'Aldosa 42.58333 1.63333 P PPL AD 02 195 1722 Europe/Andorra 2007-04-29
+3040141 l'Aldosa l'Aldosa 42.54391 1.52289 P PPL AD 04 594 1397 Europe/Andorra 2007-04-29
+3040142 L’Airola L'Airola 42.46667 1.46667 L LCTY AD 00 0 1340 Europe/Andorra 1993-12-23
+3040143 La Gonarda La Gonarda 42.55 1.53333 L LCTY AD 00 0 1593 Europe/Andorra 1993-12-23
+3040144 La Gonarda La Gonarda 42.55 1.53333 A ADMD AD 00 0 1593 Europe/Andorra 1993-12-23
+3040145 La Ginebrosa La Ginebrosa 42.55 1.51667 L LCTY AD 00 0 1397 Europe/Andorra 1993-12-23
+3040146 La Garganta La Garganta 42.53333 1.6 L LCTY AD 00 0 1888 Europe/Andorra 1993-12-23
+3040147 La Gargallera La Gargallera 42.48333 1.45 L LCTY AD 00 0 1195 Europe/Andorra 1993-12-23
+3040148 La Fonteta La Fonteta 42.58333 1.46667 L LCTY AD 00 0 1643 Europe/Andorra 1993-12-23
+3040149 La Fita La Fita 42.55 1.45 L LCTY AD 00 0 1788 Europe/Andorra 1993-12-23
+3040150 La Cuina La Cuina 42.56667 1.48333 T SPUR AD 00 0 1508 Europe/Andorra 1993-12-23
+3040151 La Creu de les Portes La Creu de les Portes 42.48333 1.48333 L LCTY AD 00 0 981 Europe/Andorra 1993-12-23
+3040152 La Costa La Costa 42.57834 1.64324 P PPL AD 02 0 1737 Europe/Andorra 2011-04-19
+3040153 La Coruvilla La Coruvilla 42.58333 1.46667 A ADMD AD 00 0 1643 Europe/Andorra 1993-12-23
+3040154 La Cortinada La Cortinada La Cortinada 42.57601 1.51896 P PPL AD 05 0 1722 Europe/Andorra 2011-11-05
+3040155 La Cortada La Cortada 42.45 1.5 L LCTY AD 00 0 1614 Europe/Andorra 1993-12-23
+3040156 La Comella La Comella 42.51667 1.68333 L LCTY AD 00 0 2352 Europe/Andorra 1993-12-23
+3040157 La Comella La Comella 42.5 1.53333 S HUTS AD 00 0 1574 Europe/Andorra 1993-12-23
+3040158 La Comarqueta La Comarqueta 42.58333 1.71667 L LCTY AD 00 0 2553 Europe/Andorra 1993-12-23
+3040159 La Comarqueta La Comarqueta 42.48333 1.63333 L LCTY AD 00 0 2296 Europe/Andorra 1993-12-23
+3040160 La Colilla La Colilla 42.53333 1.6 L LCTY AD 00 0 1888 Europe/Andorra 1993-12-23
+3040161 La Colilla La Colilla 42.5 1.58333 L LCTY AD 00 0 1888 Europe/Andorra 1993-12-23
+3040162 La Clota La Clota 42.56667 1.53333 L LCTY AD 00 0 1669 Europe/Andorra 1993-12-23
+3040163 La Caubella La Caubella 42.58333 1.48333 L CLG AD 00 0 1809 Europe/Andorra 1993-12-23
+3040164 La Castelleta La Castelleta 42.53333 1.51667 T SPUR AD 00 0 1361 Europe/Andorra 1993-12-23
+3040165 La Carbonera La Carbonera 42.46667 1.63333 L LCTY AD 00 0 2619 Europe/Andorra 1993-12-23
+3040166 La Caolla La Caolla 42.5 1.61667 T SPUR AD 00 0 2560 Europe/Andorra 1993-12-23
+3040167 La Callisa La Callisa 42.56667 1.48333 S BDG AD 00 0 1508 Europe/Andorra 1993-12-23
+3040168 La Cabeça La Cabeca 42.48333 1.45 L LCTY AD 00 0 1195 Europe/Andorra 1994-04-16
+3040169 La Cabanella La Cabanella 42.51667 1.46667 A ADMD AD 00 0 1840 Europe/Andorra 1993-12-23
+3040170 La Burna La Burna 42.6 1.48333 T CRQ AD 00 0 2441 Europe/Andorra 1993-12-23
+3040171 La Borda Nova La Borda Nova 42.61667 1.53333 S HUT AD 00 0 1609 Europe/Andorra 1993-12-23
+3040172 La Bor La Bor 42.55 1.58333 A ADMD AD 00 0 1499 Europe/Andorra 1993-12-23
+3040173 La Boixosa La Boixosa 42.56667 1.53333 L LCTY AD 00 0 1669 Europe/Andorra 1993-12-23
+3040174 La Beçosa La Becosa 42.61667 1.55 L LCTY AD 00 0 2007 Europe/Andorra 1994-04-16
+3040175 La Bauma La Bauma 42.48333 1.61667 S CAVE AD 00 0 2217 Europe/Andorra 1993-12-23
+3040176 La Basseta La Basseta 42.48333 1.65 H LK AD 00 0 2658 Europe/Andorra 1993-12-23
+3040177 La Basera La Basera 42.58333 1.65 L LCTY AD 00 0 1767 Europe/Andorra 1993-12-23
+3040178 La Bartra del Ganxo La Bartra del Ganxo 42.48333 1.46667 L LCTY AD 00 0 1148 Europe/Andorra 1993-12-23
+3040179 La Bartra La Bartra 42.51667 1.55 L LCTY AD 00 0 1322 Europe/Andorra 1993-12-23
+3040180 La Bartra La Bartra 42.46667 1.46667 L LCTY AD 00 0 1340 Europe/Andorra 1993-12-23
+3040181 La Bartra La Bartra La Barta,La Bartra 42.51667 1.56667 A ADMD AD AD 00 0 1759 Europe/Andorra 2011-11-05
+3040182 L’Abarsetar L'Abarsetar 42.61667 1.51667 L LCTY AD 00 0 1716 Europe/Andorra 1993-12-23
+3040183 L’Abarsetar L'Abarsetar 42.53333 1.61667 L LCTY AD 00 0 2237 Europe/Andorra 1993-12-23
+3040184 La Baladosa La Baladosa 42.6 1.68333 L LCTY AD 00 0 2089 Europe/Andorra 1993-12-23
+3040185 Tosa de Juclar Tosa de Juclar 42.6 1.71667 T UPLD AD 00 0 2516 Europe/Andorra 1993-12-23
+3040186 Solana de Juclar Solana de Juclar 42.6 1.7 T SLP AD 00 0 2354 Europe/Andorra 1993-12-23
+3040187 Riu de Juclar Riu de Juclar 42.60124 1.69807 H STM AD 00 0 2147 Europe/Andorra 2011-04-19
+3040188 Pleta de Juclar Pleta de Juclar 42.6 1.71667 L GRAZ AD 00 0 2516 Europe/Andorra 1993-12-23
+3040189 Obaga de Juclar Obaga de Juclar 42.61667 1.7 T SLP AD 00 0 2285 Europe/Andorra 1993-12-23
+3040190 Collada de Juclar Collada de Juclar Col de Joucla,Col de l' Albe,Col de l’ Albe,Collada de Juclar,Port de Jogela,Port de Joucla 42.61667 1.73333 T PASS AD 00 0 2508 Europe/Andorra 2011-11-05
+3040191 Canals de Juclar Canals de Juclar 42.6 1.71667 H RVN AD 00 0 2516 Europe/Andorra 1993-12-23
+3040192 Camà de Juclar Cami de Juclar 42.6 1.7 R TRL AD 00 0 2354 Europe/Andorra 1993-12-23
+3040193 Alt de Juclar Alt de Juclar 42.61667 1.7 T RDGE AD 00 0 2285 Europe/Andorra 1993-12-23
+3040194 Juclar Juclar 42.6 1.71667 A ADMD AD 00 0 2516 Europe/Andorra 1993-12-23
+3040195 Carretera de la Juberrussa Carretera de la Juberrussa 42.45 1.48333 R RD AD 00 0 1111 Europe/Andorra 1993-12-23
+3040196 Canal de la Juberrussa Canal de la Juberrussa 42.43333 1.48333 H STM AD 00 0 1228 Europe/Andorra 1993-12-23
+3040197 Bosc de la Juberrussa Bosc de la Juberrussa 42.43333 1.48333 V FRST AD 00 0 1228 Europe/Andorra 1993-12-23
+3040198 Bordes de la Juberrussa Bordes de la Juberrussa 42.43333 1.48333 S FRM AD 00 0 1228 Europe/Andorra 1993-12-23
+3040199 Juberrussa Juberrussa 42.43333 1.48333 A ADMD AD 00 0 1228 Europe/Andorra 1993-12-23
+3040200 Juberri Juberri Juberri,Juverri 42.44069 1.48972 P PPL AD 06 0 1460 Europe/Andorra 2011-11-05
+3040201 Font de la Jubanya Font de la Jubanya 42.58333 1.45 H SPNG AD 00 0 2156 Europe/Andorra 1993-12-23
+3040202 Coll Jovell Coll Jovell 42.45 1.53333 T SPUR AD 00 0 1859 Europe/Andorra 1993-12-23
+3040203 Coll Jovell Coll Jovell 42.5 1.56667 T PK AD 00 0 1776 Europe/Andorra 1993-12-23
+3040204 Coll Jovell Coll Jovell 42.48333 1.48333 T PK AD 00 0 981 Europe/Andorra 1993-12-23
+3040205 Jovell Jovell 42.58333 1.63333 L LCTY AD 00 0 1722 Europe/Andorra 1993-12-23
+3040206 Coll de Jou Coll de Jou 42.51667 1.55 T SPUR AD 00 0 1322 Europe/Andorra 1993-12-23
+3040207 Coll de Jou Coll de Jou 42.45 1.46667 T PASS AD 00 0 935 Europe/Andorra 1993-12-23
+3040208 Canal del Jou Canal del Jou 42.56667 1.5 H STM AD 00 0 1636 Europe/Andorra 1993-12-23
+3040209 Camà del Jou Cami del Jou 42.56667 1.5 R TRL AD 00 0 1636 Europe/Andorra 1993-12-23
+3040210 Bosc del Jou Bosc del Jou 42.56667 1.51667 V FRST AD 00 0 1500 Europe/Andorra 1993-12-23
+3040211 Solana del Jordà Solana del Jorda 42.51667 1.6 T SLP AD 00 0 2085 Europe/Andorra 1993-12-23
+3040212 Borda del Joansaus Borda del Joansaus 42.58333 1.65 S HUT AD 00 0 1767 Europe/Andorra 1993-12-23
+3040213 Portella de Joan Antoni Portella de Joan Antoni 42.51195 1.70887 T PASS AD 00 0 2550 Europe/Andorra 2011-04-19
+3040214 Pleta de Jes Agols Pleta de Jes Agols 42.51667 1.6 L GRAZ AD 00 0 2085 Europe/Andorra 1993-12-23
+3040215 Borda del Jep Borda del Jep Borda del Gep,Borda del Jep 42.56667 1.58333 S HUT AD AD 00 0 1919 Europe/Andorra 2011-11-05
+3040216 Borda del Jarca Borda del Jarca 42.56667 1.58333 S HUT AD 00 0 1919 Europe/Andorra 1993-12-23
+3040217 Borda del Jarca Borda del Jarca 42.55 1.6 S HUT AD 00 0 2210 Europe/Andorra 1993-12-23
+3040218 Borda del Janramon Borda del Janramon 42.56667 1.58333 S HUT AD 00 0 1919 Europe/Andorra 1993-12-23
+3040219 Turó de Jan Turo de Jan 42.61667 1.63333 T SPUR AD 00 0 2331 Europe/Andorra 1993-12-23
+3040220 Riu de Jan Riu de Jan 42.61667 1.63333 H STM AD 00 0 2331 Europe/Andorra 1993-12-23
+3040221 Pala de Jan Pala de Jan 42.61667 1.63333 T CLF AD 00 0 2331 Europe/Andorra 1993-12-23
+3040222 Cóms de Jan Coms de Jan 42.61667 1.63333 H LK AD 00 0 2331 Europe/Andorra 1993-12-23
+3040223 Collada de Jan Collada de Jan Collada de Jan 42.61667 1.63333 T PASS AD 00 0 2331 Europe/Andorra 2011-11-05
+3040224 Estany de l’ Isla Estany de l' Isla 42.61667 1.68333 H LK AD 00 0 2406 Europe/Andorra 1993-12-23
+3040225 Font dels Isards Font dels Isards 42.58333 1.7 H SPNG AD 00 0 2584 Europe/Andorra 1993-12-23
+3040226 Costa dels Isards Costa dels Isards 42.58333 1.6 T SLP AD 00 0 1828 Europe/Andorra 1993-12-23
+3040227 Coll dels Isards Coll dels Isards 42.51831 1.73762 T PASS AD 00 0 2659 Europe/Andorra 2011-04-19
+3040228 Canal dels Isards Canal dels Isards 42.5 1.66667 H RVN AD 00 0 2441 Europe/Andorra 1993-12-23
+3040229 Canal de l’ Isard Canal de l' Isard 42.58333 1.46667 H STM AD 00 0 1643 Europe/Andorra 1993-12-23
+3040230 Pla de l’ Ingla Pla de l' Ingla 42.48333 1.61667 T UPLD AD 00 0 2217 Europe/Andorra 1993-12-23
+3040231 Collet de l’ Infern Collet de l' Infern 42.48333 1.6 T PASS AD 00 0 2250 Europe/Andorra 1993-12-23
+3040232 Canal de l’ Infern Canal de l' Infern 42.53333 1.6 H STM AD 00 0 1888 Europe/Andorra 1993-12-23
+3040233 Torrent dels Indrets Torrent dels Indrets 42.48333 1.45 H STM AD 00 0 1195 Europe/Andorra 1993-12-23
+3040234 Riu d’ Incles Riu d' Incles 42.60159 1.68721 H STM AD 00 0 2014 Europe/Andorra 2011-04-19
+3040235 Prats d’ Incles Prats d' Incles 42.6 1.66667 L GRAZ AD 00 0 1858 Europe/Andorra 1993-12-23
+3040236 Port de Fontargente Port de Fontargente Port d' Incles,Port de Fontargent,Port de Fontargente,Port d’ Incles 42.61667 1.71667 T PASS AD 00 0 2352 Europe/Andorra 2011-11-05
+3040237 Pont d’ Incles Pont d' Incles 42.58333 1.66667 S BDG AD 00 0 2159 Europe/Andorra 1993-12-23
+3040238 Camà d’ Incles Cami d' Incles 42.6 1.66667 R TRL AD 00 0 1858 Europe/Andorra 1993-12-23
+3040239 Bosc d’ Incles Bosc d' Incles 42.58333 1.66667 V FRST AD 00 0 2159 Europe/Andorra 1993-12-23
+3040240 Estany de l’ Illa Estany de l' Illa 42.49785 1.65852 H RSV AD 00 0 2553 Europe/Andorra 2011-04-19
+3040241 Obagues de la Iesca Obagues de la Iesca 42.48333 1.43333 T SLP AD 00 0 1938 Europe/Andorra 1993-12-23
+3040242 Bosc de l’ Hoste Bosc de l' Hoste 42.55 1.68333 V FRST AD 00 0 2254 Europe/Andorra 1993-12-23
+3040243 Bosc de l’ Hostal del Poll Bosc de l' Hostal del Poll 42.61667 1.63333 V FRST AD 00 0 2331 Europe/Andorra 1993-12-23
+3040244 Riu dels Hortons Riu dels Hortons 42.51667 1.46667 H STM AD 00 0 1840 Europe/Andorra 1993-12-23
+3040245 Bosc dels Hortons Bosc dels Hortons 42.53333 1.55 V FRST AD 00 0 1344 Europe/Andorra 1993-12-23
+3040246 Torrent dels Hortells Torrent dels Hortells 42.45 1.48333 H STM AD 00 0 1111 Europe/Andorra 1993-12-23
+3040247 Serra de l’ Hortell Serra de l' Hortell 42.61667 1.51667 T MT AD 00 0 1716 Europe/Andorra 1993-12-23
+3040248 Pic de l’ Hortell Pic de l' Hortell 42.61914 1.50815 T PK AD 00 0 2390 Europe/Andorra 2011-04-19
+3040249 Torrent dels Hortals Torrent dels Hortals 42.53333 1.58333 H STM AD 00 0 1571 Europe/Andorra 1993-12-23
+3040250 Serra de l’ Honor Serra de l' Honor 42.53333 1.51667 T SPUR AD 00 0 1361 Europe/Andorra 1993-12-23
+3040251 Roc del’ Home Dret Roc del' Home Dret 42.58333 1.66667 T SPUR AD 00 0 2159 Europe/Andorra 1993-12-23
+3040252 Roca Herbosa Roca Herbosa 42.48333 1.56667 T RK AD 00 0 2231 Europe/Andorra 1993-12-23
+3040253 Pleta de Guitard Pleta de Guitard Pleta de Guitard,Pleta de Guitart 42.53333 1.6 L GRAZ AD AD 00 0 1888 Europe/Andorra 2011-11-05
+3040254 Cortal del Guitard Cortal del Guitard Cortal del Guitard,Cortal del Guitart 42.45 1.5 S CRRL AD AD 00 0 1614 Europe/Andorra 2011-11-05
+3040255 Tartera de les Guineus Tartera de les Guineus 42.56667 1.68333 T TAL AD 00 0 2340 Europe/Andorra 1993-12-23
+3040256 Roc de la Guilla Roc de la Guilla 42.51667 1.56667 T RK AD 00 0 1759 Europe/Andorra 1993-12-23
+3040257 Bony de les Guardioles Bony de les Guardioles 42.55 1.51667 T SPUR AD 00 0 1397 Europe/Andorra 1993-12-23
+3040258 Serra de la Guardiola Serra de la Guardiola 42.58081 1.71111 T RDGE AD 00 0 2544 Europe/Andorra 2011-04-19
+3040259 Obaga de la Guardiola Obaga de la Guardiola 42.56667 1.68333 T SLP AD 00 0 2340 Europe/Andorra 1993-12-23
+3040260 Planell de la Guà rdia Planell de la Guardia 42.61667 1.51667 T UPLD AD 00 0 1716 Europe/Andorra 1993-12-23
+3040261 Roques Grosses Roques Grosses 42.58333 1.66667 T RKS AD 00 0 2159 Europe/Andorra 1993-12-23
+3040262 Riba Grossa Riba Grossa 42.55 1.6 T TAL AD 00 0 2210 Europe/Andorra 1993-12-23
+3040263 Roc Gros Roc Gros 42.58333 1.48333 T RK AD 00 0 1809 Europe/Andorra 1993-12-23
+3040264 Riu Gros Riu Gros 42.56667 1.66667 H STM AD 00 0 1938 Europe/Andorra 1993-12-23
+3040265 Alt del Griu Alt del Griu 42.52534 1.65114 T MT AD 00 0 2508 Europe/Andorra 2011-04-19
+3040266 Riu del Grill Riu del Grill 42.51667 1.6 H STM AD 00 0 2085 Europe/Andorra 1993-12-23
+3040267 Font de les Greixes Font de les Greixes 42.46667 1.45 H SPNG AD 00 0 1562 Europe/Andorra 1993-12-23
+3040268 Clot de les Greixes Clot de les Greixes 42.46667 1.45 H RVN AD 00 0 1562 Europe/Andorra 1993-12-23
+3040269 Camà de les Gravades Cami de les Gravades 42.53333 1.51667 R TRL AD 00 0 1361 Europe/Andorra 1993-12-23
+3040270 Clot dels Gravaders Clot dels Gravaders 42.46667 1.55 H RVN AD 00 0 2341 Europe/Andorra 1993-12-23
+3040271 Pleta dels Graus Pleta dels Graus 42.48333 1.56667 L GRAZ AD 00 0 2231 Europe/Andorra 1993-12-23
+3040272 Grau Roig Grau Roig 42.53333 1.7 S RSRT AD 03 0 2357 Europe/Andorra 2010-01-11
+3040273 Obaga de Graupont Obaga de Graupont 42.48333 1.46667 T SLP AD 00 0 1148 Europe/Andorra 1993-12-23
+3040274 Clot de Graupont Clot de Graupont 42.48333 1.46667 H RVN AD 00 0 1148 Europe/Andorra 1993-12-23
+3040275 Grau d’Incles Grau d'Incles 42.58333 1.65 L LCTY AD 00 0 1767 Europe/Andorra 1993-12-23
+3040276 Grau del Cabrer Grau del Cabrer 42.56667 1.71667 L LCTY AD 00 0 2219 Europe/Andorra 1993-12-23
+3040277 Plana del Grau Plana del Grau 42.58333 1.51667 T UPLD AD 00 0 1722 Europe/Andorra 1993-12-23
+3040278 Costa del Grau Costa del Grau 42.56667 1.6 T SLP AD 00 0 1655 Europe/Andorra 1993-12-23
+3040279 Canal del Grau Canal del Grau 42.56667 1.6 H STM AD 00 0 1655 Europe/Andorra 1993-12-23
+3040280 Canal Gran de la Serrera Canal Gran de la Serrera 42.61667 1.58333 H RVN AD 00 0 2374 Europe/Andorra 1993-12-23
+3040281 Canal Gran de la Grella Canal Gran de la Grella 42.51667 1.51667 H STM AD 00 0 1265 Europe/Andorra 1993-12-23
+3040282 Planell Gran de la Cebollera Planell Gran de la Cebollera 42.63333 1.58333 T UPLD AD 00 0 2470 Europe/Andorra 1993-12-23
+3040283 Costa de les Grandalles Costa de les Grandalles 42.53333 1.7 T SLP AD 00 0 2357 Europe/Andorra 1993-12-23
+3040284 Planell Gran Planell Gran 42.63333 1.55 T UPLD AD 00 0 2053 Europe/Andorra 1993-12-23
+3040285 Planell Gran Planell Gran 42.58333 1.66667 T UPLD AD 00 0 2159 Europe/Andorra 1993-12-23
+3040286 Planell Gran Planell Gran 42.56667 1.46667 T UPLD AD 00 0 1673 Europe/Andorra 1993-12-23
+3040287 Planell Gran Planell Gran 42.55 1.68333 T UPLD AD 00 0 2254 Europe/Andorra 1993-12-23
+3040288 Planell Gran Planell Gran 42.55 1.65 T UPLD AD 00 0 2432 Europe/Andorra 1993-12-23
+3040289 Planell Gran Planell Gran 42.46667 1.56667 T UPLD AD 00 0 2365 Europe/Andorra 1993-12-23
+3040290 Costa Gran Costa Gran 42.61667 1.61667 T SLP AD 00 0 2352 Europe/Andorra 1993-12-23
+3040291 Costa Gran Costa Gran 42.6 1.61667 T SLP AD 00 0 2271 Europe/Andorra 1993-12-23
+3040292 Costa Gran Costa Gran 42.51667 1.48333 T SLP AD 00 0 1839 Europe/Andorra 1993-12-23
+3040293 Canal Gran Canal Gran 42.58333 1.46667 H STM AD 00 0 1643 Europe/Andorra 1993-12-23
+3040294 Canal Gran Canal Gran 42.56667 1.51667 H STM AD 00 0 1500 Europe/Andorra 1993-12-23
+3040295 Canal Gran Canal Gran 42.56667 1.48333 H STM AD 00 0 1508 Europe/Andorra 1993-12-23
+3040296 Canal Gran Canal Gran 42.55 1.58333 H STM AD 00 0 1499 Europe/Andorra 1993-12-23
+3040297 Canal Gran Canal Gran 42.55 1.5 H STM AD 00 0 1292 Europe/Andorra 1993-12-23
+3040298 Canal Gran Canal Gran 42.5 1.63333 H STM AD 00 0 2545 Europe/Andorra 1993-12-23
+3040299 Canal Gran Canal Gran 42.48333 1.48333 H STM AD 00 0 981 Europe/Andorra 1993-12-23
+3040300 Canal Gran Canal Gran 42.46667 1.48333 H STM AD 00 0 1134 Europe/Andorra 1993-12-23
+3040301 Basera Gran Basera Gran 42.5 1.48333 T CLF AD 00 0 1316 Europe/Andorra 1993-12-23
+3040302 Plana de Gral Plana de Gral 42.58333 1.48333 T UPLD AD 00 0 1809 Europe/Andorra 1993-12-23
+3040303 Canya de les Grailes Canya de les Grailes 42.48333 1.51667 S CAVE AD 00 0 2061 Europe/Andorra 1993-12-23
+3040304 Canya de les Grailes Canya de les Grailes 42.46667 1.46667 S CAVE AD 00 0 1340 Europe/Andorra 1993-12-23
+3040305 Canal de les Grailes Canal de les Grailes 42.5 1.61667 H STM AD 00 0 2560 Europe/Andorra 1993-12-23
+3040306 Roc del Grailer Roc del Grailer 42.56667 1.51667 T RK AD 00 0 1500 Europe/Andorra 1993-12-23
+3040307 Tartera del Goter Tartera del Goter 42.56667 1.73333 T TAL AD 00 0 2096 Europe/Andorra 1993-12-23
+3040308 Roc del Goter Roc del Goter 42.56667 1.73333 T CLF AD 00 0 2096 Europe/Andorra 1993-12-23
+3040309 Pala del Goter Pala del Goter 42.56667 1.73333 T SLP AD 00 0 2096 Europe/Andorra 1993-12-23
+3040310 Bosc de la Gonarda Bosc de la Gonarda 42.55 1.53333 V FRST AD 00 0 1593 Europe/Andorra 1993-12-23
+3040311 Coll de Gomà Coll de Goma 42.55 1.55 T PASS AD 00 0 2097 Europe/Andorra 1993-12-23
+3040312 Planell de Ginestar Planell de Ginestar 42.6 1.55 T UPLD AD 00 0 2298 Europe/Andorra 1993-12-23
+3040313 Bony de la Ginebrera Bony de la Ginebrera 42.45 1.46667 T SPUR AD 00 0 935 Europe/Andorra 1993-12-23
+3040314 Font del Ginebre Font del Ginebre 42.43333 1.45 H SPNG AD 00 0 877 Europe/Andorra 1993-12-23
+3040315 Prat del Gilet Prat del Gilet 42.51667 1.6 L GRAZ AD 00 0 2085 Europe/Andorra 1993-12-23
+3040316 Pla del Géspit Pla del Gespit 42.55 1.61667 T UPLD AD 00 0 2206 Europe/Andorra 1993-12-23
+3040317 Pala del Géspit Pala del Gespit 42.61667 1.55 T SLP AD 00 0 2007 Europe/Andorra 1993-12-23
+3040318 Pala del Géspit Pala del Gespit 42.56667 1.55 T SLP AD 00 0 1996 Europe/Andorra 1993-12-23
+3040319 Borda del Germà Borda del Germa 42.45 1.48333 S FRM AD 00 0 1111 Europe/Andorra 1993-12-23
+3040320 Costa de les Gerderes Costa de les Gerderes 42.55 1.6 T SLP AD 00 0 2210 Europe/Andorra 1993-12-23
+3040321 Cortal del Genret Cortal del Genret 42.45 1.5 S CRRL AD 00 0 1614 Europe/Andorra 1993-12-23
+3040322 Clot del Gel Clot del Gel 42.51667 1.48333 H RVN AD 00 0 1839 Europe/Andorra 1993-12-23
+3040323 Canal del Gel Canal del Gel 42.48333 1.46667 H STM AD 00 0 1148 Europe/Andorra 1993-12-23
+3040324 Solana de la Gaverna Solana de la Gaverna 42.51667 1.6 T SLP AD 00 0 2085 Europe/Andorra 1993-12-23
+3040325 Font de la Gavatxa Font de la Gavatxa 42.53333 1.73333 H SPNG AD 00 0 2300 Europe/Andorra 1993-12-23
+3040326 Borda del Gastó Borda del Gasto 42.45 1.46667 S HUT AD 00 0 935 Europe/Andorra 1993-12-23
+3040327 Serrat de la Garriga Serrat de la Garriga 42.53333 1.61667 T SPUR AD 00 0 2237 Europe/Andorra 1993-12-23
+3040328 Crestes de Gargantillar Crestes de Gargantillar 42.50208 1.63061 T RDGE AD 00 0 2666 Europe/Andorra 2011-04-19
+3040329 Collades de Gargantillar Collades de Gargantillar 42.5 1.65 T PASS AD 00 0 2542 Europe/Andorra 1993-12-23
+3040330 Clots de Gargantillar Clots de Gargantillar 42.5 1.65 H RVN AD 00 0 2542 Europe/Andorra 1993-12-23
+3040331 Gargantillar Gargantillar 42.5 1.65 A ADMD AD 00 0 2542 Europe/Andorra 1993-12-23
+3040332 Roc de la Garganta Roc de la Garganta 42.55 1.6 T RK AD 00 0 2210 Europe/Andorra 1993-12-23
+3040333 Pas dels Gargalls Pas dels Gargalls 42.6 1.68333 T PASS AD 00 0 2089 Europe/Andorra 1993-12-23
+3040334 Bosc de la Gargallosa Bosc de la Gargallosa 42.56667 1.51667 V FRST AD 00 0 1500 Europe/Andorra 1993-12-23
+3040335 Torrent del Gargallet Torrent del Gargallet 42.45 1.53333 H STM AD 00 0 1859 Europe/Andorra 1993-12-23
+3040336 Font del Gargallet Font del Gargallet 42.45 1.53333 H SPNG AD 00 0 1859 Europe/Andorra 1993-12-23
+3040337 Clotada del Gargallet Clotada del Gargallet 42.45 1.55 H RVN AD 00 0 2457 Europe/Andorra 1993-12-23
+3040338 Solana de Galliner Solana de Galliner 42.56667 1.46667 T SLP AD 00 0 1673 Europe/Andorra 1993-12-23
+3040339 Riu de Galliner Riu de Galliner 42.56667 1.48333 H STM AD 00 0 1508 Europe/Andorra 1993-12-23
+3040340 Galliner Galliner 42.56667 1.46667 A ADMD AD 00 0 1673 Europe/Andorra 1993-12-23
+3040341 Planell de la Gallina Planell de la Gallina 42.43333 1.5 T UPLD AD 00 0 1804 Europe/Andorra 1993-12-23
+3040342 Coll de la Gallina Coll de la Gallina 42.46667 1.45 T PASS AD 00 0 1562 Europe/Andorra 1993-12-23
+3040343 Canal dels Gais Canal dels Gais 42.48333 1.55 H STM AD 00 0 2233 Europe/Andorra 1993-12-23
+3040344 Borda del Gabriel Borda del Gabriel 42.56667 1.58333 S HUT AD 00 0 1919 Europe/Andorra 1993-12-23
+3040345 Canal de la Fusta Canal de la Fusta 42.55 1.55 H RVN AD 00 0 2097 Europe/Andorra 1993-12-23
+3040346 Font Freda Font Freda 42.63333 1.56667 H SPNG AD 00 0 2394 Europe/Andorra 1993-12-23
+3040347 Font Freda Font Freda 42.56667 1.46667 H SPNG AD 00 0 1673 Europe/Andorra 1993-12-23
+3040348 Font Freda Font Freda 42.45 1.5 H SPNG AD 00 0 1614 Europe/Andorra 1993-12-23
+3040349 Font Fred Font Fred 42.48333 1.6 H SPNG AD 00 0 2250 Europe/Andorra 1993-12-23
+3040350 Francolà Francoli 42.48333 1.43333 A ADMD AD 00 0 1938 Europe/Andorra 1993-12-23
+3040351 Obaga Fosca Obaga Fosca 42.48333 1.43333 T SLP AD 00 0 1938 Europe/Andorra 1993-12-23
+3040352 Collada Fosca Collada Fosca 42.43333 1.5 T SPUR AD 00 0 1804 Europe/Andorra 1993-12-23
+3040353 Canal Fosca Canal Fosca 42.6 1.53333 H STM AD 00 0 1695 Europe/Andorra 1993-12-23
+3040354 Canal Fosca Canal Fosca 42.5 1.56667 H STM AD 00 0 1776 Europe/Andorra 1993-12-23
+3040355 Bosc Fosc Bosc Fosc 42.56667 1.66667 V FRST AD 00 0 1938 Europe/Andorra 1993-12-23
+3040356 Pleta del Forquilló Pleta del Forquillo 42.61667 1.7 L GRAZ AD 00 0 2285 Europe/Andorra 1993-12-23
+3040357 Collet de Forns Collet de Forns 42.48333 1.48333 T SPUR AD 00 0 981 Europe/Andorra 1993-12-23
+3040358 Canals de la Forniga Canals de la Forniga 42.5 1.45 H STM AD 00 0 1840 Europe/Andorra 1993-12-23
+3040359 Prat del Fornet Prat del Fornet 42.55 1.61667 L GRAZ AD 00 0 2206 Europe/Andorra 1993-12-23
+3040360 Font del Fornell Font del Fornell 42.45 1.5 H SPNG AD 00 0 1614 Europe/Andorra 1993-12-23
+3040361 Canal del Forn de la Calç Canal del Forn de la Calc 42.55 1.55 H STM AD 00 0 2097 Europe/Andorra 1993-12-23
+3040362 Forn de Cals Forn de Cals 42.56667 1.6 L LCTY AD 00 0 1655 Europe/Andorra 1993-12-23
+3040363 Turó del Forn Turo del Forn 42.63333 1.58333 T PK AD 00 0 2470 Europe/Andorra 1993-12-23
+3040364 Torrent del Forn Torrent del Forn 42.5 1.51667 H STM AD 00 0 1410 Europe/Andorra 1993-12-23
+3040365 Serrat del Forn Serrat del Forn 42.55 1.51667 T SPUR AD 00 0 1397 Europe/Andorra 1993-12-23
+3040366 Roca del Forn Roca del Forn 42.55 1.61667 T RK AD 00 0 2206 Europe/Andorra 1993-12-23
+3040367 Riu del Forn Riu del Forn 42.55 1.6 H STM AD 00 0 2210 Europe/Andorra 1993-12-23
+3040368 Portella del Forn Portella del Forn 42.63333 1.58333 T PASS AD 00 0 2470 Europe/Andorra 1993-12-23
+3040369 Planells del Forn Planells del Forn 42.55 1.6 T UPLD AD 00 0 2210 Europe/Andorra 1993-12-23
+3040370 Obaga del Forn Obaga del Forn 42.48333 1.43333 T SLP AD 00 0 1938 Europe/Andorra 1993-12-23
+3040371 Clots del Forn Clots del Forn 42.63333 1.58333 H RVN AD 00 0 2470 Europe/Andorra 1993-12-23
+3040372 Carretera del Forn Carretera del Forn 42.55 1.58333 R RD AD 00 0 1499 Europe/Andorra 1993-12-23
+3040373 Carrerada del Forn Carrerada del Forn 42.56667 1.63333 R TRL AD 00 0 2016 Europe/Andorra 1993-12-23
+3040374 Canal del Forn Canal del Forn 42.56667 1.51667 H STM AD 00 0 1500 Europe/Andorra 1993-12-23
+3040375 Camà del Forn Cami del Forn 42.55 1.58333 R TRL AD 00 0 1499 Europe/Andorra 1993-12-23
+3040376 Estanys Forcats Estanys Forcats 42.6 1.45 H LKS AD 00 0 2174 Europe/Andorra 1993-12-23
+3040377 Torrent Forcat Torrent Forcat 42.45 1.51667 H STM AD 00 0 1790 Europe/Andorra 1993-12-23
+3040378 Estany Forcat Estany Forcat 42.49439 1.63825 H LK AD 00 0 2538 Europe/Andorra 2011-04-19
+3040379 Estany Forcat Estany Forcat 42.5 1.63333 H LK AD 00 0 2545 Europe/Andorra 1993-12-23
+3040380 Forats de l’Óssa Forats de l'Ossa 42.61667 1.53333 L LCTY AD 00 0 1609 Europe/Andorra 1993-12-23
+3040381 Forat Fosc Forat Fosc 42.55 1.56667 L LCTY AD 00 0 1828 Europe/Andorra 1993-12-23
+3040382 Riu de Forat de Rius Riu de Forat de Rius 42.58333 1.63333 H STM AD 00 0 1722 Europe/Andorra 1993-12-23
+3040383 Collada del Forat de Malhiverns Collada del Forat de Malhiverns 42.6 1.43333 T PASS AD 00 0 2667 Europe/Andorra 1993-12-23
+3040384 Cresta del Forat dels Malhiverns Cresta del Forat dels Malhiverns Cresta del Forat dels Malhiverns 42.6 1.43333 T RDGE AD 00 0 2667 Europe/Andorra 2011-11-05
+3040385 Forat dels Malhiverns Forat dels Malhiverns 42.6 1.45 L LCTY AD 00 0 2174 Europe/Andorra 1993-12-23
+3040386 Forat dels Clots de Massat Forat dels Clots de Massat 42.55 1.7 L LCTY AD 00 0 2358 Europe/Andorra 1993-12-23
+3040387 Forat d’Arau Forat d'Arau 42.56667 1.48333 L LCTY AD 00 0 1508 Europe/Andorra 1993-12-23
+3040388 Coma del Forat Coma del Forat 42.61667 1.48333 H STMH AD 00 0 2470 Europe/Andorra 1993-12-23
+3040389 Font de Fontverd Font de Fontverd 42.5 1.6 H SPNG AD 00 0 2416 Europe/Andorra 1993-12-23
+3040390 Fontverd Fontverd 42.48333 1.6 S RUIN AD 00 0 2250 Europe/Andorra 1993-12-23
+3040391 Fontverd Fontverd 42.5 1.6 A ADMD AD 00 0 2416 Europe/Andorra 1993-12-23
+3040392 Riu de les Fonts de la Tosa Riu de les Fonts de la Tosa 42.6 1.68333 H STM AD 00 0 2089 Europe/Andorra 1993-12-23
+3040393 Tosa de les Fonts Tosa de les Fonts 42.55 1.65 T UPLD AD 00 0 2432 Europe/Andorra 1993-12-23
+3040394 Pic de les Fonts Pic de les Fonts 42.6 1.6 T PK AD 00 0 2143 Europe/Andorra 1993-12-23
+3040395 Pic de les Fonts Pic de les Fonts 42.6 1.48333 T PK AD 00 0 2441 Europe/Andorra 1993-12-23
+3040396 Estany de les Fonts Estany de les Fonts 42.51667 1.66667 H LK AD 00 0 2410 Europe/Andorra 1993-12-23
+3040397 Comella de les Fonts Comella de les Fonts 42.45 1.46667 H STM AD 00 0 935 Europe/Andorra 1993-12-23
+3040398 Clots de les Fonts Clots de les Fonts 42.58333 1.68333 H RVN AD 00 0 2294 Europe/Andorra 1993-12-23
+3040399 Clot de les Fonts Clot de les Fonts 42.55 1.65 H RVN AD 00 0 2432 Europe/Andorra 1993-12-23
+3040400 Clot de les Fonts Clot de les Fonts 42.46667 1.45 H RVN AD 00 0 1562 Europe/Andorra 1993-12-23
+3040401 Clotada de les Fonts Clotada de les Fonts 42.6 1.48333 T SLP AD 00 0 2441 Europe/Andorra 1993-12-23
+3040402 Canal de les Fonts Canal de les Fonts 42.61667 1.51667 H STM AD 00 0 1716 Europe/Andorra 1993-12-23
+3040403 Bosc de les Fonts Bosc de les Fonts 42.56667 1.6 V FRST AD 00 0 1655 Europe/Andorra 1993-12-23
+3040404 Aspre de les Fonts Aspre de les Fonts 42.6 1.48333 V VINS AD 00 0 2441 Europe/Andorra 1993-12-23
+3040405 Bosc de la Font Roja Bosc de la Font Roja 42.55 1.45 V FRST AD 00 0 1788 Europe/Andorra 1993-12-23
+3040406 Collet de Font Podrida Collet de Font Podrida 42.58333 1.46667 T PK AD 00 0 1643 Europe/Andorra 1993-12-23
+3040407 Canal de la Font Llarga Canal de la Font Llarga 42.6 1.65 H STM AD 00 0 2131 Europe/Andorra 1993-12-23
+3040408 Costa de Font Freda Costa de Font Freda 42.63333 1.56667 T SLP AD 00 0 2394 Europe/Andorra 1993-12-23
+3040409 Font de Fontduà Font de Fontdui 42.56667 1.68333 H SPNG AD 00 0 2340 Europe/Andorra 1993-12-23
+3040410 Obaga de la Font dels Pets Obaga de la Font dels Pets 42.6 1.48333 T SLP AD 00 0 2441 Europe/Andorra 1993-12-23
+3040411 Torrent de la Font dels Pals Torrent de la Font dels Pals 42.45 1.51667 H STM AD 00 0 1790 Europe/Andorra 1993-12-23
+3040412 Font del Solà Font del Sola 42.58333 1.66667 H STM AD 00 0 2159 Europe/Andorra 1993-12-23
+3040413 Costa de la Font dels Miquelets Costa de la Font dels Miquelets 42.58333 1.43333 T SLP AD 00 0 2412 Europe/Andorra 1993-12-23
+3040414 Font dels Comellassos Font dels Comellassos 42.6 1.68333 H STM AD 00 0 2089 Europe/Andorra 1993-12-23
+3040415 Bosc de la Font del Pi Bosc de la Font del Pi 42.58333 1.53333 V FRST AD 00 0 1924 Europe/Andorra 1993-12-23
+3040416 Bosc de la Font del Pascol Bosc de la Font del Pascol 42.53333 1.55 V FRST AD 00 0 1344 Europe/Andorra 1993-12-23
+3040417 Serrat de la Font del Mallol Serrat de la Font del Mallol 42.55 1.55 T SPUR AD 00 0 2097 Europe/Andorra 1993-12-23
+3040418 Bosc de la Font del Mallol Bosc de la Font del Mallol 42.55 1.55 V FRST AD 00 0 2097 Europe/Andorra 1993-12-23
+3040419 Canal de la Font del Llop Canal de la Font del Llop 42.55 1.46667 H STM AD 00 0 1585 Europe/Andorra 1993-12-23
+3040420 Bosc de la Font del Gripal Bosc de la Font del Gripal 42.51667 1.5 V FRST AD 00 0 1688 Europe/Andorra 1993-12-23
+3040421 Canal de la Font del Cuc Canal de la Font del Cuc 42.48333 1.51667 H STM AD 00 0 2061 Europe/Andorra 1993-12-23
+3040422 Canal de la Font del Boix Canal de la Font del Boix 42.55 1.48333 H STM AD 00 0 1548 Europe/Andorra 1993-12-23
+3040423 Bosc de la Font del Bisbe Bosc de la Font del Bisbe 42.55 1.46667 V FRST AD 00 0 1585 Europe/Andorra 1993-12-23
+3040424 Barranc de la Font de la Pauca Barranc de la Font de la Pauca 42.56667 1.58333 H STM AD 00 0 1919 Europe/Andorra 1993-12-23
+3040425 Canal de la Font de l’Angleveta Canal de la Font de l'Angleveta 42.53333 1.5 H STM AD 00 0 1357 Europe/Andorra 1993-12-23
+3040426 Planell de la Font de l’Altar Planell de la Font de l'Altar 42.55 1.41667 T UPLD AD 00 0 2105 Europe/Andorra 1993-12-23
+3040427 Canal de la Font de la Gallina Canal de la Font de la Gallina 42.48333 1.46667 H STM AD 00 0 1148 Europe/Andorra 1993-12-23
+3040428 Oratori de la Font de Joans Oratori de la Font de Joans 42.48333 1.48333 S AMTH AD 00 0 981 Europe/Andorra 1993-12-23
+3040429 Basers de la Font de Joans Basers de la Font de Joans 42.48333 1.48333 T CLF AD 00 0 981 Europe/Andorra 1993-12-23
+3040430 Canal de la Font de Gambada Canal de la Font de Gambada 42.56667 1.5 H STM AD 00 0 1636 Europe/Andorra 1993-12-23
+3040431 Fontauzina Fontauzina 42.58333 1.63333 T SLP AD 00 0 1722 Europe/Andorra 1993-12-23
+3040432 Camà de Fontargent Cami de Fontargent 42.61667 1.71667 R TRL AD 00 0 2352 Europe/Andorra 1993-12-23
+3040433 Barranc de la Font Antiga Barranc de la Font Antiga 42.55 1.48333 H STM AD 00 0 1548 Europe/Andorra 1993-12-23
+3040434 Canal de les Fontanelles Canal de les Fontanelles 42.45 1.48333 H STM AD 00 0 1111 Europe/Andorra 1993-12-23
+3040435 Pont de Fontaneda Pont de Fontaneda 42.46667 1.48333 S BDG AD 00 0 1134 Europe/Andorra 1993-12-23
+3040436 Boscarró de Fontaneda Boscarro de Fontaneda 42.45 1.48333 V FRST AD 00 0 1111 Europe/Andorra 1993-12-23
+3040437 Fontaneda Fontaneda 42.45432 1.46402 P PPL AD 06 0 1253 Europe/Andorra 2011-04-19
+3040438 Fontanals del Pui Fontanals del Pui 42.46667 1.48333 H STM AD 00 0 1134 Europe/Andorra 1993-12-23
+3040439 Bosc dels Fontanals Bosc dels Fontanals 42.55 1.58333 V FRST AD 00 0 1499 Europe/Andorra 1993-12-23
+3040440 Font del Fontanal Font del Fontanal 42.46667 1.5 H SPNG AD 00 0 1383 Europe/Andorra 1993-12-23
+3040441 Canal del Fontanal Canal del Fontanal 42.58333 1.65 H RVN AD 00 0 1767 Europe/Andorra 1993-12-23
+3040442 Riu de Font Amagada Riu de Font Amagada 42.53333 1.53333 H STM AD 00 0 1521 Europe/Andorra 1993-12-23
+3040443 Planell de la Font Planell de la Font 42.56667 1.66667 T UPLD AD 00 0 1938 Europe/Andorra 1993-12-23
+3040444 Costa de la Font Costa de la Font 42.53333 1.51667 T SLP AD 00 0 1361 Europe/Andorra 1993-12-23
+3040445 Clot de la Font Clot de la Font 42.6 1.66667 H RVN AD 00 0 1858 Europe/Andorra 1993-12-23
+3040446 Canal de la Font Canal de la Font 42.58333 1.48333 H STM AD 00 0 1809 Europe/Andorra 1993-12-23
+3040447 Clots Fondos Clots Fondos 42.55 1.61667 H RVN AD 00 0 2206 Europe/Andorra 1993-12-23
+3040448 Collada Fonda Collada Fonda Collada Fonda 42.46667 1.63333 T PASS AD 00 0 2619 Europe/Andorra 2011-11-05
+3040449 Canal Fonda Canal Fonda 42.53333 1.61667 H STM AD 00 0 2237 Europe/Andorra 1993-12-23
+3040450 Cortal del Folc Cortal del Folc 42.45 1.5 S CRRL AD 00 0 1614 Europe/Andorra 1993-12-23
+3040451 Planell del Fogal Planell del Fogal 42.63333 1.56667 T UPLD AD 00 0 2394 Europe/Andorra 1993-12-23
+3040452 Planell de les Flores Planell de les Flores 42.61667 1.5 T UPLD AD 00 0 2390 Europe/Andorra 1993-12-23
+3040453 Canal de les Flamies Canal de les Flamies 42.58333 1.61667 H RVN AD 00 0 1707 Europe/Andorra 1993-12-23
+3040454 Roc del Fiter Roc del Fiter 42.45 1.51667 T CLF AD 00 0 1790 Europe/Andorra 1993-12-23
+3040455 Borda del Fiter Borda del Fiter 42.58333 1.61667 S HUT AD 00 0 1707 Europe/Andorra 1993-12-23
+3040456 Canal de la Fita Canal de la Fita 42.53333 1.6 H STM AD 00 0 1888 Europe/Andorra 1993-12-23
+3040457 Bosc de la Fita Bosc de la Fita 42.56667 1.53333 V FRST AD 00 0 1669 Europe/Andorra 1993-12-23
+3040458 Coll de Finestres Coll de Finestres 42.43333 1.55 T SPUR AD 00 0 2178 Europe/Andorra 1993-12-23
+3040459 Coll de la Finestra Coll de la Finestra 42.5 1.53333 T SPUR AD 00 0 1574 Europe/Andorra 1993-12-23
+3040460 Bosc de la Finestra Bosc de la Finestra 42.55 1.46667 V FRST AD 00 0 1585 Europe/Andorra 1993-12-23
+3040461 Canal de les Fijoles Canal de les Fijoles 42.58333 1.48333 H RVN AD 00 0 1809 Europe/Andorra 1993-12-23
+3040462 Canal de Fhasa Canal de Fhasa 42.51667 1.56667 H CNL AD 00 0 1759 Europe/Andorra 1993-12-23
+3040463 Font de Ferrús Font de Ferrus 42.51667 1.51667 H SPNG AD 00 0 1265 Europe/Andorra 1993-12-23
+3040464 Font de Ferro del Planell Gran Font de Ferro del Planell Gran 42.53333 1.6 H SPNG AD 00 0 1888 Europe/Andorra 1993-12-23
+3040465 Font de Ferro Font de Ferro 42.58333 1.58333 H SPNG AD 00 0 1993 Europe/Andorra 1993-12-23
+3040466 Font de Ferro Font de Ferro 42.46667 1.48333 H SPNG AD 00 0 1134 Europe/Andorra 1993-12-23
+3040467 Solana de Ferreroles Solana de Ferreroles 42.6 1.56667 T SLP AD 00 0 2513 Europe/Andorra 1993-12-23
+3040468 Riu de Ferreroles Riu de Ferreroles 42.6 1.53333 H STM AD 00 0 1695 Europe/Andorra 1993-12-23
+3040469 Planells de Ferreroles Planells de Ferreroles 42.6 1.55 T UPLD AD 00 0 2298 Europe/Andorra 1993-12-23
+3040470 Collada de Ferreroles Collada de Ferreroles 42.61667 1.56667 T PASS AD 00 0 2228 Europe/Andorra 1993-12-23
+3040471 Clots de Ferreroles Clots de Ferreroles 42.6 1.56667 H RVN AD 00 0 2513 Europe/Andorra 1993-12-23
+3040472 Pont de Ferreres Pont de Ferreres 42.6 1.53333 S BDG AD 00 0 1695 Europe/Andorra 1993-12-23
+3040473 Font del Feritxet Font del Feritxet 42.51667 1.6 H SPNG AD 00 0 2085 Europe/Andorra 1993-12-23
+3040474 Feritxet Feritxet 42.51667 1.6 A ADMD AD 00 0 2085 Europe/Andorra 1993-12-23
+3040475 Font del Fenoll Font del Fenoll 42.58333 1.46667 H SPNG AD 00 0 1643 Europe/Andorra 1993-12-23
+3040476 Barranc del Fenetau Barranc del Fenetau 42.6 1.66667 H STM AD 00 0 1858 Europe/Andorra 1993-12-23
+3040477 Bosc dels Feners Bosc dels Feners 42.43333 1.5 V FRST AD 00 0 1804 Europe/Andorra 1993-12-23
+3040478 Bordes dels Fenerols Bordes dels Fenerols 42.53333 1.5 S HUTS AD 00 0 1357 Europe/Andorra 1993-12-23
+3040479 Fener Llong Fener Llong 42.55 1.55 L LCTY AD 00 0 2097 Europe/Andorra 1993-12-23
+3040480 Canal de Fener de Cussols Canal de Fener de Cussols 42.53333 1.51667 H STM AD 00 0 1361 Europe/Andorra 1993-12-23
+3040481 Fener de Comadejó Fener de Comadejo 42.5 1.48333 L LCTY AD 00 0 1316 Europe/Andorra 1993-12-23
+3040482 Canal del Fener Blanc Canal del Fener Blanc 42.48333 1.48333 H STM AD 00 0 981 Europe/Andorra 1993-12-23
+3040483 Torrent dels Fenerals Torrent dels Fenerals 42.5 1.45 H STM AD 00 0 1840 Europe/Andorra 1993-12-23
+3040484 Obagues dels Fenerals Obagues dels Fenerals 42.5 1.45 T SLP AD 00 0 1840 Europe/Andorra 1993-12-23
+3040485 Bosc de les Fenemores Bosc de les Fenemores 42.53333 1.48333 V FRST AD 00 0 1677 Europe/Andorra 1993-12-23
+3040486 Borda del Fenemars Borda del Fenemars 42.58333 1.63333 S HUT AD 00 0 1722 Europe/Andorra 1993-12-23
+3040487 Barraca de Fembra Morta Barraca de Fembra Morta 42.56667 1.71667 S HUT AD 00 0 2219 Europe/Andorra 1993-12-23
+3040488 Bosc del Felegrill Bosc del Felegrill 42.53333 1.53333 V FRST AD 00 0 1521 Europe/Andorra 1993-12-23
+3040489 Bosc de les Feixes Bosc de les Feixes 42.55 1.43333 V FRST AD 00 0 1949 Europe/Andorra 1993-12-23
+3040490 Feixar de Setut Feixar de Setut 42.46667 1.63333 L LCTY AD 00 0 2619 Europe/Andorra 1993-12-23
+3040491 Feixar del Baladre Feixar del Baladre 42.65 1.55 L LCTY AD 00 0 2181 Europe/Andorra 1993-12-23
+3040492 Pic del Feixar Pic del Feixar 42.46667 1.63333 T PK AD 00 0 2619 Europe/Andorra 1993-12-23
+3040493 Font del Feixar Font del Feixar 42.46667 1.63333 H SPNG AD 00 0 2619 Europe/Andorra 1993-12-23
+3040494 Feixants de Xixerella Feixants de Xixerella 42.55 1.48333 L LCTY AD 00 0 1548 Europe/Andorra 1993-12-23
+3040495 Feixa de l’Escobar Feixa de l'Escobar 42.43333 1.5 L LCTY AD 00 0 1804 Europe/Andorra 1993-12-23
+3040496 Clots de la Febrerrussa Clots de la Febrerrussa 42.46667 1.55 H RVN AD 00 0 2341 Europe/Andorra 1993-12-23
+3040497 Canal del Favar Canal del Favar 42.51667 1.53333 H STM AD 00 0 1460 Europe/Andorra 1993-12-23
+3040498 Solà de Faucellers Sola de Faucellers 42.45 1.5 T SLP AD 00 0 1614 Europe/Andorra 1993-12-23
+3040499 Pont de Faucellers Pont de Faucellers 42.45 1.5 S BDG AD 00 0 1614 Europe/Andorra 1993-12-23
+3040500 Faucellers Faucellers 42.45 1.5 L LCTY AD 00 0 1614 Europe/Andorra 1993-12-23
+3040501 Serrat de la Farga Serrat de la Farga 42.45 1.53333 T RDGE AD 00 0 1859 Europe/Andorra 1993-12-23
+3040502 Pont de la Farga Pont de la Farga 42.61667 1.53333 S BDG AD 00 0 1609 Europe/Andorra 1993-12-23
+3040503 Barraca de la Farga Barraca de la Farga 42.5 1.6 S HUT AD 00 0 2416 Europe/Andorra 1993-12-23
+3040504 Roc del Far Roc del Far 42.43333 1.5 T RK AD 00 0 1804 Europe/Andorra 1993-12-23
+3040505 Plana del Far Plana del Far 42.48333 1.41667 T SLP AD 00 0 1920 Europe/Andorra 1993-12-23
+3040506 Fangots de Moretó Fangots de Moreto 42.55 1.68333 L LCTY AD 00 0 2254 Europe/Andorra 1993-12-23
+3040507 Fangots dels Maians Fangots dels Maians 42.55 1.61667 L LCTY AD 00 0 2206 Europe/Andorra 1993-12-23
+3040508 Fangot Gran Fangot Gran 42.53333 1.63333 L LCTY AD 00 0 2360 Europe/Andorra 1993-12-23
+3040509 Canya de les Falgueres Canya de les Falgueres 42.45 1.46667 S CAVE AD 00 0 935 Europe/Andorra 1993-12-23
+3040510 Falconeres Falconeres 42.55 1.7 L LCTY AD 00 0 2358 Europe/Andorra 1993-12-23
+3040511 Serra de Falcobà Serra de Falcobi 42.63333 1.55 T MT AD 00 0 2053 Europe/Andorra 1993-12-23
+3040512 Canya dels Eucassers Canya dels Eucassers 42.55 1.61667 S CAVE AD 00 0 2206 Europe/Andorra 1993-12-23
+3040513 Cabana de l' Eucasser Cabana de l' Eucasser 42.63086 1.48341 S HUT AD 07 0 2111 Europe/Andorra 2007-03-04
+3040514 Cabana de l’ Eucasser Cabana de l' Eucasser 42.61667 1.56667 S HUT AD 00 0 2228 Europe/Andorra 1993-12-23
+3040515 Cabana de l’ Eucasser Cabana de l' Eucasser 42.58333 1.61667 S HUT AD 00 0 1707 Europe/Andorra 1993-12-23
+3040516 Pala Estreta Pala Estreta 42.55 1.7 T SLP AD 00 0 2358 Europe/Andorra 1993-12-23
+3040517 Torrent Estret Torrent Estret 42.53333 1.56667 H STM AD 00 0 1418 Europe/Andorra 1993-12-23
+3040518 Cortal de Estevet Cortal de Estevet 42.5 1.53333 S CRRL AD 00 0 1574 Europe/Andorra 1993-12-23
+3040519 Collada dels Estanys Forcats Collada dels Estanys Forcats Collada dels Estanys Forcats 42.6 1.45 T PK AD 00 0 2174 Europe/Andorra 2011-11-05
+3040520 Clots de l’ Estany Segon Clots de l' Estany Segon 42.61667 1.73333 H RVN AD 00 0 2508 Europe/Andorra 1993-12-23
+3040521 Estanys de Tristaina Estanys de Tristaina 42.64217 1.48615 H LKS AD 07 0 2530 Europe/Andorra 2007-04-29
+3040522 Estanys del Pessons Estanys del Pessons 42.51667 1.66667 L LCTY AD 00 0 2410 Europe/Andorra 1993-12-23
+3040523 Estanys de l’Obac Estanys de l'Obac 42.51667 1.66667 L LCTY AD 00 0 2410 Europe/Andorra 1993-12-23
+3040524 Estanys de la Solana Estanys de la Solana 42.53333 1.66667 L LCTY AD 00 0 2489 Europe/Andorra 1993-12-23
+3040525 Estanys de Juclar Estanys de Juclar 42.61667 1.71667 L LCTY AD 00 0 2352 Europe/Andorra 1993-12-23
+3040526 Serra dels Estanys Serra dels Estanys 42.58333 1.58333 T RDGE AD 00 0 1993 Europe/Andorra 1993-12-23
+3040527 Riu dels Estanys Riu dels Estanys 42.6 1.61667 H STM AD 00 0 2271 Europe/Andorra 1993-12-23
+3040528 Collada dels Estanys Collada dels Estanys 42.58333 1.58333 T PASS AD 00 0 1993 Europe/Andorra 1993-12-23
+3040529 Camà dels Estanys Cami dels Estanys 42.48333 1.65 R TRL AD 00 0 2658 Europe/Andorra 1993-12-23
+3040530 Cabana dels Estanys Cabana dels Estanys 42.48333 1.65 S HUT AD 00 0 2658 Europe/Andorra 1993-12-23
+3040531 Estanyons de Banyell Estanyons de Banyell 42.65 1.56667 L LCTY AD 00 0 2471 Europe/Andorra 1993-12-23
+3040532 Pic dels Estanyons Pic dels Estanyons Pic dels Estanyons,Toseta de la Colilla,Tosseta de la Caulla,Tosseta de la Caülla 42.46667 1.61667 T PK AD 00 0 2448 Europe/Andorra 2011-11-05
+3040533 Estanys dels Estanyons Estanys dels Estanyons 42.46667 1.61667 H LKS AD 00 0 2448 Europe/Andorra 1993-12-23
+3040534 Canals Tancades dels Estanyons Canals Tancades dels Estanyons 42.46667 1.63333 H RVN AD 00 0 2619 Europe/Andorra 1993-12-23
+3040535 Bosc dels Estanyons Bosc dels Estanyons 42.48333 1.63333 V FRST AD 00 0 2296 Europe/Andorra 1993-12-23
+3040536 Serra de l’ Estanyó Serra de l' Estanyo 42.6 1.58333 T MT AD 00 0 2461 Europe/Andorra 1993-12-23
+3040537 Saleres de l’ Estanyó Saleres de l' Estanyo 42.61667 1.56667 L SALT AD 00 0 2228 Europe/Andorra 1993-12-23
+3040538 Riu de l’ Estanyó Riu de l' Estanyo 42.61667 1.56667 H STM AD 00 0 2228 Europe/Andorra 1993-12-23
+3040539 Pic de l’ Estanyó Pic de l' Estanyo Montagne de l' Estanyo,Montagne de l’ Estanyó,Pic de l' Estanyo,Pic de l’ Estanyó 42.6088 1.59235 T PK AD 00 0 2709 Europe/Andorra 2011-11-05
+3040540 Estret de l’ Estanyó Estret de l' Estanyo 42.61667 1.56667 T PASS AD 00 0 2228 Europe/Andorra 1993-12-23
+3040541 Estany de l’ Estanyó Estany de l' Estanyo 42.61667 1.58333 H LK AD 00 0 2374 Europe/Andorra 1993-12-23
+3040542 Clots de l’ Estanyó Clots de l' Estanyo 42.61667 1.58333 H STMH AD 00 0 2374 Europe/Andorra 1993-12-23
+3040543 Canals de l’ Estanyó Canals de l' Estanyo 42.6 1.58333 H RVN AD 00 0 2461 Europe/Andorra 1993-12-23
+3040544 Serrat de l’ Estany Negre Serrat de l' Estany Negre 42.58333 1.43333 T SPUR AD 00 0 2412 Europe/Andorra 1993-12-23
+3040545 Rocs de l’ Estany Negre Rocs de l' Estany Negre 42.58333 1.43333 T RKS AD 00 0 2412 Europe/Andorra 1993-12-23
+3040546 Basses de l’ Estany Negre Basses de l' Estany Negre 42.58333 1.43333 H LK AD 00 0 2412 Europe/Andorra 1993-12-23
+3040547 Bony de l’ Estany Mort Bony de l' Estany Mort 42.61667 1.61667 T SPUR AD 00 0 2352 Europe/Andorra 1993-12-23
+3040548 Roc de l’ Estany Moreno Roc de l' Estany Moreno 42.51667 1.63333 T CLF AD 00 0 2379 Europe/Andorra 1993-12-23
+3040549 Pala de l’ Estany Gran Pala de l' Estany Gran 42.6 1.58333 T CLF AD 00 0 2461 Europe/Andorra 1993-12-23
+3040550 Riu de l' Estany Esbalçat Riu de l' Estany Esbalcat 42.63612 1.51736 H STM AD 07 0 2334 Europe/Andorra 2007-03-04
+3040551 Port de l’ Estany Esbalçat Port de l' Estany Esbalcat 42.65 1.51667 T PASS AD 00 0 2546 Europe/Andorra 1993-12-23
+3040552 Costa de l’ Estany de Més Avall Costa de l' Estany de Mes Avall 42.6 1.48333 T SPUR AD 00 0 2441 Europe/Andorra 1993-12-23
+3040553 Clots de l’ Estany de Més Avall Clots de l' Estany de Mes Avall 42.6 1.48333 T TAL AD 00 0 2441 Europe/Andorra 1993-12-23
+3040554 Costa de l’ Estany de Més Amunt Costa de l' Estany de Mes Amunt 42.61667 1.48333 T SLP AD 00 0 2470 Europe/Andorra 1993-12-23
+3040555 Costa de l’ Estany del Mig Costa de l' Estany del Mig 42.65 1.48333 T SLP AD 00 0 2341 Europe/Andorra 1993-12-23
+3040556 Canals d’Amunt de l’ Estany del Mig Canals d'Amunt de l' Estany del Mig 42.6 1.48333 H RVN AD 00 0 2441 Europe/Andorra 1993-12-23
+3040557 Riu de l’ Estany de l’Isla Riu de l' Estany de l'Isla 42.61667 1.7 H STM AD 00 0 2285 Europe/Andorra 1993-12-23
+3040558 Canal de l’ Estany de l’Isla Canal de l' Estany de l'Isla 42.61667 1.68333 H RVN AD 00 0 2406 Europe/Andorra 1993-12-23
+3040559 Solana de l’ Estany de l’Illa Solana de l' Estany de l'Illa 42.5 1.65 T SLP AD 00 0 2542 Europe/Andorra 1993-12-23
+3040560 Baser de l’ Estany de les Truites Baser de l' Estany de les Truites 42.56667 1.43333 T CLF AD 00 0 2402 Europe/Andorra 1993-12-23
+3040561 Turó de l’ Estany de la Nou Turo de l' Estany de la Nou 42.46667 1.58333 T SPUR AD 00 0 2367 Europe/Andorra 1993-12-23
+3040562 Camà de l’ Estany de la Nou Cami de l' Estany de la Nou 42.48333 1.58333 R TRL AD 00 0 2349 Europe/Andorra 1993-12-23
+3040563 Riu de l' Estany de Creussans Riu de l' Estany de Creussans 42.63292 1.47976 H STM AD 07 0 2283 Europe/Andorra 2007-03-04
+3040564 Vial de l’ Estany Blau Vial de l' Estany Blau 42.5 1.61667 R RD AD 00 0 2560 Europe/Andorra 1993-12-23
+3040565 Turo de l’ Estany Blau Turo de l' Estany Blau 42.5 1.61667 T PK AD 00 0 2560 Europe/Andorra 1993-12-23
+3040566 Riu de l’ Estany Blau Riu de l' Estany Blau 42.5 1.61667 H STM AD 00 0 2560 Europe/Andorra 1993-12-23
+3040567 Canals de l’ Estany Blau Canals de l' Estany Blau 42.5 1.6 H RVN AD 00 0 2416 Europe/Andorra 1993-12-23
+3040568 Serrat de l’ Estany Serrat de l' Estany 42.51667 1.56667 T MT AD 00 0 1759 Europe/Andorra 1993-12-23
+3040569 Riu de l’ Estany Riu de l' Estany 42.58333 1.43333 H STM AD 00 0 2412 Europe/Andorra 1993-12-23
+3040570 Pla de l’ Estany Pla de l' Estany 42.6 1.46667 T UPLD AD 00 0 2421 Europe/Andorra 1993-12-23
+3040571 Pleta de l’ Estall Serrer Pleta de l' Estall Serrer 42.48333 1.61667 L GRAZ AD 00 0 2217 Europe/Andorra 1993-12-23
+3040572 Planells de l’ Estall Serrer Planells de l' Estall Serrer 42.48333 1.61667 T UPLD AD 00 0 2217 Europe/Andorra 1993-12-23
+3040573 Canals de l’ Estall Serrer Canals de l' Estall Serrer 42.48333 1.61667 H RVN AD 00 0 2217 Europe/Andorra 1993-12-23
+3040574 Bosc de l’ Estall Serrer Bosc de l' Estall Serrer 42.48333 1.61667 V FRST AD 00 0 2217 Europe/Andorra 1993-12-23
+3040575 Estall Serrer Estall Serrer 42.48333 1.61667 L LCTY AD 00 0 2217 Europe/Andorra 1993-12-23
+3040576 Estall Serrer Estall Serrer 42.46667 1.61667 A ADMD AD 00 0 2448 Europe/Andorra 1993-12-23
+3040577 Roc de l’ Estall Roc de l' Estall 42.5 1.58333 T RK AD 00 0 1888 Europe/Andorra 1993-12-23
+3040578 Planell de l’ Estall Planell de l' Estall 42.55 1.55 T UPLD AD 00 0 2097 Europe/Andorra 1993-12-23
+3040579 Collada de l’ Estall Collada de l' Estall 42.55 1.55 T PASS AD 00 0 2097 Europe/Andorra 1993-12-23
+3040580 Carretera de l’ Estall Carretera de l' Estall 42.53333 1.53333 R RD AD 00 0 1521 Europe/Andorra 1993-12-23
+3040581 Borda de l’ Estall Borda de l' Estall 42.55 1.55 S HUT AD 00 0 2097 Europe/Andorra 1993-12-23
+3040582 Pleta de l’ Estaleritx Pleta de l' Estaleritx 42.61667 1.55 L GRAZ AD 00 0 2007 Europe/Andorra 1993-12-23
+3040583 Collada de l’ Estaleritx Collada de l' Estaleritx 42.61667 1.55 T SPUR AD 00 0 2007 Europe/Andorra 1993-12-23
+3040584 Pont dels Esquirols Pont dels Esquirols 42.56667 1.48333 S BDG AD 00 0 1508 Europe/Andorra 1993-12-23
+3040585 Roc de les Esquiroles Roc de les Esquiroles 42.46667 1.5 T RK AD 00 0 1383 Europe/Andorra 1993-12-23
+3040586 Roc de les Esquiroles Roc de les Esquiroles 42.45 1.48333 T RK AD 00 0 1111 Europe/Andorra 1993-12-23
+3040587 Canal de les Esquiroles Canal de les Esquiroles 42.45 1.48333 H STM AD 00 0 1111 Europe/Andorra 1993-12-23
+3040588 Roc d’ Esquers Roc d' Esquers 42.5 1.55 T RK AD 00 0 1566 Europe/Andorra 1993-12-23
+3040589 Roc de l’ Espluga Roc de l' Espluga 42.46667 1.46667 T RK AD 00 0 1340 Europe/Andorra 1993-12-23
+3040590 Planell de l’ Espluga Planell de l' Espluga 42.46667 1.46667 T UPLD AD 00 0 1340 Europe/Andorra 1993-12-23
+3040591 Tosa dels Espiolets Tosa dels Espiolets 42.55 1.65 T UPLD AD 00 0 2432 Europe/Andorra 1993-12-23
+3040592 Espeluga Espeluga 42.56667 1.43333 L LCTY AD 00 0 2402 Europe/Andorra 1993-12-23
+3040593 Espeluga Espeluga 42.53333 1.55 A ADMD AD 00 0 1344 Europe/Andorra 1993-12-23
+3040594 Pont de l’ Espalmera Pont de l' Espalmera 42.55 1.46667 S BDG AD 00 0 1585 Europe/Andorra 1993-12-23
+3040595 Riu de l’ Escobet Riu de l' Escobet 42.46667 1.51667 H STM AD 00 0 1985 Europe/Andorra 1993-12-23
+3040596 Escobet Escobet 42.46667 1.51667 L LCTY AD 00 0 1985 Europe/Andorra 1993-12-23
+3040597 Cylindre d’ Ascobes Cylindre d' Ascobes Cylindre d' Ascobes,Cylindre d’ Ascobes,Pic d' Escobes,Pic d’ Escobes 42.6 1.73333 T PK AD 00 0 2383 Europe/Andorra 2011-11-05
+3040598 Comella dels Esclops Comella dels Esclops 42.43333 1.48333 H STM AD 00 0 1228 Europe/Andorra 1993-12-23
+3040599 Solà d’ Escàs Sola d' Escas 42.55 1.5 T SLP AD 00 0 1292 Europe/Andorra 1993-12-23
+3040600 Camà d’ Escàs Cami d' Escas 42.55 1.5 R TRL AD 00 0 1292 Europe/Andorra 1993-12-23
+3040601 Escàs Escas 42.54643 1.50895 P PPL AD 04 0 1257 Europe/Andorra 2011-04-19
+3040602 Roc d’ Escalluquer Roc d' Escalluquer 42.55 1.5 T CLF AD 00 0 1292 Europe/Andorra 1993-12-23
+3040603 Bosc d’ Escalluquer Bosc d' Escalluquer 42.55 1.5 V FRST AD 00 0 1292 Europe/Andorra 1993-12-23
+3040604 Escalluquer Escalluquer 42.55 1.5 A ADMD AD 00 0 1292 Europe/Andorra 1993-12-23
+3040605 Canal de l’ Escalella Canal de l' Escalella 42.5 1.45 H STM AD 00 0 1840 Europe/Andorra 1993-12-23
+3040606 Vial de l’ Escala Vial de l' Escala 42.48333 1.5 R RD AD 00 0 1631 Europe/Andorra 1993-12-23
+3040607 Estany Esbalçat Estany Esbalcat 42.64002 1.51371 H LK AD 07 0 2130 Europe/Andorra 2007-03-04
+3040608 Obac d’ Erts Obac d' Erts 42.56667 1.5 T SLP AD 00 0 1636 Europe/Andorra 1993-12-23
+3040609 Erts Erts Ercs,Ercz,Erez 42.56218 1.4968 P PPL AD AD 04 0 1430 Europe/Andorra 2007-04-16
+3040610 Costa de les Eroles Costa de les Eroles 42.56667 1.45 T SLP AD 00 0 2137 Europe/Andorra 1993-12-23
+3040611 Solana de l’ Era de Mitges Solana de l' Era de Mitges 42.46667 1.45 T SLP AD 00 0 1562 Europe/Andorra 1993-12-23
+3040612 Refugi d’ Envalira Refugi d' Envalira 42.53333 1.68333 S RSRT AD 00 0 2322 Europe/Andorra 1993-12-23
+3040613 Port d’ Envalira Port d' Envalira Port d' Envalira,Port d’ Envalira,Puerto d' Envalira,Puerto d’ Envalira 42.54041 1.71897 T PASS AD 00 0 2230 Europe/Andorra 2011-11-05
+3040615 Bordes d’ Envalira Bordes d' Envalira Bordas d' Envalira,Bordas d’ Envalira,Bordes d' Envalira,Bordes d’ Envalira 42.56667 1.68333 S HUTS AD 00 0 2340 Europe/Andorra 2011-11-05
+3040616 Envalira Envalira 42.53333 1.7 A ADMD AD 00 0 2357 Europe/Andorra 1993-12-23
+3040617 Solà d’ Entremesaiqües Sola d' Entremesaiques 42.50094 1.55771 T SLP AD 00 0 1621 Europe/Andorra 2011-04-19
+3040618 Pont d’ Entremesaigües Pont d' Entremesaigues 42.5 1.56667 S BDG AD 00 0 1776 Europe/Andorra 1993-12-23
+3040619 Entremesaigües Entremesaigues 42.49692 1.55577 L LCTY AD 00 0 1566 Europe/Andorra 2011-04-19
+3040620 Roca Entravessada Roca Entravessada 42.5986 1.44241 T SPUR AD 00 0 2406 Europe/Andorra 2011-04-19
+3040621 Font de les Entrades Font de les Entrades 42.56667 1.48333 H SPNG AD 00 0 1508 Europe/Andorra 1993-12-23
+3040622 Bosc de l’ Entrada Bosc de l' Entrada 42.55 1.46667 V FRST AD 00 0 1585 Europe/Andorra 1993-12-23
+3040623 Camà d’ Entor Cami d' Entor 42.58333 1.63333 R TRL AD 00 0 1722 Europe/Andorra 1993-12-23
+3040624 Bosc d’ Entor Bosc d' Entor 42.58333 1.65 V FRST AD 00 0 1767 Europe/Andorra 1993-12-23
+3040625 Entor Entor 42.6 1.65 A ADMD AD 00 0 2131 Europe/Andorra 1993-12-23
+3040626 Collada d’ Entinyola Collada d' Entinyola 42.51667 1.65 T PASS AD 00 0 2633 Europe/Andorra 1993-12-23
+3040627 Clots d’ Entinyac Clots d' Entinyac 42.58333 1.68333 H STMH AD 00 0 2294 Europe/Andorra 1993-12-23
+3040628 Tarteres d’ Entalàs Tarteres d' Entalas 42.53333 1.63333 T TAL AD 00 0 2360 Europe/Andorra 1993-12-23
+3040629 Canals d’ Entalàs Canals d' Entalas 42.53333 1.63333 H RVN AD 00 0 2360 Europe/Andorra 1993-12-23
+3040630 Bosc d’ En Som Bosc d' En Som 42.56667 1.58333 V FRST AD 00 0 1919 Europe/Andorra 1993-12-23
+3040631 Serra de l’ Ensegur Serra de l' Ensegur 42.58333 1.55 T RDGE AD 00 0 2357 Europe/Andorra 1993-12-23
+3040632 Riu de l’ Ensegur Riu de l' Ensegur 42.6 1.53333 H STM AD 00 0 1695 Europe/Andorra 1993-12-23
+3040633 Obaga de l’ Ensegur Obaga de l' Ensegur 42.58333 1.55 T SLP AD 00 0 2357 Europe/Andorra 1993-12-23
+3040634 Collada de l’ Ensegur Collada de l' Ensegur 42.58333 1.53333 T PASS AD 00 0 1924 Europe/Andorra 1993-12-23
+3040635 Clot de l’ Ensegur Clot de l' Ensegur 42.58333 1.55 H RVN AD 00 0 2357 Europe/Andorra 1993-12-23
+3040636 Camà de l’ Ensegur Cami de l' Ensegur 42.58333 1.53333 R TRL AD 00 0 1924 Europe/Andorra 1993-12-23
+3040637 Bosc de l’ Ensegur Bosc de l' Ensegur 42.6 1.55 V FRST AD 00 0 2298 Europe/Andorra 1993-12-23
+3040638 Bordes de l’ Ensegur Bordes de l' Ensegur 42.58333 1.55 S HUTS AD 00 0 2357 Europe/Andorra 1993-12-23
+3040639 Aspres de l’ Ensegur Aspres de l' Ensegur 42.58333 1.55 V VINS AD 00 0 2357 Europe/Andorra 1993-12-23
+3040640 Solana d’ Ensagents Solana d' Ensagents 42.51667 1.63333 T SLP AD 00 0 2379 Europe/Andorra 1993-12-23
+3040641 Riu d’ Ensagents Riu d' Ensagents 42.52752 1.6099 H STM AD 00 0 2101 Europe/Andorra 2011-04-19
+3040642 Obaga d’ Ensagents Obaga d' Ensagents 42.51667 1.63333 T SLP AD 00 0 2379 Europe/Andorra 1993-12-23
+3040643 Estanys d’ Ensagents Estanys d' Ensagents 42.52041 1.64793 H LKS AD 00 0 2627 Europe/Andorra 2011-04-19
+3040644 Ensagents Ensagents 42.51667 1.65 A ADMD AD 00 0 2633 Europe/Andorra 1993-12-23
+3040645 Costa d’ Enradort Costa d' Enradort 42.53333 1.66667 T SLP AD 00 0 2489 Europe/Andorra 1993-12-23
+3040646 Collada d’ Enradort Collada d' Enradort 42.53333 1.66667 T PASS AD 00 0 2489 Europe/Andorra 1993-12-23
+3040647 Rec d’ Engordany Rec d' Engordany 42.51667 1.53333 H CNL AD 00 0 1460 Europe/Andorra 1993-12-23
+3040648 Engordany Engordany Engordany 42.51115 1.54118 P PPL AD 08 0 1139 Europe/Andorra 2007-04-05
+3040649 Pla d’ Engolasters Pla d' Engolasters 42.5 1.56667 T UPLD AD 00 0 1776 Europe/Andorra 1993-12-23
+3040650 Estany d'Engolasters Estany d'Engolasters 42.51966 1.56772 H LK AD 07 0 1615 1759 Europe/Andorra 2007-04-05
+3040651 Carretera d’ Engolasters Carretera d' Engolasters 42.51667 1.56667 R RD AD 00 0 1759 Europe/Andorra 1993-12-23
+3040652 Canal d’ Engolasters Canal d' Engolasters 42.53333 1.6 H CNL AD 00 0 1888 Europe/Andorra 1993-12-23
+3040653 Engolasters Engolasters 42.5 1.56667 A ADMD AD 00 0 1776 Europe/Andorra 1993-12-23
+3040654 Estany d’ Engaït Estany d' Engait 42.51667 1.71667 H LK AD 00 0 2591 Europe/Andorra 1993-12-23
+3040655 Engaït Engait 42.51667 1.71667 A ADMD AD 00 0 2591 Europe/Andorra 1993-12-23
+3040656 Serrat de l’ Enfreu Serrat de l' Enfreu 42.56667 1.56667 T RDGE AD 00 0 2089 Europe/Andorra 1993-12-23
+3040657 Riu de l’ Enfreu Riu de l' Enfreu 42.56667 1.55 H STM AD 00 0 1996 Europe/Andorra 1993-12-23
+3040658 Bosc de l’ Enfreu Bosc de l' Enfreu 42.56667 1.55 V FRST AD 00 0 1996 Europe/Andorra 1993-12-23
+3040659 Borda d’ Endrieta Borda d' Endrieta 42.55 1.58333 S HUT AD 00 0 1499 Europe/Andorra 1993-12-23
+3040660 Obaga d’ Encortesa Obaga d' Encortesa 42.45 1.51667 T SLP AD 00 0 1790 Europe/Andorra 1993-12-23
+3040661 Carretera Encortesa Carretera Encortesa 42.45 1.5 R RD AD 00 0 1614 Europe/Andorra 1993-12-23
+3040662 Encortesa Encortesa 42.45 1.51667 L LCTY AD 00 0 1790 Europe/Andorra 1993-12-23
+3040663 Camà d’ Encodina Cami d' Encodina 42.63333 1.53333 R TRL AD 00 0 2072 Europe/Andorra 1993-12-23
+3040664 Encodina Encodina 42.63333 1.53333 L LCTY AD 00 0 2072 Europe/Andorra 1993-12-23
+3040665 Serra d’ Enclar Serra d' Enclar 42.51408 1.48329 T RDGE AD 00 0 2069 Europe/Andorra 2011-04-19
+3040666 Riu d’ Enclar Riu d' Enclar 42.49067 1.49562 H STM AD 00 0 1353 Europe/Andorra 2011-04-19
+3040667 Prat d’ Enclar Prat d' Enclar 42.5 1.48333 L GRAZ AD 00 0 1316 Europe/Andorra 1993-12-23
+3040668 Bony de Garci Bony de Garci Bony de Garci,Pic d' Enclar,Pic d’ Enclar,Puig de Ancla,Puig de Anclá 42.51667 1.46667 T PK AD 00 0 1840 Europe/Andorra 2011-11-05
+3040669 Camà d’ Enclar Cami d' Enclar 42.5 1.48333 R TRL AD 00 0 1316 Europe/Andorra 1993-12-23
+3040670 Bosc d’ Enclar Bosc d' Enclar 42.48333 1.48333 V FRST AD 00 0 981 Europe/Andorra 1993-12-23
+3040671 Font de l’ Enciam Font de l' Enciam 42.61667 1.51667 H SPNG AD 00 0 1716 Europe/Andorra 1993-12-23
+3040672 Carrerons d’ Encenrera Carrerons d' Encenrera 42.53333 1.68333 R TRL AD 00 0 2322 Europe/Andorra 1993-12-23
+3040673 Encenrera Encenrera 42.53333 1.68333 L LCTY AD 00 0 2322 Europe/Andorra 1993-12-23
+3040674 Clots d’ Encarners Clots d' Encarners 42.6 1.58333 H RVN AD 00 0 2461 Europe/Andorra 1993-12-23
+3040675 Basera d’ Encarners Basera d' Encarners 42.5 1.45 T CLF AD 00 0 1840 Europe/Andorra 1993-12-23
+3040676 Basera d’ Encarners Basera d' Encarners 42.46667 1.55 T CLF AD 00 0 2341 Europe/Andorra 1993-12-23
+3040677 Solà d’ Encampadana Sola d' Encampadana 42.55 1.61667 T SLP AD 00 0 2206 Europe/Andorra 1993-12-23
+3040678 Pic d’ Encampadana Pic d' Encampadana Pic d' Encampadana,Pic d’ Encampadana,Tossa d' Encampdana,Tossa d’ Encampdana,Tossal d' Encampdana,Tossal d’ Encampdana 42.5552 1.63153 T PK AD 00 0 2364 Europe/Andorra 2011-11-05
+3040679 Obaga d’ Encampadana Obaga d' Encampadana 42.55 1.61667 T SLP AD 00 0 2206 Europe/Andorra 1993-12-23
+3040680 Font d’ Encampadana Font d' Encampadana 42.55 1.61667 H SPNG AD 00 0 2206 Europe/Andorra 1993-12-23
+3040681 Clot d’ Encampadana Clot d' Encampadana 42.55 1.61667 H RVN AD 00 0 2206 Europe/Andorra 1993-12-23
+3040682 Encampadana Encampadana 42.56667 1.61667 A ADMD AD 00 0 1920 Europe/Andorra 1993-12-23
+3040683 Serra d’ Encamp Serra d' Encamp 42.53333 1.55 T RDGE AD 00 0 1344 Europe/Andorra 1993-12-23
+3040684 Parròquia d'Encamp Parroquia d'Encamp Encamp,Parroquia d'Encamp,Parròquia d'Encamp 42.53333 1.63333 A ADM1 AD 03 13685 2360 Europe/Andorra 2008-03-17
+3040685 Estany d’ Encamp Estany d' Encamp 42.5 1.65 H LK AD 00 0 2542 Europe/Andorra 1993-12-23
+3040686 Encamp Encamp Ehnkam,Encamp,en kan pu,enkanpu jiao qu,Ðнкам,エンカンプ教区,æ©åŽæ™® 42.53451 1.5767 P PPLA AD 03 11223 1309 Europe/Andorra 2011-11-05
+3040687 Borda d’ En Cadena Borda d' En Cadena 42.53333 1.56667 S HUT AD 00 0 1418 Europe/Andorra 1993-12-23
+3040688 Pleta d’ Emportona Pleta d' Emportona 42.53333 1.65 L GRAZ AD 00 0 2508 Europe/Andorra 1993-12-23
+3040689 Emportona Emportona 42.53333 1.65 A ADMD AD 00 0 2508 Europe/Andorra 1993-12-23
+3040690 Riu de l’ Empallador Riu de l' Empallador 42.53333 1.7 H STM AD 00 0 2357 Europe/Andorra 1993-12-23
+3040691 Canal de l’ Embut Canal de l' Embut 42.58333 1.48333 H RVN AD 00 0 1809 Europe/Andorra 1993-12-23
+3040692 Clots d’ Embolcar Clots d' Embolcar 42.61667 1.61667 T CRQS AD 00 0 2352 Europe/Andorra 1993-12-23
+3040693 Basers d’ Embolcar Basers d' Embolcar 42.61667 1.61667 T CLF AD 00 0 2352 Europe/Andorra 1993-12-23
+3040694 El Vilar El Vilar El Vilar 42.57226 1.60781 P PPL AD 02 0 1655 Europe/Andorra 2011-11-05
+3040695 El Vedat El Vedat 42.46667 1.48333 A ADMD AD 00 0 1134 Europe/Andorra 1993-12-23
+3040696 El Turer El Turer 42.56667 1.53333 T SPUR AD 00 0 1669 Europe/Andorra 1993-12-23
+3040697 El Trillar El Trillar 42.46667 1.5 L LCTY AD 00 0 1383 Europe/Andorra 1993-12-23
+3040698 El Tremat El Tremat 42.53348 1.58056 P PPL AD 03 0 1309 Europe/Andorra 2011-04-19
+3040699 El Torrentill El Torrentill 42.45 1.48333 H STM AD 00 0 1111 Europe/Andorra 1993-12-23
+3040700 El Tarter El Tarter 42.58026 1.64902 P PPL AD 02 0 1737 Europe/Andorra 2007-04-16
+3040701 El Tamany El Tamany 42.63333 1.51667 T SLP AD 00 0 1894 Europe/Andorra 1993-12-23
+3040702 Els Tarters Els Tarters 42.56667 1.68333 L LCTY AD 00 0 2340 Europe/Andorra 1993-12-23
+3040703 Els Tarterals Els Tarterals 42.48333 1.51667 L LCTY AD 00 0 2061 Europe/Andorra 1993-12-23
+3040704 Els Rebolians Els Rebolians 42.53333 1.51667 L LCTY AD 00 0 1361 Europe/Andorra 1993-12-23
+3040705 Els Quatre Rocs Els Quatre Rocs 42.46667 1.53333 T RKS AD 00 0 2332 Europe/Andorra 1993-12-23
+3040706 Els Pujols Els Pujols 42.48333 1.48333 L LCTY AD 00 0 981 Europe/Andorra 1993-12-23
+3040707 Els Puiols Els Puiols 42.56667 1.63333 L LCTY AD 00 0 2016 Europe/Andorra 1993-12-23
+3040708 Els Pletius Els Pletius 42.61667 1.68333 L LCTY AD 00 0 2406 Europe/Andorra 1993-12-23
+3040709 Els Plans Els Plans 42.58142 1.63273 P PPL AD 02 0 1722 Europe/Andorra 2011-04-19
+3040710 Els Plans Els Plans 42.45084 1.50641 L LCTY AD 00 0 1394 Europe/Andorra 2011-04-19
+3040711 Els Plans Els Plans 42.45 1.5 S FRM AD 00 0 1614 Europe/Andorra 1993-12-23
+3040712 Els Plans Els Plans 42.53333 1.51667 A ADMD AD 00 0 1361 Europe/Andorra 1993-12-23
+3040713 Els Pessons Els Pessons 42.51667 1.66667 A ADMD AD 00 0 2410 Europe/Andorra 1993-12-23
+3040714 Els Pallers Els Pallers 42.56667 1.75 L LCTY AD 00 0 1923 Europe/Andorra 1993-12-23
+3040715 Els Pallerils Els Pallerils 42.58333 1.53333 L LCTY AD 00 0 1924 Europe/Andorra 1993-12-23
+3040716 Els Padals Els Padals 42.58333 1.66667 L LCTY AD 00 0 2159 Europe/Andorra 1993-12-23
+3040717 Els Orris Els Orris 42.55 1.46667 L LCTY AD 00 0 1585 Europe/Andorra 1993-12-23
+3040718 Els Oriosos Els Oriosos 42.53333 1.53333 L LCTY AD 00 0 1521 Europe/Andorra 1993-12-23
+3040719 El Solà El Sola 42.55 1.53333 L LCTY AD 00 0 1593 Europe/Andorra 1993-12-23
+3040720 Els Obacs Els Obacs 42.6 1.5 T SLP AD 00 0 1923 Europe/Andorra 1993-12-23
+3040721 Els Obacs Els Obacs 42.55 1.48333 L LCTY AD 00 0 1548 Europe/Andorra 1993-12-23
+3040722 Els Maians Els Maians 42.55 1.61667 L LCTY AD 00 0 2206 Europe/Andorra 1993-12-23
+3040723 Els Llacs Els Llacs 42.53333 1.41667 T UPLD AD 00 0 1948 Europe/Andorra 1993-12-23
+3040724 Els Indrets Els Indrets 42.48333 1.45 L LCTY AD 00 0 1195 Europe/Andorra 1993-12-23
+3040725 Els Hortells Els Hortells 42.45 1.5 L LCTY AD 00 0 1614 Europe/Andorra 1993-12-23
+3040726 Els Graus Els Graus 42.56667 1.73333 L LCTY AD 00 0 2096 Europe/Andorra 1993-12-23
+3040727 Els Graus Els Graus 42.48333 1.56667 A ADMD AD 00 0 2231 Europe/Andorra 1993-12-23
+3040728 Els Fontanals Els Fontanals 42.56667 1.68333 L LCTY AD 00 0 2340 Europe/Andorra 1993-12-23
+3040729 Els Feners Els Feners 42.58333 1.66667 T SLP AD 00 0 2159 Europe/Andorra 1993-12-23
+3040730 Els Feners Els Feners 42.48333 1.48333 L LCTY AD 00 0 981 Europe/Andorra 1993-12-23
+3040731 Els Fenerols Els Fenerols 42.53333 1.56667 L LCTY AD 00 0 1418 Europe/Andorra 1993-12-23
+3040732 Els Fenerols Els Fenerols 42.53333 1.5 L LCTY AD 00 0 1357 Europe/Andorra 1993-12-23
+3040733 Els Fenerals Els Fenerals 42.5 1.46667 A ADMD AD 00 0 1678 Europe/Andorra 1993-12-23
+3040734 Els Estanys Els Estanys 42.48333 1.63333 A ADMD AD 00 0 2296 Europe/Andorra 1993-12-23
+3040735 Els Estanyons Els Estanyons 42.46667 1.61667 L LCTY AD 00 0 2448 Europe/Andorra 1993-12-23
+3040736 Els Espiolets Els Espiolets 42.56667 1.66667 L LCTY AD 00 0 1938 Europe/Andorra 1993-12-23
+3040737 El Serrat El Serrat Lo Serrat 42.6183 1.53912 P PPL AD AD 05 0 1704 Europe/Andorra 2007-04-16
+3040738 El Seig El Seig 42.53333 1.58333 A ADMD AD 00 0 1571 Europe/Andorra 1993-12-23
+3040739 Els Cuiners Els Cuiners 42.63333 1.55 L CLG AD 00 0 2053 Europe/Andorra 1993-12-23
+3040740 Els Cortals Els Cortals 42.53333 1.61667 A ADMD AD 00 0 2237 Europe/Andorra 1993-12-23
+3040741 Els Corralets Els Corralets 42.56667 1.55 L LCTY AD 00 0 1996 Europe/Andorra 1993-12-23
+3040742 Els Colls Els Colls 42.55 1.51667 L LCTY AD 00 0 1397 Europe/Andorra 1993-12-23
+3040743 Els Collets Els Collets 42.53333 1.51667 L LCTY AD 00 0 1361 Europe/Andorra 1993-12-23
+3040744 Els Collells Els Collells 42.56667 1.48333 T PK AD 00 0 1508 Europe/Andorra 1993-12-23
+3040745 Els Colells Els Colells 42.6 1.7 L LCTY AD 00 0 2354 Europe/Andorra 1993-12-23
+3040746 Els Colells Els Colells 42.51667 1.7 A ADMD AD 00 0 2435 Europe/Andorra 1993-12-23
+3040747 Els Clots Els Clots 42.56667 1.6 T SLP AD 00 0 1655 Europe/Andorra 1993-12-23
+3040748 Els Clots Els Clots 42.55 1.43333 L LCTY AD 00 0 1949 Europe/Andorra 1993-12-23
+3040749 Els Caubets Els Caubets 42.55 1.48333 T VAL AD 00 0 1548 Europe/Andorra 1993-12-23
+3040750 Els Carabedius Els Carabedius 42.46667 1.45 L LCTY AD 00 0 1562 Europe/Andorra 1993-12-23
+3040751 Els Canalons Els Canalons 42.48333 1.48333 H RVN AD 00 0 981 Europe/Andorra 1993-12-23
+3040752 Els Botaders Els Botaders 42.48333 1.56667 L LCTY AD 00 0 2231 Europe/Andorra 1993-12-23
+3040753 Els Bedres Els Bedres 42.55 1.48333 L LCTY AD 00 0 1548 Europe/Andorra 1993-12-23
+3040754 Els Beçolans Els Becolans 42.63333 1.55 L LCTY AD 00 0 2053 Europe/Andorra 1993-12-23
+3040755 Els Bassots Els Bassots 42.55 1.65 H LKS AD 00 0 2432 Europe/Andorra 1993-12-23
+3040756 Els Aubells Els Aubells 42.56667 1.53333 L LCTY AD 00 0 1669 Europe/Andorra 1993-12-23
+3040757 Els Astrells Els Astrells 42.5 1.56667 L LCTY AD 00 0 1776 Europe/Andorra 1993-12-23
+3040758 Els Assaladors Els Assaladors 42.55 1.66667 L LCTY AD 00 0 2224 Europe/Andorra 1993-12-23
+3040759 Els Aspres Els Aspres 42.56667 1.45 T RKS AD 00 0 2137 Europe/Andorra 1993-12-23
+3040760 Els Aspedius Els Aspedius 42.48333 1.53333 L LCTY AD 00 0 2255 Europe/Andorra 1993-12-23
+3040761 El Saquet El Saquet 42.6 1.53333 A ADMD AD 00 0 1695 Europe/Andorra 1993-12-23
+3040762 Els Amorriadors Els Amorriadors 42.51667 1.6 L LCTY AD 00 0 2085 Europe/Andorra 1993-12-23
+3040763 Els Alabars Els Alabars 42.5 1.48333 L LCTY AD 00 0 1316 Europe/Andorra 1993-12-23
+3040764 El Riguer El Riguer 42.48333 1.55 A ADMD AD 00 0 2233 Europe/Andorra 1993-12-23
+3040765 El Remugar El Remugar 42.56667 1.53333 L LCTY AD 00 0 1669 Europe/Andorra 1993-12-23
+3040766 El Ramer El Ramer 42.56667 1.48333 L LCTY AD 00 0 1508 Europe/Andorra 1993-12-23
+3040767 El Pui El Pui 42.54731 1.51439 P PPL AD 04 0 1257 Europe/Andorra 2011-04-19
+3040768 El Pouader El Pouader El Ponader,El Pouader 42.53333 1.6 T RK AD AD 00 0 1888 Europe/Andorra 2011-11-05
+3040769 El Pletiu El Pletiu 42.5 1.6 L GRAZ AD 00 0 2416 Europe/Andorra 1993-12-23
+3040770 El Planellet El Planellet 42.61667 1.53333 L LCTY AD 00 0 1609 Europe/Andorra 1993-12-23
+3040771 El Pla El Pla 42.53333 1.58333 L LCTY AD 00 0 1571 Europe/Andorra 1993-12-23
+3040772 El Pas Mal El Pas Mal 42.53333 1.65 T PASS AD 00 0 2508 Europe/Andorra 1993-12-23
+3040773 El Pardal El Pardal 42.55 1.5 A ADMD AD 00 0 1292 Europe/Andorra 1993-12-23
+3040774 El Palinqueró El Palinquero 42.58333 1.66667 L LCTY AD 00 0 2159 Europe/Andorra 1993-12-23
+3040775 El Noguer El Noguer 42.51667 1.55 A ADMD AD 00 0 1322 Europe/Andorra 1993-12-23
+3040776 El Mollar El Mollar 42.53333 1.6 L LCTY AD 00 0 1888 Europe/Andorra 1993-12-23
+3040777 El Moixeret El Moixeret 42.58333 1.51667 L LCTY AD 00 0 1722 Europe/Andorra 1993-12-23
+3040778 El Meligar El Meligar 42.5 1.61667 T RDGE AD 00 0 2560 Europe/Andorra 1993-12-23
+3040779 El Mas El Mas 42.56667 1.5 A ADMD AD 00 0 1636 Europe/Andorra 1993-12-23
+3040780 El Maià El Maia 42.56667 1.73333 A ADMD AD 00 0 2096 Europe/Andorra 1993-12-23
+3040781 El Madriu El Madriu 42.48333 1.58333 A ADMD AD 00 0 2349 Europe/Andorra 1993-12-23
+3040782 El Llempo El Llempo 42.58333 1.6 L LCTY AD 00 0 1828 Europe/Andorra 1993-12-23
+3040783 El Jou El Jou 42.56667 1.5 A ADMD AD 00 0 1636 Europe/Andorra 1993-12-23
+3040784 El Griu El Griu 42.53333 1.63333 A ADMD AD 00 0 2360 Europe/Andorra 1993-12-23
+3040785 El Fornet El Fornet 42.55 1.6 L LCTY AD 00 0 2210 Europe/Andorra 1993-12-23
+3040786 El Fornell El Fornell 42.51667 1.51667 L LCTY AD 00 0 1265 Europe/Andorra 1993-12-23
+3040787 El Fornell El Fornell 42.45 1.5 L LCTY AD 00 0 1614 Europe/Andorra 1993-12-23
+3040788 El Forn El Forn 42.55 1.6 A ADMD AD 00 0 2210 Europe/Andorra 1993-12-23
+3040789 El Fontanal El Fontanal 42.46667 1.5 L LCTY AD 00 0 1383 Europe/Andorra 1993-12-23
+3040790 El Cubil El Cubil 42.43333 1.55 L LCTY AD 00 0 2178 Europe/Andorra 1993-12-23
+3040791 El Cubil El Cubil 42.53333 1.68333 A ADMD AD 00 0 2322 Europe/Andorra 1993-12-23
+3040792 El Cresper El Cresper 42.51667 1.56667 A ADMD AD 00 0 1759 Europe/Andorra 1993-12-23
+3040793 El Cortalet El Cortalet 42.55 1.51667 L LCTY AD 00 0 1397 Europe/Andorra 1993-12-23
+3040794 El Cortalet El Cortalet 42.51667 1.56667 L LCTY AD 00 0 1759 Europe/Andorra 1993-12-23
+3040795 El Corbater El Corbater 42.55 1.71667 L LCTY AD 00 0 2192 Europe/Andorra 1993-12-23
+3040796 El Confòs El Confos 42.51667 1.58333 A ADMD AD 00 0 1994 Europe/Andorra 1993-12-23
+3040797 El Collell El Collell 42.45 1.5 T PASS AD 00 0 1614 Europe/Andorra 1993-12-23
+3040798 El Colitx El Colitx 42.58333 1.51667 L LCTY AD 00 0 1722 Europe/Andorra 1993-12-23
+3040799 El Clos El Clos 42.53333 1.6 L LCTY AD 00 0 1888 Europe/Andorra 1993-12-23
+3040800 El Castellar El Castellar 42.63333 1.51667 A ADMD AD 00 0 1894 Europe/Andorra 1993-12-23
+3040801 El Carregador El Carregador 42.56667 1.53333 L LCTY AD 00 0 1669 Europe/Andorra 1993-12-23
+3040802 El Cardemeller El Cardemeller 42.55 1.46667 L LCTY AD 00 0 1585 Europe/Andorra 1993-12-23
+3040803 El Campús El Campus 42.43333 1.48333 T UPLD AD 00 0 1228 Europe/Andorra 1993-12-23
+3040804 El Bullidor El Bullidor 42.55 1.71667 L LCTY AD 00 0 2192 Europe/Andorra 1993-12-23
+3040805 El Brossós El Brossos 42.61667 1.53333 A ADMD AD 00 0 1609 Europe/Andorra 1993-12-23
+3040806 El Braibal El Braibal 42.5 1.58333 L LCTY AD 00 0 1888 Europe/Andorra 1993-12-23
+3040807 El Bosquet El Bosquet 42.56667 1.53333 L LCTY AD 00 0 1669 Europe/Andorra 1993-12-23
+3040808 El Boscarró El Boscarro 42.46667 1.48333 L LCTY AD 00 0 1134 Europe/Andorra 1993-12-23
+3040809 El Barrerol El Barrerol 42.43333 1.45 L LCTY AD 00 0 877 Europe/Andorra 1993-12-23
+3040810 Camà d’ Easagents Cami d' Easagents 42.53333 1.61667 R TRL AD 00 0 2237 Europe/Andorra 1993-12-23
+3040811 Pleta de Duedra Pleta de Duedra 42.63333 1.5 L GRAZ AD 00 0 1979 Europe/Andorra 1993-12-23
+3040812 Pleta de Duedra Pleta de Duedra 42.61667 1.56667 L GRAZ AD 00 0 2228 Europe/Andorra 1993-12-23
+3040813 Plana Duedra Plana Duedra 42.58333 1.51667 T UPLD AD 00 0 1722 Europe/Andorra 1993-12-23
+3040814 Planella del Duc Planella del Duc 42.45 1.5 T SLP AD 00 0 1614 Europe/Andorra 1993-12-23
+3040815 Canal del Duc Canal del Duc 42.58333 1.61667 H RVN AD 00 0 1707 Europe/Andorra 1993-12-23
+3040816 Canal Dreta Canal Dreta 42.55 1.53333 H STM AD 00 0 1593 Europe/Andorra 1993-12-23
+3040817 Canal Dreta Canal Dreta 42.51667 1.48333 H STM AD 00 0 1839 Europe/Andorra 1993-12-23
+3040818 Port Dret Port Dret 42.57454 1.70316 T PASS AD 00 0 2375 Europe/Andorra 2011-04-19
+3040819 Mas del Diumenge Mas del Diumenge 42.51667 1.53333 S FRM AD 00 0 1460 Europe/Andorra 1993-12-23
+3040820 Canal del Diumenge Canal del Diumenge 42.51667 1.53333 H STM AD 00 0 1460 Europe/Andorra 1993-12-23
+3040821 Clot del Diable Clot del Diable 42.56667 1.7 T CRQ AD 00 0 2375 Europe/Andorra 1993-12-23
+3040822 Devesassa Devesassa 42.56667 1.6 L LCTY AD 00 0 1655 Europe/Andorra 1993-12-23
+3040823 Costa de la Devesa Costa de la Devesa 42.55 1.45 T SLP AD 00 0 1788 Europe/Andorra 1993-12-23
+3040824 Bosc de la Devesa Bosc de la Devesa 42.5 1.55 V FRST AD 00 0 1566 Europe/Andorra 1993-12-23
+3040825 Bony de les Deu Hores Bony de les Deu Hores 42.53333 1.65 T SPUR AD 00 0 2508 Europe/Andorra 1993-12-23
+3040826 Pleta de Dalt Pleta de Dalt 42.48333 1.43333 L GRAZ AD 00 0 1938 Europe/Andorra 1993-12-23
+3040827 Carrera de Dalt Carrera de Dalt 42.55 1.61667 R TRL AD 00 0 2206 Europe/Andorra 1993-12-23
+3040828 Serra del Cussol Serra del Cussol 42.45 1.45 T RDGE AD 00 0 1482 Europe/Andorra 1993-12-23
+3040829 Bosc del Cussol Bosc del Cussol 42.45 1.45 V FRST AD 00 0 1482 Europe/Andorra 1993-12-23
+3040830 Borda de la Cultiassa Borda de la Cultiassa 42.53333 1.58333 S HUT AD 00 0 1571 Europe/Andorra 1993-12-23
+3040831 Obaga del Cultiar Obaga del Cultiar 42.55 1.6 T SLP AD 00 0 2210 Europe/Andorra 1993-12-23
+3040832 Cultiar Cultiar 42.55 1.58333 L LCTY AD 00 0 1499 Europe/Andorra 1993-12-23
+3040833 Canal del Cul Canal del Cul 42.48333 1.43333 H STM AD 00 0 1938 Europe/Andorra 1993-12-23
+3040834 Serrat dels Cuiners Serrat dels Cuiners 42.63333 1.55 T SPUR AD 00 0 2053 Europe/Andorra 1993-12-23
+3040835 Roc dels Cuiners Roc dels Cuiners 42.63333 1.55 T RK AD 00 0 2053 Europe/Andorra 1993-12-23
+3040836 Canal del Cuinal Canal del Cuinal 42.45 1.48333 H STM AD 00 0 1111 Europe/Andorra 1993-12-23
+3040837 Bosc del Cúbol Bosc del Cubol 42.6 1.7 V FRST AD 00 0 2354 Europe/Andorra 1993-12-23
+3040838 Costa del Cubil d’Erts Costa del Cubil d'Erts 42.58333 1.48333 T SLP AD 00 0 1809 Europe/Andorra 1993-12-23
+3040839 Bony del Cubil d’Erts Bony del Cubil d'Erts 42.58333 1.48333 T PK AD 00 0 1809 Europe/Andorra 1993-12-23
+3040840 Solana del Cubil Solana del Cubil 42.56667 1.46667 T SLP AD 00 0 1673 Europe/Andorra 1993-12-23
+3040841 Serrat del Cubil Serrat del Cubil 42.55 1.66667 T RDGE AD 00 0 2224 Europe/Andorra 1993-12-23
+3040842 Riu del Cubil Riu del Cubil 42.56667 1.46667 H STM AD 00 0 1673 Europe/Andorra 1993-12-23
+3040843 Riu del Cubil Riu del Cubil 42.55568 1.68579 H STM AD 00 0 2083 Europe/Andorra 2011-04-19
+3040844 Pla del Cubil Pla del Cubil 42.53333 1.66667 T UPLD AD 00 0 2489 Europe/Andorra 1993-12-23
+3040845 Pic del Cubil Pic del Cubil Pic del Cubil 42.53333 1.45 T PK AD 00 0 2130 Europe/Andorra 2011-11-05
+3040846 Pic Baix del Cubil Pic Baix del Cubil 42.53333 1.68333 T PK AD 00 0 2322 Europe/Andorra 1993-12-23
+3040847 Pic Alt del Cubil Pic Alt del Cubil Pic Alt del Cubil,Pic de Cuvil,Pic de Suvil 42.52808 1.66868 T PK AD 00 0 2489 Europe/Andorra 2011-11-05
+3040848 Obaga del Cubil Obaga del Cubil 42.56667 1.46667 T SLP AD 00 0 1673 Europe/Andorra 1993-12-23
+3040849 Llac del Cubil Llac del Cubil 42.53647 1.66891 H LK AD 00 0 2335 Europe/Andorra 2011-04-19
+3040850 Port de Caraussans Port de Caraussans Port de Caraussans,Port de Creussans 42.63333 1.46667 T PASS AD 00 0 2324 Europe/Andorra 2011-11-05
+3040851 Estany de Creussans Estany de Creussans 42.63484 1.47697 H LK AD 07 0 2291 Europe/Andorra 2007-03-04
+3040852 Creussans Creussans 42.63355 1.47785 L LCTY AD 07 0 2291 Europe/Andorra 2007-03-04
+3040853 Planell de la Creueta Planell de la Creueta 42.55 1.55 T UPLD AD 00 0 2097 Europe/Andorra 1993-12-23
+3040854 Creu de Noral Creu de Noral 42.56667 1.55 L LCTY AD 00 0 1996 Europe/Andorra 1993-12-23
+3040855 Serra de la Creu Serra de la Creu 42.48333 1.51667 T MT AD 00 0 2061 Europe/Andorra 1993-12-23
+3040856 Roc de la Creu Roc de la Creu 42.56667 1.48333 T RK AD 00 0 1508 Europe/Andorra 1993-12-23
+3040857 Borda del Cresper Borda del Cresper 42.53333 1.56667 S HUT AD 00 0 1418 Europe/Andorra 1993-12-23
+3040858 Rocs del Cresp Rocs del Cresp 42.58333 1.51667 T RKS AD 00 0 1722 Europe/Andorra 1993-12-23
+3040859 Roc del Cresp Roc del Cresp 42.56667 1.48333 T SPUR AD 00 0 1508 Europe/Andorra 1993-12-23
+3040860 Canal del Cresp Canal del Cresp 42.58333 1.51667 H STM AD 00 0 1722 Europe/Andorra 1993-12-23
+3040861 Font del Crau Font del Crau 42.6 1.51667 H SPNG AD 00 0 1445 Europe/Andorra 1993-12-23
+3040862 Pla de la Cot Pla de la Cot 42.53333 1.46667 T UPLD AD 00 0 1846 Europe/Andorra 1993-12-23
+3040863 Canal de les Costes Canal de les Costes 42.51667 1.53333 H STM AD 00 0 1460 Europe/Andorra 1993-12-23
+3040864 Canal de Costa Verda Canal de Costa Verda 42.5 1.56667 H STM AD 00 0 1776 Europe/Andorra 1993-12-23
+3040865 Collet de Costasseda Collet de Costasseda 42.48333 1.5 T PASS AD 00 0 1631 Europe/Andorra 1993-12-23
+3040866 Bosc de la Costassa Bosc de la Costassa 42.55 1.51667 V FRST AD 00 0 1397 Europe/Andorra 1993-12-23
+3040867 Barranc de la Costa Rodona Barranc de la Costa Rodona 42.56667 1.73333 H STM AD 00 0 2096 Europe/Andorra 1993-12-23
+3040868 Font de la Costa Gran Font de la Costa Gran 42.51667 1.48333 H SPNG AD 00 0 1839 Europe/Andorra 1993-12-23
+3040869 Bony de la Costa del Sodorn Bony de la Costa del Sodorn 42.5 1.45 T PK AD 00 0 1840 Europe/Andorra 1993-12-23
+3040870 Canal de la Costa de les Salineres Canal de la Costa de les Salineres 42.5 1.46667 H STM AD 00 0 1678 Europe/Andorra 1993-12-23
+3040871 Costa de les Neres Costa de les Neres 42.55 1.55 A ADMD AD 00 0 2097 Europe/Andorra 1993-12-23
+3040872 Canal de la Costa de les Gerderes Canal de la Costa de les Gerderes 42.55 1.6 H RVN AD 00 0 2210 Europe/Andorra 1993-12-23
+3040873 Collet de la Costa del Bony Roig Collet de la Costa del Bony Roig 42.6 1.61667 T PASS AD 00 0 2271 Europe/Andorra 1993-12-23
+3040874 Ras de la Costa de l’Avier Ras de la Costa de l'Avier 42.58333 1.5 T SLP AD 00 0 1595 Europe/Andorra 1993-12-23
+3040875 Font de la Costa de l’Avier Font de la Costa de l'Avier 42.56667 1.53333 H SPNG AD 00 0 1669 Europe/Andorra 1993-12-23
+3040876 Canal de Costa de l’Avier Canal de Costa de l'Avier 42.58333 1.48333 H STM AD 00 0 1809 Europe/Andorra 1993-12-23
+3040877 Roc de la Costa Roc de la Costa 42.56667 1.48333 T RK AD 00 0 1508 Europe/Andorra 1993-12-23
+3040878 Solana del Cosp Solana del Cosp 42.56667 1.61667 T SLP AD 00 0 1920 Europe/Andorra 1993-12-23
+3040879 Roca Cosconera Roca Cosconera 42.48333 1.56667 T RK AD 00 0 2231 Europe/Andorra 1993-12-23
+3040880 Font de la Coruvilla Font de la Coruvilla 42.58333 1.46667 H SPNG AD 00 0 1643 Europe/Andorra 1993-12-23
+3040881 Canals de la Coruvilla Canals de la Coruvilla 42.58333 1.46667 H RVN AD 00 0 1643 Europe/Andorra 1993-12-23
+3040882 Borda de la Coruvilla Borda de la Coruvilla 42.58333 1.46667 S FRM AD 00 0 1643 Europe/Andorra 1993-12-23
+3040883 Corts d’Ern Corts d'Ern Corts d'Aern,Corts d'Ern,Corts d’Aern,Corts d’Ern 42.5 1.48333 L LCTY AD 00 0 1316 Europe/Andorra 2011-11-05
+3040884 Bosc de les Corts Bosc de les Corts 42.56667 1.53333 V FRST AD 00 0 1669 Europe/Andorra 1993-12-23
+3040885 Cort d’Esteve Cort d'Esteve 42.6 1.51667 L LCTY AD 00 0 1445 Europe/Andorra 1993-12-23
+3040886 Cort de Rossell Cort de Rossell 42.46667 1.48333 L LCTY AD 00 0 1134 Europe/Andorra 1993-12-23
+3040887 Cort Cremada Cort Cremada 42.56667 1.53333 L LCTY AD 00 0 1669 Europe/Andorra 1993-12-23
+3040888 Bosc de les Cortanbelles Bosc de les Cortanbelles 42.46667 1.45 V FRST AD 00 0 1562 Europe/Andorra 1993-12-23
+3040889 Canal del Cortal Vell Canal del Cortal Vell 42.58333 1.46667 H STM AD 00 0 1643 Europe/Andorra 1993-12-23
+3040890 Cortal Vell Cortal Vell 42.58333 1.46667 L LCTY AD 00 0 1643 Europe/Andorra 1993-12-23
+3040891 Cortals de Sispony Cortals de Sispony Corfots de Sispony,Cortals de Sispony 42.53333 1.5 L LCTY AD AD 00 0 1357 Europe/Andorra 2011-11-05
+3040892 Cortals de Fontaneda Cortals de Fontaneda 42.45 1.46667 L LCTY AD 00 0 935 Europe/Andorra 1993-12-23
+3040893 Riu dels Cortals Riu dels Cortals 42.53333 1.58333 H STM AD 00 0 1571 Europe/Andorra 1993-12-23
+3040894 Riu dels Cortals Riu dels Cortals 42.53333 1.51667 H STM AD 00 0 1361 Europe/Andorra 1993-12-23
+3040895 Carretera dels Cortals Carretera dels Cortals 42.53333 1.58333 R RD AD 00 0 1571 Europe/Andorra 1993-12-23
+3040896 Camà dels Cortals Cami dels Cortals 42.53333 1.53333 R TRL AD 00 0 1521 Europe/Andorra 1993-12-23
+3040897 Canal del Cortalet Canal del Cortalet 42.48333 1.48333 H STM AD 00 0 981 Europe/Andorra 1993-12-23
+3040898 Camà del Cortal de la Serra Cami del Cortal de la Serra 42.53333 1.5 R TRL AD 00 0 1357 Europe/Andorra 1993-12-23
+3040899 Mas del Cortal Mas del Cortal 42.56667 1.6 S FRM AD 00 0 1655 Europe/Andorra 1993-12-23
+3040900 Canal del Cortà Canal del Corta 42.5 1.48333 H STM AD 00 0 1316 Europe/Andorra 1993-12-23
+3040901 Canal de la Corruga Canal de la Corruga 42.58333 1.63333 H RVN AD 00 0 1722 Europe/Andorra 1993-12-23
+3040902 Bosc de la Corruga Bosc de la Corruga 42.56667 1.65 V FRST AD 00 0 1988 Europe/Andorra 1993-12-23
+3040903 Font del Correus Font del Correus 42.56667 1.71667 H SPNG AD 00 0 2219 Europe/Andorra 1993-12-23
+3040904 Corrals de la Mentirosa Corrals de la Mentirosa 42.43333 1.51667 S RUIN AD 00 0 2031 Europe/Andorra 1993-12-23
+3040905 Serra dels Corrals Serra dels Corrals 42.55 1.45 T MT AD 00 0 1788 Europe/Andorra 1993-12-23
+3040906 Serrat de Corpalanca Serrat de Corpalanca 42.53333 1.46667 T RDGE AD 00 0 1846 Europe/Andorra 1993-12-23
+3040907 Canal de Cordabalba Canal de Cordabalba 42.48333 1.55 H STM AD 00 0 2233 Europe/Andorra 1993-12-23
+3040908 Roc dels Corbs Roc dels Corbs 42.5 1.51667 T RK AD 00 0 1410 Europe/Andorra 1993-12-23
+3040909 Torrent de les Corbelles Torrent de les Corbelles 42.55 1.6 H STM AD 00 0 2210 Europe/Andorra 1993-12-23
+3040910 Roca Corba Roca Corba 42.51667 1.53333 T RK AD 00 0 1460 Europe/Andorra 1993-12-23
+3040911 Font del Corb Font del Corb 42.55 1.46667 H SPNG AD 00 0 1585 Europe/Andorra 1993-12-23
+3040912 Canal del Corb Canal del Corb 42.55 1.5 H STM AD 00 0 1292 Europe/Andorra 1993-12-23
+3040913 Canal del Corb Canal del Corb 42.53333 1.56667 H STM AD 00 0 1418 Europe/Andorra 1993-12-23
+3040914 Camà del Corb Cami del Corb 42.63333 1.51667 R TRL AD 00 0 1894 Europe/Andorra 1993-12-23
+3040915 Basers del Corb Basers del Corb 42.63333 1.51667 T CLF AD 00 0 1894 Europe/Andorra 1993-12-23
+3040916 Serrat del Corantell Serrat del Corantell 42.53333 1.5 T RDGE AD 00 0 1357 Europe/Andorra 1993-12-23
+3040917 Roc de la Copa Roc de la Copa 42.5 1.46667 T RK AD 00 0 1678 Europe/Andorra 1993-12-23
+3040918 Font de Conxa Font de Conxa 42.6 1.65 H SPNG AD 00 0 2131 Europe/Andorra 1993-12-23
+3040919 Bosc de Conxa Bosc de Conxa 42.6 1.65 V FRST AD 00 0 2131 Europe/Andorra 1993-12-23
+3040920 Solana del Contador Solana del Contador 42.48333 1.43333 T SLP AD 00 0 1938 Europe/Andorra 1993-12-23
+3040921 Font del Coniol Font del Coniol 42.5 1.58333 H SPNG AD 00 0 1888 Europe/Andorra 1993-12-23
+3040922 Costa del Congost Costa del Congost 42.6 1.46667 T SLP AD 00 0 2421 Europe/Andorra 1993-12-23
+3040923 Conangle Conangle 42.43333 1.51667 L LCTY AD 00 0 2031 Europe/Andorra 1993-12-23
+3040924 Cóms de Jan Coms de Jan 42.63333 1.61667 L LCTY AD 00 0 2541 Europe/Andorra 1993-12-23
+3040925 Roc dels Cóms Roc dels Coms 42.63333 1.63333 T CLF AD 00 0 2603 Europe/Andorra 1993-12-23
+3040926 Planells dels Cóms Planells dels Coms 42.55 1.6 T UPLD AD 00 0 2210 Europe/Andorra 1993-12-23
+3040927 Obaga dels Cóms Obaga dels Coms 42.48333 1.41667 T SLP AD 00 0 1920 Europe/Andorra 1993-12-23
+3040928 Font dels Cóms Font dels Coms 42.45 1.45 H SPNG AD 00 0 1482 Europe/Andorra 1993-12-23
+3040929 Canal dels Cóms Canal dels Coms 42.48333 1.41667 H STM AD 00 0 1920 Europe/Andorra 1993-12-23
+3040930 Bosc dels Cóms Bosc dels Coms 42.53333 1.46667 V FRST AD 00 0 1846 Europe/Andorra 1993-12-23
+3040931 Riu del ComÃs Vell Riu del Comis Vell 42.63667 1.52189 H STM AD 07 0 2334 Europe/Andorra 2007-03-04
+3040932 ComÃs Vell Comis Vell 42.63748 1.52098 L LCTY AD 07 0 2334 Europe/Andorra 2007-03-04
+3040933 Borda del Comet Borda del Comet 42.56667 1.58333 S HUT AD 00 0 1919 Europe/Andorra 1993-12-23
+3040934 Comes de Banyàs Comes de Banyas 42.55 1.51667 L LCTY AD 00 0 1397 Europe/Andorra 1993-12-23
+3040935 Bosc de Comes Beçoses Bosc de Comes Becoses 42.51667 1.58333 V FRST AD 00 0 1994 Europe/Andorra 1993-12-23
+3040936 Solà de les Comes Sola de les Comes 42.58333 1.5 T SLP AD 00 0 1595 Europe/Andorra 1993-12-23
+3040937 Portell de les Comes Portell de les Comes 42.5 1.46667 T PASS AD 00 0 1678 Europe/Andorra 1993-12-23
+3040938 Canals de les Comes Canals de les Comes 42.56667 1.51667 H RVN AD 00 0 1500 Europe/Andorra 1993-12-23
+3040939 Borda de les Comes Borda de les Comes 42.53333 1.58333 S FRM AD 00 0 1571 Europe/Andorra 1993-12-23
+3040940 Bosc dels Comellassos Bosc dels Comellassos 42.6 1.66667 V FRST AD 00 0 1858 Europe/Andorra 1993-12-23
+3040941 Costa del Comellar Llarg Costa del Comellar Llarg 42.56667 1.61667 T SLP AD 00 0 1920 Europe/Andorra 1993-12-23
+3040942 Camà del Comellar Llarg Cami del Comellar Llarg 42.56667 1.61667 R TRL AD 00 0 1920 Europe/Andorra 1993-12-23
+3040943 Clot de la Comellada Clot de la Comellada 42.53333 1.45 H RVN AD 00 0 2130 Europe/Andorra 1993-12-23
+3040944 Riu de la Comella Riu de la Comella 42.5 1.53333 H STM AD 00 0 1574 Europe/Andorra 1993-12-23
+3040945 Carretera de la Comella Carretera de la Comella 42.51667 1.55 R RD AD 00 0 1322 Europe/Andorra 1993-12-23
+3040946 Bony de Comascura Bony de Comascura 42.5 1.55 T SPUR AD 00 0 1566 Europe/Andorra 1993-12-23
+3040947 Canal de Coma Sansa Canal de Coma Sansa 42.48333 1.46667 H STM AD 00 0 1148 Europe/Andorra 1993-12-23
+3040948 Riu de la Comarqueta d’Incles Riu de la Comarqueta d'Incles 42.6 1.61667 H STM AD 00 0 2271 Europe/Andorra 1993-12-23
+3040949 Collet de la Comarqueta d’Incles Collet de la Comarqueta d'Incles 42.6 1.61667 T PASS AD 00 0 2271 Europe/Andorra 1993-12-23
+3040950 Comarqueta d’Incles Comarqueta d'Incles 42.6 1.61667 L LCTY AD 00 0 2271 Europe/Andorra 1993-12-23
+3040951 Tosa de la Comarqueta Tosa de la Comarqueta 42.56667 1.73333 T UPLD AD 00 0 2096 Europe/Andorra 1993-12-23
+3040952 Font de la Comarqueta Font de la Comarqueta 42.56667 1.71667 H SPNG AD 00 0 2219 Europe/Andorra 1993-12-23
+3040953 Basers de la Comarqueta Basers de la Comarqueta 42.58333 1.71667 T CLF AD 00 0 2553 Europe/Andorra 1993-12-23
+3040954 Riu de la Comarca de les Fonts Riu de la Comarca de les Fonts 42.6 1.61667 H STM AD 00 0 2271 Europe/Andorra 1993-12-23
+3040955 Obaga de la Comarca Obaga de la Comarca 42.56667 1.46667 T SLP AD 00 0 1673 Europe/Andorra 1993-12-23
+3040956 Font de la Comarca Font de la Comarca 42.56667 1.45 H SPNG AD 00 0 2137 Europe/Andorra 1993-12-23
+3040957 Riu de Coma Pedrosa Riu de Coma Pedrosa 42.58333 1.46667 H STM AD 00 0 1643 Europe/Andorra 1993-12-23
+3040958 Pleta de Coma Pedrosa Pleta de Coma Pedrosa 42.58333 1.45 L GRAZ AD 00 0 2156 Europe/Andorra 1993-12-23
+3040959 Pic de Coma Pedrosa Pic de Coma Pedrosa Pic Alt de la Coma Pedrosa,Pic Alt de la Pedrosa,Pic de Coma Pedrosa 42.5917 1.44428 T PK AD 00 0 2406 Europe/Andorra 2011-11-05
+3040960 Obaga de Coma Pedrosa Obaga de Coma Pedrosa 42.58387 1.44182 T SLP AD 00 0 2350 Europe/Andorra 2011-04-19
+3040961 Grau de Coma Pedrosa Grau de Coma Pedrosa 42.58333 1.46667 T SLP AD 00 0 1643 Europe/Andorra 1993-12-23
+3040962 Collet de Coma Pedrosa Collet de Coma Pedrosa 42.58333 1.45 T PK AD 00 0 2156 Europe/Andorra 1993-12-23
+3040963 Camà de Coma Pedrosa Cami de Coma Pedrosa 42.58333 1.48333 R TRL AD 00 0 1809 Europe/Andorra 1993-12-23
+3040964 Coma Pedrosa Coma Pedrosa Coma Pedrosa 42.58333 1.43333 A ADMD AD 00 0 2412 Europe/Andorra 2011-11-05
+3040965 Serra de Coma Obaga i Ferreroles Serra de Coma Obaga i Ferreroles 42.61667 1.56667 T RDGE AD 00 0 2228 Europe/Andorra 1993-12-23
+3040966 Solana de Coma Obaga Solana de Coma Obaga 42.61667 1.55 T SLP AD 00 0 2007 Europe/Andorra 1993-12-23
+3040967 Serra de Coma Obaga Serra de Coma Obaga 42.61667 1.56667 T RDGE AD 00 0 2228 Europe/Andorra 1993-12-23
+3040968 Pala de Coma Obaga Pala de Coma Obaga 42.61667 1.56667 T SLP AD 00 0 2228 Europe/Andorra 1993-12-23
+3040969 Coma Obaga Coma Obaga 42.6 1.55 A ADMD AD 00 0 2298 Europe/Andorra 1993-12-23
+3040970 Comangerra Comangerra 42.56667 1.5 T SPUR AD 00 0 1636 Europe/Andorra 1993-12-23
+3040971 Canal de Coma Llonga Canal de Coma Llonga 42.56667 1.6 H STM AD 00 0 1655 Europe/Andorra 1993-12-23
+3040972 Riu de Comallempla Riu de Comallempla 42.56667 1.48333 H STM AD 00 0 1508 Europe/Andorra 1993-12-23
+3040973 Portella de Comallempla Portella de Comallempla 42.56667 1.45 T PASS AD 00 0 2137 Europe/Andorra 1993-12-23
+3040974 Camà de Comallempla Cami de Comallempla 42.56667 1.48333 R TRL AD 00 0 1508 Europe/Andorra 1993-12-23
+3040975 Bordes de Comallempla Bordes de Comallempla 42.56667 1.46667 S HUTS AD 00 0 1673 Europe/Andorra 1993-12-23
+3040976 Comallempla Comallempla 42.56667 1.46667 A ADMD AD 00 0 1673 Europe/Andorra 1993-12-23
+3040977 Canal de Coma Fregona Canal de Coma Fregona 42.58333 1.51667 H STM AD 00 0 1722 Europe/Andorra 1993-12-23
+3040978 Canal de Coma Fregona Canal de Coma Fregona 42.56667 1.51667 H STM AD 00 0 1500 Europe/Andorra 1993-12-23
+3040979 Coma Estreta Coma Estreta 42.58333 1.55 L LCTY AD 00 0 2357 Europe/Andorra 1993-12-23
+3040980 Coma Estremera Coma Estremera 42.51667 1.68333 A ADMD AD 00 0 2352 Europe/Andorra 1993-12-23
+3040981 Col de la Portaneille Col de la Portaneille Col de la Portaneille,Portella de la Coma de Varilles 42.61667 1.65 T PASS AD 00 0 2567 Europe/Andorra 2011-11-05
+3040982 Pics de la Portaneille Pics de la Portaneille Passada,Pic de la Coma de Varilles,Pic de la Passada,Picos de la Passade,Pics de la Passade,Pics de la Portaneille 42.61667 1.66667 T PKS AD 00 0 2536 Europe/Andorra 2011-11-05
+3040983 Rocs de Coma de Teix Rocs de Coma de Teix 42.46667 1.46667 T RKS AD 00 0 1340 Europe/Andorra 1993-12-23
+3040984 Coma de Ransol Coma de Ransol 42.6 1.63333 A ADMD AD 00 0 1893 Europe/Andorra 1993-12-23
+3040985 Solana de la Coma dels Llops Solana de la Coma dels Llops 42.51667 1.63333 T SLP AD 00 0 2379 Europe/Andorra 1993-12-23
+3040986 Riu de la Coma dels Llops Riu de la Coma dels Llops 42.52722 1.60965 H STM AD 00 0 2101 Europe/Andorra 2011-04-19
+3040987 Pleta de la Coma dels Llops Pleta de la Coma dels Llops 42.51667 1.61667 L GRAZ AD 00 0 2254 Europe/Andorra 1993-12-23
+3040988 Cap de la Coma dels Llops Cap de la Coma dels Llops 42.50769 1.62525 T RDGE AD 00 0 2666 Europe/Andorra 2011-04-19
+3040989 Bosc de la Coma dels Llops Bosc de la Coma dels Llops 42.51667 1.61667 V FRST AD 00 0 2254 Europe/Andorra 1993-12-23
+3040990 Coma dels Llops Coma dels Llops 42.51667 1.61667 A ADMD AD 00 0 2254 Europe/Andorra 1993-12-23
+3040991 Clot de la Coma del Prat Clot de la Coma del Prat 42.51667 1.46667 H RVN AD 00 0 1840 Europe/Andorra 1993-12-23
+3040992 Clot de la Coma del Pou Clot de la Coma del Pou 42.51667 1.48333 H RVN AD 00 0 1839 Europe/Andorra 1993-12-23
+3040993 Riu de la Coma del Mig Riu de la Coma del Mig 42.63333 1.51667 H STM AD 00 0 1894 Europe/Andorra 1993-12-23
+3040994 Riu de la Coma del Forat Riu de la Coma del Forat 42.63333 1.5 H STM AD 00 0 1979 Europe/Andorra 1993-12-23
+3040995 Costa de la Coma del Forat Costa de la Coma del Forat 42.63333 1.48333 T SLP AD 00 0 2283 Europe/Andorra 1993-12-23
+3040996 Coma del Favar Coma del Favar 42.51667 1.58333 L LCTY AD 00 0 1994 Europe/Andorra 1993-12-23
+3040997 Clot de la Coma de la Sella Clot de la Coma de la Sella 42.51667 1.48333 H RVN AD 00 0 1839 Europe/Andorra 1993-12-23
+3040998 Solà de la Coma de Cardes Sola de la Coma de Cardes 42.58333 1.61667 T SLP AD 00 0 1707 Europe/Andorra 1993-12-23
+3040999 Tosa de Coma Bella Tosa de Coma Bella 42.58333 1.68333 T UPLD AD 00 0 2294 Europe/Andorra 1993-12-23
+3041000 Font de Coma Bella Font de Coma Bella 42.45 1.5 H SPNG AD 00 0 1614 Europe/Andorra 1993-12-23
+3041001 Canal de Coma Bella Canal de Coma Bella 42.45 1.48333 H STM AD 00 0 1111 Europe/Andorra 1993-12-23
+3041002 Coma Bella Coma Bella 42.45 1.5 L LCTY AD 00 0 1614 Europe/Andorra 1993-12-23
+3041003 Planell de Coma Aubosa Planell de Coma Aubosa 42.58333 1.5 T UPLD AD 00 0 1595 Europe/Andorra 1993-12-23
+3041004 Clot de Coma Aubosa Clot de Coma Aubosa 42.58333 1.48333 H RVN AD 00 0 1809 Europe/Andorra 1993-12-23
+3041005 Roc de la Coma Roc de la Coma 42.51667 1.55 T RK AD 00 0 1322 Europe/Andorra 1993-12-23
+3041006 Riu de la Coma Riu de la Coma 42.58333 1.63333 H STM AD 00 0 1722 Europe/Andorra 1993-12-23
+3041007 Riu de la Coma Riu de la Coma 42.45 1.46667 H STM AD 00 0 935 Europe/Andorra 1993-12-23
+3041008 Prats de Coma Prats de Coma 42.56667 1.46667 L GRAZ AD 00 0 1673 Europe/Andorra 1993-12-23
+3041009 Pont de la Coma Pont de la Coma 42.55 1.46667 S BDG AD 00 0 1585 Europe/Andorra 1993-12-23
+3041010 Collet de la Coma Collet de la Coma 42.65 1.51667 T PASS AD 00 0 2546 Europe/Andorra 1993-12-23
+3041011 Collada de la Coma Collada de la Coma 42.6 1.61667 T PASS AD 00 0 2271 Europe/Andorra 1993-12-23
+3041012 Canal de la Coma Canal de la Coma 42.61667 1.55 H STM AD 00 0 2007 Europe/Andorra 1993-12-23
+3041013 Canal de la Coma Canal de la Coma 42.55 1.55 H STM AD 00 0 2097 Europe/Andorra 1993-12-23
+3041014 Canal de la Coma Canal de la Coma 42.6 1.51667 H RVN AD 00 0 1445 Europe/Andorra 1993-12-23
+3041015 Bosc de Coma Bosc de Coma 42.53333 1.55 V FRST AD 00 0 1344 Europe/Andorra 1993-12-23
+3041016 Bony de la Coma Bony de la Coma 42.55 1.53333 T SPUR AD 00 0 1593 Europe/Andorra 1993-12-23
+3041017 Rocs del Colomer Rocs del Colomer 42.53333 1.51667 T SPUR AD 00 0 1361 Europe/Andorra 1993-12-23
+3041018 Collet dels Colls Collet dels Colls 42.55 1.51667 T PASS AD 00 0 1397 Europe/Andorra 1993-12-23
+3041019 Solana de Coll Pa Solana de Coll Pa 42.55 1.43333 T SLP AD 00 0 1949 Europe/Andorra 1993-12-23
+3041020 Serrat de Coll Pa Serrat de Coll Pa 42.55 1.43333 T RDGE AD 00 0 1949 Europe/Andorra 1993-12-23
+3041021 Planell de Coll Pa Planell de Coll Pa 42.48333 1.56667 T UPLD AD 00 0 2231 Europe/Andorra 1993-12-23
+3041022 Pic de Coll Pa Pic de Coll Pa 42.51667 1.48333 T PK AD 00 0 1839 Europe/Andorra 1993-12-23
+3041023 Bosc de Coll Pa Bosc de Coll Pa 42.48333 1.55 V FRST AD 00 0 2233 Europe/Andorra 1993-12-23
+3041024 Basers de Coll Pa Basers de Coll Pa 42.48333 1.56667 T CLF AD 00 0 2231 Europe/Andorra 1993-12-23
+3041025 Canal de Coll Jovell Canal de Coll Jovell 42.5 1.56667 H STM AD 00 0 1776 Europe/Andorra 1993-12-23
+3041026 Canal de Collet Purgat Canal de Collet Purgat 42.46667 1.48333 H STM AD 00 0 1134 Europe/Andorra 1993-12-23
+3041027 Clot del Collet de Font Podrida Clot del Collet de Font Podrida 42.58333 1.46667 T SLP AD 00 0 1643 Europe/Andorra 1993-12-23
+3041028 Camà dels Collells Cami dels Collells 42.56667 1.46667 R TRL AD 00 0 1673 Europe/Andorra 1993-12-23
+3041029 Carretera del Coll d’Ordino Carretera del Coll d'Ordino 42.55 1.53333 R RD AD 00 0 1593 Europe/Andorra 1993-12-23
+3041030 Camà del Coll d’Ordino Cami del Coll d'Ordino 42.55 1.56667 R TRL AD 00 0 1828 Europe/Andorra 1993-12-23
+3041031 Font del Coll de Vista Font del Coll de Vista 42.48333 1.45 H SPNG AD 00 0 1195 Europe/Andorra 1993-12-23
+3041032 Canal del Coll de Vista Canal del Coll de Vista 42.48333 1.45 H STM AD 00 0 1195 Europe/Andorra 1993-12-23
+3041033 Canal del Coll de Turer Canal del Coll de Turer 42.56667 1.46667 H STM AD 00 0 1673 Europe/Andorra 1993-12-23
+3041034 Camà de Coll de Turer Cami de Coll de Turer 42.56667 1.46667 R TRL AD 00 0 1673 Europe/Andorra 1993-12-23
+3041035 Canal de Coll d’Eres Canal de Coll d'Eres 42.5 1.51667 H STM AD 00 0 1410 Europe/Andorra 1993-12-23
+3041036 Camà del Coll dels Isards Cami del Coll dels Isards 42.51667 1.73333 R TRL AD 00 0 2484 Europe/Andorra 1993-12-23
+3041037 Canal del Coll de l’Obac Canal del Coll de l'Obac 42.48333 1.48333 H STM AD 00 0 981 Europe/Andorra 1993-12-23
+3041038 Canal del Coll de les Cases Canal del Coll de les Cases 42.56667 1.5 H STM AD 00 0 1636 Europe/Andorra 1993-12-23
+3041039 Bony del Coll de l’Era Bony del Coll de l'Era 42.48333 1.45 T SPUR AD 00 0 1195 Europe/Andorra 1993-12-23
+3041040 Riu del Coll de l’Aquell Riu del Coll de l'Aquell 42.48333 1.43333 H STM AD 00 0 1938 Europe/Andorra 1993-12-23
+3041041 Canal del Coll de l’Acaumader Canal del Coll de l'Acaumader 42.48333 1.46667 H STM AD 00 0 1148 Europe/Andorra 1993-12-23
+3041042 Canal del Coll de la Cauba Canal del Coll de la Cauba 42.58333 1.61667 H STM AD 00 0 1707 Europe/Andorra 1993-12-23
+3041043 Canal del Coll de la Basera Canal del Coll de la Basera 42.58333 1.65 H RVN AD 00 0 1767 Europe/Andorra 1993-12-23
+3041044 Camà del Coll d’Arenes Cami del Coll d'Arenes 42.6 1.58333 R TRL AD 00 0 2461 Europe/Andorra 1993-12-23
+3041045 Pala de Coll Carnisser Pala de Coll Carnisser 42.6 1.46667 T SLP AD 00 0 2421 Europe/Andorra 1993-12-23
+3041046 Collada de Coll Carnisser Collada de Coll Carnisser 42.6 1.48333 T PASS AD 00 0 2441 Europe/Andorra 1993-12-23
+3041047 Prats de Collart Prats de Collart 42.58333 1.65 L GRAZ AD 00 0 1767 Europe/Andorra 1993-12-23
+3041048 Canal de Collart Canal de Collart 42.58333 1.65 H STM AD 00 0 1767 Europe/Andorra 1993-12-23
+3041049 Bosc de Collart Bosc de Collart 42.56667 1.66667 V FRST AD 00 0 1938 Europe/Andorra 1993-12-23
+3041050 La Colladeta La Colladeta 42.55 1.55 T PASS AD 00 0 2097 Europe/Andorra 1993-12-23
+3041051 Bony de les Collades Bony de les Collades 42.55 1.51667 T MT AD 00 0 1397 Europe/Andorra 1993-12-23
+3041052 Canal de la Collada Gran Canal de la Collada Gran 42.5 1.48333 H STM AD 00 0 1316 Europe/Andorra 1993-12-23
+3041053 Camà de la Collada de Sanfons Cami de la Collada de Sanfons 42.58333 1.45 R TRL AD 00 0 2156 Europe/Andorra 1993-12-23
+3041054 Camà de la Collada d’Enradort Cami de la Collada d'Enradort 42.53333 1.61667 R TRL AD 00 0 2237 Europe/Andorra 1993-12-23
+3041055 Camà de la Collada de la Maiana Cami de la Collada de la Maiana 42.48333 1.61667 R TRL AD 00 0 2217 Europe/Andorra 1993-12-23
+3041056 Camà de la Collada de Ferreroles Cami de la Collada de Ferreroles 42.6 1.56667 R TRL AD 00 0 2513 Europe/Andorra 1993-12-23
+3041057 Clots de la Collada Clots de la Collada 42.61667 1.61667 H RVN AD 00 0 2352 Europe/Andorra 1993-12-23
+3041058 Bosc de la Collada Bosc de la Collada 42.51667 1.46667 V FRST AD 00 0 1840 Europe/Andorra 1993-12-23
+3041059 Planell del Colitx Planell del Colitx 42.61667 1.51667 T UPLD AD 00 0 1716 Europe/Andorra 1993-12-23
+3041060 Font de la Colilla Font de la Colilla 42.51667 1.6 H SPNG AD 00 0 2085 Europe/Andorra 1993-12-23
+3041061 Canal de la Colilla Canal de la Colilla 42.48333 1.58333 H STM AD 00 0 2349 Europe/Andorra 1993-12-23
+3041062 Canal de la Colija Canal de la Colija 42.58333 1.65 H STM AD 00 0 1767 Europe/Andorra 1993-12-23
+3041063 Bosc de la Colija Bosc de la Colija 42.58333 1.65 V FRST AD 00 0 1767 Europe/Andorra 1993-12-23
+3041064 Riu dels Colells Riu dels Colells 42.53333 1.7 H STM AD 00 0 2357 Europe/Andorra 1993-12-23
+3041065 Circ dels Colells Circ dels Colells 42.51667 1.7 T CRQ AD 00 0 2435 Europe/Andorra 1993-12-23
+3041066 Bosc dels Colells Bosc dels Colells 42.53333 1.7 V FRST AD 00 0 2357 Europe/Andorra 1993-12-23
+3041067 Cortal del Coix Cortal del Coix 42.55 1.55 S HUTS AD 00 0 2097 Europe/Andorra 1993-12-23
+3041068 Tartera del Coferony Tartera del Coferony 42.5 1.45 T SLP AD 00 0 1840 Europe/Andorra 1993-12-23
+3041069 Coferony Coferony 42.48333 1.45 L LCTY AD 00 0 1195 Europe/Andorra 1993-12-23
+3041070 Canal de les Codolles Canal de les Codolles 42.53333 1.51667 H STM AD 00 0 1361 Europe/Andorra 1993-12-23
+3041071 Serrat de Codinet Serrat de Codinet 42.51667 1.6 T SPUR AD 00 0 2085 Europe/Andorra 1993-12-23
+3041072 Collada del Clot Sord Collada del Clot Sord 42.6 1.65 T PASS AD 00 0 2131 Europe/Andorra 1993-12-23
+3041073 Pala dels Clots d’Entinyac Pala dels Clots d'Entinyac 42.58333 1.68333 T SLP AD 00 0 2294 Europe/Andorra 1993-12-23
+3041074 Tosa dels Clots de Massat Tosa dels Clots de Massat 42.56667 1.7 T UPLD AD 00 0 2375 Europe/Andorra 1993-12-23
+3041075 Pala dels Clots de Massat Pala dels Clots de Massat 42.56667 1.7 T SLP AD 00 0 2375 Europe/Andorra 1993-12-23
+3041076 Bassot dels Clots de Massat Bassot dels Clots de Massat 42.56667 1.7 H LK AD 00 0 2375 Europe/Andorra 1993-12-23
+3041077 Clots de Massat Clots de Massat 42.56667 1.68333 A ADMD AD 00 0 2340 Europe/Andorra 1993-12-23
+3041078 Clots de l’Ós Clots de l'Os 42.58333 1.68333 A ADMD AD 00 0 2294 Europe/Andorra 1993-12-23
+3041079 Font dels Clots de la Llosa Font dels Clots de la Llosa 42.61667 1.61667 H SPNG AD 00 0 2352 Europe/Andorra 1993-12-23
+3041080 Font dels Clots Font dels Clots 42.55 1.71667 H SPNG AD 00 0 2192 Europe/Andorra 1993-12-23
+3041081 Canal del Clot del Mener Canal del Clot del Mener 42.5 1.53333 H STM AD 00 0 1574 Europe/Andorra 1993-12-23
+3041082 Barranc del Clot de les Deveses Barranc del Clot de les Deveses 42.53333 1.51667 H STM AD 00 0 1361 Europe/Andorra 1993-12-23
+3041083 Pic del Clot del Cavall Pic del Clot del Cavall 42.6 1.5 T PK AD 00 0 1923 Europe/Andorra 1993-12-23
+3041084 Barranc del Clot d’Aixades Barranc del Clot d'Aixades 42.56667 1.58333 H STM AD 00 0 1919 Europe/Andorra 1993-12-23
+3041085 Font de la Closa Font de la Closa 42.5 1.56667 H SPNG AD 00 0 1776 Europe/Andorra 1993-12-23
+3041086 Pas de la Clau Pas de la Clau 42.51667 1.61667 T PASS AD 00 0 2254 Europe/Andorra 1993-12-23
+3041087 Riu de Claror i Perafita Riu de Claror i Perafita 42.5 1.55 H STM AD 00 0 1566 Europe/Andorra 1993-12-23
+3041088 Riu de Claror Riu de Claror 42.47897 1.56898 H STM AD 00 0 2231 Europe/Andorra 2011-04-19
+3041089 Pleta de Claror Pleta de Claror 42.48333 1.56667 L GRAZ AD 00 0 2231 Europe/Andorra 1993-12-23
+3041090 Camà de Claror Cami de Claror 42.48333 1.56667 R TRL AD 00 0 2231 Europe/Andorra 1993-12-23
+3041091 Cabana de Claror Cabana de Claror 42.46667 1.56667 S HUT AD 00 0 2365 Europe/Andorra 1993-12-23
+3041092 Claror Claror 42.46667 1.56667 A ADMD AD 00 0 2365 Europe/Andorra 1993-12-23
+3041093 Riu de les Claperes Riu de les Claperes 42.55 1.51667 H STM AD 00 0 1397 Europe/Andorra 1993-12-23
+3041094 Canal de les Claperes Canal de les Claperes 42.55 1.5 H STM AD 00 0 1292 Europe/Andorra 1993-12-23
+3041095 Civòs Civos 42.45 1.48333 L LCTY AD 00 0 1111 Europe/Andorra 1993-12-23
+3041096 Canal de la Cirera Canal de la Cirera 42.5 1.5 H STM AD 00 0 1135 Europe/Andorra 1993-12-23
+3041097 Conreu de Certers Conreu de Certers 42.48333 1.5 V CULT AD 00 0 1631 Europe/Andorra 1993-12-23
+3041098 Certers Certers Certers,Certes,Certés,Sertes 42.47468 1.50575 P PPL AD 06 0 1383 Europe/Andorra 2011-11-05
+3041099 Coll del Cerc Coll del Cerc 42.46667 1.5 T PASS AD 00 0 1383 Europe/Andorra 1993-12-23
+3041100 Cementiri Cementiri 42.56667 1.73333 L LCTY AD 00 0 2096 Europe/Andorra 1993-12-23
+3041101 Costa dell Cell Costa dell Cell 42.48333 1.48333 T SLP AD 00 0 981 Europe/Andorra 1993-12-23
+3041102 Tarteres de la Cebollera Tarteres de la Cebollera 42.63333 1.6 T TAL AD 00 0 2635 Europe/Andorra 1993-12-23
+3041103 Riu de la Cebollera Riu de la Cebollera 42.61667 1.56667 H STM AD 00 0 2228 Europe/Andorra 1993-12-23
+3041104 Portella de la Cebollera Portella de la Cebollera Portella de la Cebollera 42.63333 1.6 T PASS AD 00 0 2635 Europe/Andorra 2011-11-05
+3041105 Pleta de la Cebollera Pleta de la Cebollera 42.63333 1.58333 L GRAZ AD 00 0 2470 Europe/Andorra 1993-12-23
+3041106 Basses de la Cebollera Basses de la Cebollera 42.63333 1.58333 H LKS AD 00 0 2470 Europe/Andorra 1993-12-23
+3041107 Aspres de la Cebollera Aspres de la Cebollera 42.63333 1.58333 V VINS AD 00 0 2470 Europe/Andorra 1993-12-23
+3041108 Riu de les Cebes Riu de les Cebes 42.61667 1.58333 H STM AD 00 0 2374 Europe/Andorra 1993-12-23
+3041109 Clot del Cavall Clot del Cavall 42.6 1.5 T SLP AD 00 0 1923 Europe/Andorra 1993-12-23
+3041110 Costa del Caup Costa del Caup 42.6 1.66667 T SLP AD 00 0 1858 Europe/Andorra 1993-12-23
+3041111 Solana de la Caülla Solana de la Caulla 42.48333 1.53333 T SLP AD 00 0 2255 Europe/Andorra 1993-12-23
+3041112 Collada de la Caülla Collada de la Caulla 42.48333 1.53333 T PASS AD 00 0 2255 Europe/Andorra 1993-12-23
+3041113 Clots de la Caülla Clots de la Caulla 42.48333 1.53333 H RVN AD 00 0 2255 Europe/Andorra 1993-12-23
+3041114 Bosc de la Caülla Bosc de la Caulla 42.48333 1.53333 V FRST AD 00 0 2255 Europe/Andorra 1993-12-23
+3041115 Planell de la Caubella Planell de la Caubella 42.53333 1.48333 T UPLD AD 00 0 1677 Europe/Andorra 1993-12-23
+3041116 Torrent de la Cauba Torrent de la Cauba 42.55 1.51667 H STM AD 00 0 1397 Europe/Andorra 1993-12-23
+3041117 Roc de la Cauba Roc de la Cauba 42.56114 1.51506 T RK AD 00 0 1551 Europe/Andorra 2011-04-19
+3041118 Coll de la Cauba Coll de la Cauba 42.58333 1.61667 T PASS AD 00 0 1707 Europe/Andorra 1993-12-23
+3041119 Bosc de la Cauba Bosc de la Cauba 42.56667 1.51667 V FRST AD 00 0 1500 Europe/Andorra 1993-12-23
+3041120 Catolla la Guineu Catolla la Guineu 42.46667 1.46667 L LCTY AD 00 0 1340 Europe/Andorra 1993-12-23
+3041121 Pic de Cataverdis Pic de Cataverdis Pic de Cataperdis,Pic de CataperdÃs,Pic de Cataverdis 42.61667 1.46667 T PK AD 00 0 2442 Europe/Andorra 2011-11-05
+3041122 Roc dels Castells Roc dels Castells 42.51667 1.55 T RK AD 00 0 1322 Europe/Andorra 1993-12-23
+3041123 Riu de les Castelletes Riu de les Castelletes 42.45 1.53333 H STM AD 00 0 1859 Europe/Andorra 1993-12-23
+3041124 Roc de la Castelleta Roc de la Castelleta 42.56667 1.5 T RK AD 00 0 1636 Europe/Andorra 1993-12-23
+3041125 Canal de la Castelleta Canal de la Castelleta 42.53333 1.5 H STM AD 00 0 1357 Europe/Andorra 1993-12-23
+3041126 Bosc de la Castelleta Bosc de la Castelleta 42.53333 1.5 V FRST AD 00 0 1357 Europe/Andorra 1993-12-23
+3041127 Bony de la Castelleta Bony de la Castelleta 42.53333 1.53333 T SPUR AD 00 0 1521 Europe/Andorra 1993-12-23
+3041128 Font del Casteller Font del Casteller 42.53333 1.55 H SPNG AD 00 0 1344 Europe/Andorra 1993-12-23
+3041129 Castell de Sant Vicenç Castell de Sant Vicenc Castell de Sant Vicenc,Castell de Sant Vicens,Castell de Sant Vicenç 42.49658 1.48686 S RUIN AD 00 0 1027 Europe/Andorra 2011-11-05
+3041130 Castell dels Moros Castell dels Moros Castel dels Moros La Meca,Castell dels Moros,La Meca 42.55 1.53333 T PROM AD AD 00 0 1593 Europe/Andorra 2011-11-05
+3041131 Pleta del Castellar Pleta del Castellar 42.63333 1.51667 L GRAZ AD 00 0 1894 Europe/Andorra 1993-12-23
+3041132 Canal del Castellar Canal del Castellar Canal del Castella,Canal del Castellar,Canal del Castellà 42.6 1.63333 H STM AD AD 00 0 1893 Europe/Andorra 2011-11-05
+3041133 Bosc del Castellar Bosc del Castellar 42.63333 1.51667 V FRST AD 00 0 1894 Europe/Andorra 1993-12-23
+3041134 Bordes del Castellar Bordes del Castellar 42.53031 1.60873 S HUTS AD 00 0 2101 Europe/Andorra 2011-04-19
+3041135 Rocs de Castell Rocs de Castell 42.46667 1.45 T RKS AD 00 0 1562 Europe/Andorra 1993-12-23
+3041136 Roc del Castell Roc del Castell 42.46667 1.46667 T RK AD 00 0 1340 Europe/Andorra 1993-12-23
+3041137 Canal del Castell Canal del Castell 42.58333 1.51667 H STM AD 00 0 1722 Europe/Andorra 1993-12-23
+3041138 Bosc del Castell Bosc del Castell 42.58333 1.51667 V FRST AD 00 0 1722 Europe/Andorra 1993-12-23
+3041139 Coll de les Cases Coll de les Cases 42.58333 1.5 T PK AD 00 0 1595 Europe/Andorra 1993-12-23
+3041140 Canal de les Casasses Canal de les Casasses 42.55 1.5 H STM AD 00 0 1292 Europe/Andorra 1993-12-23
+3041141 Serra de Casamanya Serra de Casamanya 42.58877 1.57163 T RDGE AD 00 0 2423 Europe/Andorra 2011-04-19
+3041142 Riu de Casamanya Riu de Casamanya 42.55 1.55 H STM AD 00 0 2097 Europe/Andorra 1993-12-23
+3041143 Pic de Casamanya Pic de Casamanya Pic de Camanya,Pic de Casamanya 42.58619 1.56971 T PK AD 00 0 2423 Europe/Andorra 2011-11-05
+3041144 Camà de Casamanya Cami de Casamanya 42.56667 1.55 R TRL AD 00 0 1996 Europe/Andorra 1993-12-23
+3041145 Casamanya Casamanya 42.56667 1.55 A ADMD AD 00 0 1996 Europe/Andorra 1993-12-23
+3041146 Borda del Casadet Borda del Casadet 42.56667 1.6 S HUT AD 00 0 1655 Europe/Andorra 1993-12-23
+3041147 Bordes de la Casa Bordes de la Casa Bordes,Bordes de la Casa 42.53333 1.61667 S HUTS AD AD 00 0 2237 Europe/Andorra 2011-11-05
+3041148 Bordes de la Casa Bordes de la Casa 42.53333 1.6 S HUTS AD 00 0 1888 Europe/Andorra 1993-12-23
+3041149 Pic de Carroi Pic de Carroi 42.51667 1.5 T PK AD 00 0 1688 Europe/Andorra 1993-12-23
+3041150 Roc del Carret Roc del Carret 42.56667 1.48333 T RK AD 00 0 1508 Europe/Andorra 1993-12-23
+3041151 Roc del Carrador Roc del Carrador 42.56667 1.48333 T RK AD 00 0 1508 Europe/Andorra 1993-12-23
+3041152 Bosc del Carpider Bosc del Carpider 42.51667 1.5 V FRST AD 00 0 1688 Europe/Andorra 1993-12-23
+3041153 Canal Carnissera Canal Carnissera 42.58333 1.46667 H STM AD 00 0 1643 Europe/Andorra 1993-12-23
+3041154 Canal Carnissera Canal Carnissera 42.5 1.6 H STM AD 00 0 2416 Europe/Andorra 1993-12-23
+3041155 Canal Carnissera Canal Carnissera 42.65 1.55 H RVN AD 00 0 2181 Europe/Andorra 1993-12-23
+3041156 Roca de Carmenús Roca de Carmenus 42.55 1.61667 T RK AD 00 0 2206 Europe/Andorra 1993-12-23
+3041157 Clots de Carmenús Clots de Carmenus 42.55 1.61667 H RVN AD 00 0 2206 Europe/Andorra 1993-12-23
+3041158 Riu del Cardemeller Riu del Cardemeller 42.55 1.46667 H STM AD 00 0 1585 Europe/Andorra 1993-12-23
+3041159 Borda del Cardago Borda del Cardago 42.53333 1.58333 S HUT AD 00 0 1571 Europe/Andorra 1993-12-23
+3041160 Roca de Carcamanyà Roca de Carcamanya 42.53333 1.56667 T RK AD 00 0 1418 Europe/Andorra 1993-12-23
+3041161 Barranc del Carcabanyat Barranc del Carcabanyat 42.55 1.48333 H STM AD 00 0 1548 Europe/Andorra 1993-12-23
+3041162 Carboneres de Ferrer Carboneres de Ferrer 42.48333 1.6 L LCTY AD 00 0 2250 Europe/Andorra 1993-12-23
+3041163 Bosc de les Carboneres Bosc de les Carboneres 42.51667 1.51667 V FRST AD 00 0 1265 Europe/Andorra 1993-12-23
+3041164 Bony de les Carboneres Bony de les Carboneres 42.56667 1.65 T SPUR AD 00 0 1988 Europe/Andorra 1993-12-23
+3041165 Pleta Carbona Pleta Carbona 42.63333 1.5 L GRAZ AD 00 0 1979 Europe/Andorra 1993-12-23
+3041166 Planell del Carbó Planell del Carbo 42.53333 1.48333 T UPLD AD 00 0 1677 Europe/Andorra 1993-12-23
+3041167 Canal de la Carbassa Canal de la Carbassa 42.51667 1.48333 H STM AD 00 0 1839 Europe/Andorra 1993-12-23
+3041168 Tosa de Caraup Tosa de Caraup 42.6 1.65 T UPLD AD 00 0 2131 Europe/Andorra 1993-12-23
+3041169 Planells de Caraup Planells de Caraup 42.61667 1.65 T UPLD AD 00 0 2567 Europe/Andorra 1993-12-23
+3041170 Clots de Caraup Clots de Caraup 42.61667 1.65 H RVN AD 00 0 2567 Europe/Andorra 1993-12-23
+3041171 Riu de Cap Torrent Riu de Cap Torrent 42.53333 1.56667 H STM AD 00 0 1418 Europe/Andorra 1993-12-23
+3041172 Pont de Capigol Pont de Capigol 42.56667 1.66667 S BDG AD 00 0 1938 Europe/Andorra 1993-12-23
+3041173 Font dels Capellans Font dels Capellans 42.6 1.63333 H SPNG AD 00 0 1893 Europe/Andorra 1993-12-23
+3041174 Cortal del Capdevila Cortal del Capdevila 42.53333 1.53333 S CRRL AD 00 0 1521 Europe/Andorra 1993-12-23
+3041175 Estany del Cap dels Pessons Estany del Cap dels Pessons 42.51996 1.67873 H LK AD 00 0 2352 Europe/Andorra 2011-04-19
+3041176 Tosa del Cap del Siscaró Tosa del Cap del Siscaro 42.58333 1.71667 T UPLD AD 00 0 2553 Europe/Andorra 1993-12-23
+3041177 Cap dels Clots de Massat Cap dels Clots de Massat 42.56667 1.7 L LCTY AD 00 0 2375 Europe/Andorra 1993-12-23
+3041178 Collada del Cap dels Clots Collada del Cap dels Clots 42.55 1.63333 T PASS AD 00 0 2336 Europe/Andorra 1993-12-23
+3041179 Cap dels Clots Cap dels Clots 42.55 1.63333 L LCTY AD 00 0 2336 Europe/Andorra 1993-12-23
+3041180 Canal del Cap dels Camp Canal del Cap dels Camp 42.55 1.53333 H STM AD 00 0 1593 Europe/Andorra 1993-12-23
+3041181 Clot del Cap del Maià Clot del Cap del Maia 42.55 1.71667 H RVN AD 00 0 2192 Europe/Andorra 1993-12-23
+3041182 Pala del Cap de les Tallades Pala del Cap de les Tallades 42.61667 1.55 T SLP AD 00 0 2007 Europe/Andorra 1993-12-23
+3041183 Planada del Cap de les Canals dels Obacs Planada del Cap de les Canals dels Obacs 42.6 1.5 T UPLD AD 00 0 1923 Europe/Andorra 1993-12-23
+3041184 Cap de les Agols Cap de les Agols 42.5 1.61667 L LCTY AD 00 0 2560 Europe/Andorra 1993-12-23
+3041185 Cap del Bosc de Moretó Cap del Bosc de Moreto 42.53333 1.68333 L LCTY AD 00 0 2322 Europe/Andorra 1993-12-23
+3041186 Cap del Bosc dels Plans Cap del Bosc dels Plans 42.58333 1.61667 L LCTY AD 00 0 1707 Europe/Andorra 1993-12-23
+3041187 Cap de la Solana del Forn Cap de la Solana del Forn 42.53333 1.65 L LCTY AD 00 0 2508 Europe/Andorra 1993-12-23
+3041188 Cap de la Montada Cap de la Montada 42.56667 1.58333 L LCTY AD 00 0 1919 Europe/Andorra 1993-12-23
+3041189 Tarteres del Cap de la Coma Tarteres del Cap de la Coma 42.61667 1.48333 T TAL AD 00 0 2470 Europe/Andorra 1993-12-23
+3041190 Serra del Cap de la Coma Serra del Cap de la Coma 42.61667 1.48333 T RDGE AD 00 0 2470 Europe/Andorra 1993-12-23
+3041191 Alt de la Capa Alt de la Capa 42.56293 1.45424 T PK AD 00 0 2173 Europe/Andorra 2011-04-19
+3041192 Font de les Canyorques Font de les Canyorques 42.58333 1.43333 H SPNG AD 00 0 2412 Europe/Andorra 1993-12-23
+3041193 Coves de la Canya Gran Coves de la Canya Gran 42.48333 1.46667 S CAVE AD 00 0 1148 Europe/Andorra 1993-12-23
+3041194 Planell de la Canya Planell de la Canya 42.58333 1.6 T UPLD AD 00 0 1828 Europe/Andorra 1993-12-23
+3041195 Bosc de la Canya Bosc de la Canya 42.58333 1.6 V FRST AD 00 0 1828 Europe/Andorra 1993-12-23
+3041196 Font de Cantallops Font de Cantallops 42.56667 1.5 H SPNG AD 00 0 1636 Europe/Andorra 1993-12-23
+3041197 Canal de Cantallops Canal de Cantallops 42.56667 1.5 H STM AD 00 0 1636 Europe/Andorra 1993-12-23
+3041198 Roc de Canomala Roc de Canomala 42.56667 1.68333 T RK AD 00 0 2340 Europe/Andorra 1993-12-23
+3041199 Santuari de Canòlic Santuari de Canolic 42.46667 1.45 S CH AD 00 0 1562 Europe/Andorra 1993-12-23
+3041200 Conreu de Canòlic Conreu de Canolic 42.48333 1.45 V CULT AD 00 0 1195 Europe/Andorra 1993-12-23
+3041201 Carretera de Canòlic Carretera de Canolic 42.48333 1.46667 R RD AD 00 0 1148 Europe/Andorra 1993-12-23
+3041202 Canòlic Canolic 42.46667 1.45 A ADMD AD 00 0 1562 Europe/Andorra 1993-12-23
+3041203 Parròquia de Canillo Parroquia de Canillo Canillo,Parroquia de Canillo,Parròquia de Canillo 42.58333 1.66667 A ADM1 AD AD 02 5067 2159 Europe/Andorra 2011-11-05
+3041204 Canillo Canillo Canillo,Kanil'o,ka ni e,kaniryo jiao qu,Канильо,カニーリョ教区,å¡å°¼ç•¥ 42.5669 1.59556 P PPLA AD 02 3292 1640 Europe/Andorra 2011-11-05
+3041205 Estany de les Canals Roges Estany de les Canals Roges 42.58333 1.71667 H LK AD 00 0 2553 Europe/Andorra 1993-12-23
+3041206 Cap de les Canals de Ribanelles Cap de les Canals de Ribanelles 42.58333 1.46667 T PK AD 00 0 1643 Europe/Andorra 1993-12-23
+3041207 Pic de les Canals de Montmantell Pic de les Canals de Montmantell 42.6 1.48333 T PK AD 00 0 2441 Europe/Andorra 1993-12-23
+3041208 Canals dels Planells de Baell Canals dels Planells de Baell 42.5 1.6 L LCTY AD 00 0 2416 Europe/Andorra 1993-12-23
+3041209 Canals dels Obacs Canals dels Obacs 42.6 1.5 H RVN AD 00 0 1923 Europe/Andorra 1993-12-23
+3041210 Canals del Pla de l’Ingla Canals del Pla de l'Ingla 42.48333 1.61667 L LCTY AD 00 0 2217 Europe/Andorra 1993-12-23
+3041211 Canals del Maià Canals del Maia 42.56667 1.73333 L LCTY AD 00 0 2096 Europe/Andorra 1993-12-23
+3041212 Canals de la Rabassa Canals de la Rabassa 42.63333 1.56667 L LCTY AD 00 0 2394 Europe/Andorra 1993-12-23
+3041213 Canals de la Comarqueta Canals de la Comarqueta 42.48333 1.61667 L LCTY AD 00 0 2217 Europe/Andorra 1993-12-23
+3041214 Canals de la Burna Canals de la Burna 42.58333 1.5 L LCTY AD 00 0 1595 Europe/Andorra 1993-12-23
+3041215 Serra de les Canals de Falcobà Serra de les Canals de Falcobi 42.63333 1.55 T RDGE AD 00 0 2053 Europe/Andorra 1993-12-23
+3041216 Canals de Falcobà Canals de Falcobi 42.63333 1.55 L LCTY AD 00 0 2053 Europe/Andorra 1993-12-23
+3041217 Canals de Comascura Canals de Comascura 42.5 1.55 L LCTY AD 00 0 1566 Europe/Andorra 1993-12-23
+3041218 Riu de les Canals Riu de les Canals 42.58333 1.63333 H STM AD 00 0 1722 Europe/Andorra 1993-12-23
+3041219 Camà de les Canals Cami de les Canals 42.58333 1.63333 R TRL AD 00 0 1722 Europe/Andorra 1993-12-23
+3041220 Bosc de les Canals Bosc de les Canals 42.58333 1.63333 V FRST AD 00 0 1722 Europe/Andorra 1993-12-23
+3041221 Bosc de la Canal Llisa Bosc de la Canal Llisa 42.56667 1.5 V FRST AD 00 0 1636 Europe/Andorra 1993-12-23
+3041222 Serrat de la Canal de Nicolau Serrat de la Canal de Nicolau 42.61667 1.55 T RDGE AD 00 0 2007 Europe/Andorra 1993-12-23
+3041223 Solana de la Canal Solana de la Canal 42.48333 1.43333 T SLP AD 00 0 1938 Europe/Andorra 1993-12-23
+3041224 Torrent de la Canadilla Torrent de la Canadilla 42.53333 1.58333 H STM AD 00 0 1571 Europe/Andorra 1993-12-23
+3041225 Camps de Sispony Camps de Sispony 42.53333 1.51667 L LCTY AD 00 0 1361 Europe/Andorra 1993-12-23
+3041226 Torrent dels Camps de Pardellà Torrent dels Camps de Pardella 42.46667 1.5 H STM AD 00 0 1383 Europe/Andorra 1993-12-23
+3041227 Camps de Pardellà Camps de Pardella 42.46667 1.51667 L LCTY AD 00 0 1985 Europe/Andorra 1993-12-23
+3041228 Camp Ramonet Camp Ramonet 42.47397 1.53854 L LCTY AD 00 0 2541 Europe/Andorra 2011-04-19
+3041229 Planell de Campillar Planell de Campillar 42.58333 1.68333 T UPLD AD 00 0 2294 Europe/Andorra 1993-12-23
+3041230 Fonts del Campeà Fonts del Campea 42.51667 1.61667 H SPNG AD 00 0 2254 Europe/Andorra 1993-12-23
+3041231 Bosc del Campeà Bosc del Campea 42.53333 1.63333 V FRST AD 00 0 2360 Europe/Andorra 1993-12-23
+3041232 Camp de Vassalló Camp de Vassallo 42.58333 1.53333 L LCTY AD 00 0 1924 Europe/Andorra 1993-12-23
+3041233 Camp del Sastre Camp del Sastre 42.45 1.53333 L LCTY AD 00 0 1859 Europe/Andorra 1993-12-23
+3041234 Camp del Remugar Camp del Remugar 42.56667 1.53333 L LCTY AD 00 0 1669 Europe/Andorra 1993-12-23
+3041235 Camp del Cortal Camp del Cortal 42.56667 1.5 L LCTY AD 00 0 1636 Europe/Andorra 1993-12-23
+3041236 Camp de la Trava Camp de la Trava 42.56667 1.53333 L LCTY AD 00 0 1669 Europe/Andorra 1993-12-23
+3041237 Camp de la Llosa Camp de la Llosa 42.56667 1.51667 L LCTY AD 00 0 1500 Europe/Andorra 1993-12-23
+3041238 Bosc del Camp de la Finestra Bosc del Camp de la Finestra 42.5 1.53333 V FRST AD 00 0 1574 Europe/Andorra 1993-12-23
+3041239 Pedrusques del Camp de Claror Pedrusques del Camp de Claror 42.48333 1.55 T TAL AD 00 0 2233 Europe/Andorra 1993-12-23
+3041240 Camp de Claror Camp de Claror 42.46667 1.55 L LCTY AD 00 0 2341 Europe/Andorra 1993-12-23
+3041241 Camp Borrut Camp Borrut 42.45 1.56667 L LCTY AD 00 0 2558 Europe/Andorra 1993-12-23
+3041242 Pont del Camp Pont del Camp 42.55 1.48333 S BDG AD 00 0 1548 Europe/Andorra 1993-12-23
+3041243 Camà del Canal Cami del Canal 42.51667 1.58333 H CNL AD 00 0 1994 Europe/Andorra 1993-12-23
+3041244 Cal Toni Cal Toni 42.55 1.6 S HSE AD 00 0 2210 Europe/Andorra 1993-12-23
+3041245 Cal Serra Cal Serra 42.46667 1.5 S FRM AD 00 0 1383 Europe/Andorra 1993-12-23
+3041246 Cal Ponet Cal Ponet 42.56667 1.6 S HSE AD 00 0 1655 Europe/Andorra 1993-12-23
+3041247 Cal Patxeta Cal Patxeta 42.56667 1.6 S HSE AD 00 0 1655 Europe/Andorra 1993-12-23
+3041248 Cal Jaumina Cal Jaumina 42.55 1.58333 S HSE AD 00 0 1499 Europe/Andorra 1993-12-23
+3041249 Canal de la Calcinera Canal de la Calcinera Canal de la Calcinera,Canal de la Calzinera 42.53333 1.58333 H STM AD AD 00 0 1571 Europe/Andorra 2011-11-05
+3041250 Cal Call Cal Call 42.55 1.6 S HSE AD 00 0 2210 Europe/Andorra 1993-12-23
+3041251 Cal Borronet Cal Borronet 42.56667 1.6 S HSE AD 00 0 1655 Europe/Andorra 1993-12-23
+3041252 Cal Borró Cal Borro 42.55 1.6 S HSE AD 00 0 2210 Europe/Andorra 1993-12-23
+3041253 Cal Becaina Cal Becaina 42.55 1.58333 S HSE AD 00 0 1499 Europe/Andorra 1993-12-23
+3041254 Cal Bartreta Cal Bartreta 42.55 1.6 S HSE AD 00 0 2210 Europe/Andorra 1993-12-23
+3041255 Solà de Calaup Sola de Calaup 42.58333 1.65 T SLP AD 00 0 1767 Europe/Andorra 1993-12-23
+3041256 Font de la Caitanta Font de la Caitanta 42.48333 1.63333 H SPNG AD 00 0 2296 Europe/Andorra 1993-12-23
+3041257 Serrat del Caire Forc Serrat del Caire Forc 42.53333 1.61667 T SPUR AD 00 0 2237 Europe/Andorra 1993-12-23
+3041258 Riu del Caire Forc Riu del Caire Forc 42.53333 1.61667 H STM AD 00 0 2237 Europe/Andorra 1993-12-23
+3041259 Caire Forc Caire Forc 42.53333 1.63333 L LCTY AD 00 0 2360 Europe/Andorra 1993-12-23
+3041260 Torrent dels CÃ cols Torrent dels Cacols 42.56667 1.48333 H STM AD 00 0 1508 Europe/Andorra 1993-12-23
+3041261 Roc de la Cacarulla Roc de la Cacarulla 42.55 1.48333 T RK AD 00 0 1548 Europe/Andorra 1993-12-23
+3041262 Collado de Cabris Collado de Cabris Collado de Cabris,Port de Cabus,Port de Cabús 42.55 1.41667 T PASS AD 00 0 2105 Europe/Andorra 2011-11-05
+3041263 Solana de Caborreu Solana de Caborreu 42.43333 1.55 T SLP AD 00 0 2178 Europe/Andorra 1993-12-23
+3041264 Riu de Caborreu Riu de Caborreu 42.45 1.53333 H STM AD 00 0 1859 Europe/Andorra 1993-12-23
+3041265 Bosc de la Cabeça Bosc de la Cabeca 42.5 1.45 V FRST AD 00 0 1840 Europe/Andorra 1993-12-23
+3041266 Pleta de la Cabaneta Pleta de la Cabaneta 42.6 1.61667 L GRAZ AD 00 0 2271 Europe/Andorra 1993-12-23
+3041267 Pic de la Cabaneta Pic de la Cabaneta 42.61667 1.6 T PK AD 00 0 2528 Europe/Andorra 1993-12-23
+3041268 Pic de la Cabanette Pic de la Cabanette Cabaneta,Pic de la Cabaneta,Pic de la Cabanette 42.58333 1.73333 T PK AD 00 0 2378 Europe/Andorra 2011-11-05
+3041269 Bosc de la Cabanella Bosc de la Cabanella 42.51667 1.46667 V FRST AD 00 0 1840 Europe/Andorra 1993-12-23
+3041270 Serra de Cabana Sorda Serra de Cabana Sorda 42.61667 1.66667 T RDGE AD 00 0 2536 Europe/Andorra 1993-12-23
+3041271 Riu de Cabana Sorda Riu de Cabana Sorda 42.6 1.68333 H STM AD 00 0 2089 Europe/Andorra 1993-12-23
+3041272 Pleta de Cabana Sorda Pleta de Cabana Sorda 42.61667 1.68333 L GRAZ AD 00 0 2406 Europe/Andorra 1993-12-23
+3041273 Pales de Cabana Sorda Pales de Cabana Sorda 42.61667 1.66667 T CLF AD 00 0 2536 Europe/Andorra 1993-12-23
+3041274 Estany de Cabana Sorda Estany de Cabana Sorda 42.61667 1.66667 H LK AD 00 0 2536 Europe/Andorra 1993-12-23
+3041275 Cabana Sorda Cabana Sorda 42.61667 1.66667 A ADMD AD 00 0 2536 Europe/Andorra 1993-12-23
+3041276 Font de la Cabana de l’Eucasser Font de la Cabana de l'Eucasser 42.58333 1.61667 H SPNG AD 00 0 1707 Europe/Andorra 1993-12-23
+3041277 Pic de Cabayrou Pic de Cabayrou Cabairu,Cabairú,Pic de Cabagnau,Pic de Cabairu,Pic de Cabairú,Pic de Cabayrou 42.63333 1.46667 T PK AD 00 0 2324 Europe/Andorra 2011-11-05
+3041278 Font de la Ca Font de la Ca 42.45 1.5 H SPNG AD 00 0 1614 Europe/Andorra 1993-12-23
+3041279 Pla de Buscalls Pla de Buscalls Pla de Buscalls,Pla de Busoalls 42.56667 1.65 T UPLD AD AD 00 0 1988 Europe/Andorra 2011-11-05
+3041280 Serrat de la Burna Serrat de la Burna 42.6 1.48333 T SPUR AD 00 0 2441 Europe/Andorra 1993-12-23
+3041281 Pic de la Burna Pic de la Burna 42.6 1.48333 T PK AD 00 0 2441 Europe/Andorra 1993-12-23
+3041282 Clot de la Burna Clot de la Burna 42.6 1.48333 T SLP AD 00 0 2441 Europe/Andorra 1993-12-23
+3041283 Font dels Bullidors Font dels Bullidors 42.46667 1.45 H SPNG AD 00 0 1562 Europe/Andorra 1993-12-23
+3041284 Toll Bullidor Toll Bullidor 42.58333 1.61667 L GRAZ AD 00 0 1707 Europe/Andorra 1993-12-23
+3041285 Barranc del Bullidor Barranc del Bullidor 42.53333 1.71667 H STM AD 00 0 2400 Europe/Andorra 1993-12-23
+3041286 Roc de Bruna Roja Roc de Bruna Roja 42.63333 1.53333 T RK AD 00 0 2072 Europe/Andorra 1993-12-23
+3041287 Pleta del Bruig Pleta del Bruig 42.63333 1.5 L GRAZ AD 00 0 1979 Europe/Andorra 1993-12-23
+3041288 Marrades del Bruig Marrades del Bruig 42.63333 1.5 R TRL AD 00 0 1979 Europe/Andorra 1993-12-23
+3041289 Basers del Bruig Basers del Bruig 42.65 1.5 T CLF AD 00 0 2455 Europe/Andorra 1993-12-23
+3041290 Bruig Bruig 42.65 1.5 T SLP AD 00 0 2455 Europe/Andorra 1993-12-23
+3041291 Pic del Brossós Pic del Brossos 42.61667 1.51667 T PK AD 00 0 1716 Europe/Andorra 1993-12-23
+3041292 Canals del Brossós Canals del Brossos 42.61667 1.53333 H RVN AD 00 0 1609 Europe/Andorra 1993-12-23
+3041293 Camà del Brossós Cami del Brossos 42.61667 1.53333 R TRL AD 00 0 1609 Europe/Andorra 1993-12-23
+3041294 Cortal del Bringuer Cortal del Bringuer 42.45 1.46667 S CRRL AD 00 0 935 Europe/Andorra 1993-12-23
+3041295 Cortal de Bringuer Cortal de Bringuer 42.53333 1.53333 S CRRL AD 00 0 1521 Europe/Andorra 1993-12-23
+3041296 Borda del Bringuer Borda del Bringuer 42.45 1.48333 S HUTS AD 00 0 1111 Europe/Andorra 1993-12-23
+3041297 Clot dels Brillons Clot dels Brillons 42.46667 1.46667 H RVN AD 00 0 1340 Europe/Andorra 1993-12-23
+3041298 Brancs de la Farga Brancs de la Farga 42.48333 1.61667 L LCTY AD 00 0 2217 Europe/Andorra 1993-12-23
+3041299 Tosa del Braibal Tosa del Braibal Tosa del Braibal,Tossal Braibal 42.50302 1.59836 T PK AD 00 0 2436 Europe/Andorra 2011-11-05
+3041300 Planells del Braibal Planells del Braibal 42.51667 1.58333 T UPLD AD 00 0 1994 Europe/Andorra 1993-12-23
+3041301 Font del Braibal Font del Braibal 42.51667 1.58333 H SPNG AD 00 0 1994 Europe/Andorra 1993-12-23
+3041302 Estany de la Bova Estany de la Bova 42.48333 1.65 H LK AD 00 0 2658 Europe/Andorra 1993-12-23
+3041303 Canal de la Bova Canal de la Bova 42.5 1.58333 H STM AD 00 0 1888 Europe/Andorra 1993-12-23
+3041304 Costa de Bou Mort Costa de Bou Mort 42.46667 1.56667 T SLP AD 00 0 2365 Europe/Andorra 1993-12-23
+3041305 Plana del Bou Plana del Bou 42.45 1.46667 T UPLD AD 00 0 935 Europe/Andorra 1993-12-23
+3041306 Cortal del Bou Cortal del Bou 42.45 1.46667 S HUT AD 00 0 935 Europe/Andorra 1993-12-23
+3041307 Roc de la Botiffarra Roc de la Botiffarra 42.48333 1.48333 T RK AD 00 0 981 Europe/Andorra 1993-12-23
+3041308 Col de la Botella Col de la Botella 42.55 1.46667 T PASS AD 00 0 1585 Europe/Andorra 1993-12-23
+3041309 Canal del Botàs Canal del Botas 42.55 1.58333 H STM AD 00 0 1499 Europe/Andorra 1993-12-23
+3041310 Canal dels Botaders Canal dels Botaders 42.5 1.48333 H STM AD 00 0 1316 Europe/Andorra 1993-12-23
+3041311 Canal del Bosc Nou Canal del Bosc Nou 42.58333 1.65 H STM AD 00 0 1767 Europe/Andorra 1993-12-23
+3041312 Canal del Bosc Negre Canal del Bosc Negre 42.55 1.46667 H STM AD 00 0 1585 Europe/Andorra 1993-12-23
+3041313 Bosc del Coll d’Ordino Bosc del Coll d'Ordino 42.55 1.55 A ADMD AD 00 0 2097 Europe/Andorra 1993-12-23
+3041314 Canal del Bosc de Coma Canal del Bosc de Coma 42.53333 1.53333 H STM AD 00 0 1521 Europe/Andorra 1993-12-23
+3041315 Boscarró Boscarro 42.55 1.46667 L LCTY AD 00 0 1585 Europe/Andorra 1993-12-23
+3041316 Torrent del Bosc Torrent del Bosc 42.48333 1.45 H STM AD 00 0 1195 Europe/Andorra 1993-12-23
+3041317 Pla del Bosc Pla del Bosc 42.56667 1.66667 T UPLD AD 00 0 1938 Europe/Andorra 1993-12-23
+3041318 Pla del Bosc Pla del Bosc 42.55 1.6 T UPLD AD 00 0 2210 Europe/Andorra 1993-12-23
+3041319 Clot del Bosc Clot del Bosc 42.43333 1.51667 T SLP AD 00 0 2031 Europe/Andorra 1993-12-23
+3041320 Barranc del Bosc Barranc del Bosc 42.56667 1.58333 H STM AD 00 0 1919 Europe/Andorra 1993-12-23
+3041321 Boïgues de Borró Boigues de Borro 42.55 1.6 V CULT AD 00 0 2210 Europe/Andorra 1993-12-23
+3041322 Pleta dels Borrecs Pleta dels Borrecs 42.58333 1.68333 L GRAZ AD 00 0 2294 Europe/Andorra 1993-12-23
+3041323 Borrassica Borrassica 42.5 1.48333 L LCTY AD 00 0 1316 Europe/Andorra 1993-12-23
+3041324 Pla de Borràs Pla de Borras 42.53333 1.48333 T UPLD AD 00 0 1677 Europe/Andorra 1993-12-23
+3041325 Bosc del Bornal Bosc del Bornal 42.53333 1.46667 V FRST AD 00 0 1846 Europe/Andorra 1993-12-23
+3041326 Pla de Bordetes Pla de Bordetes 42.6 1.66667 T UPLD AD 00 0 1858 Europe/Andorra 1993-12-23
+3041327 Bordes de Ramonet Bordes de Ramonet 42.51667 1.55 A ADMD AD 00 0 1322 Europe/Andorra 1993-12-23
+3041328 Canal de les Bordes Canal de les Bordes 42.56667 1.61667 H RVN AD 00 0 1920 Europe/Andorra 1993-12-23
+3041329 Palanca de la Borda del Sabater Palanca de la Borda del Sabater 42.45 1.48333 S BDG AD 00 0 1111 Europe/Andorra 1993-12-23
+3041330 Bosc de la Borda del Rauquet Bosc de la Borda del Rauquet 42.6 1.63333 V FRST AD 00 0 1893 Europe/Andorra 1993-12-23
+3041331 Borda del Molines Borda del Molines 42.5 1.43333 S RUIN AD 00 0 1654 Europe/Andorra 1993-12-23
+3041332 Borda del Ferrer Nou Borda del Ferrer Nou 42.45 1.48333 S RUIN AD 00 0 1111 Europe/Andorra 1993-12-23
+3041333 Camà de la Borda del Cosp Cami de la Borda del Cosp 42.45 1.48333 R TRL AD 00 0 1111 Europe/Andorra 1993-12-23
+3041334 Basera de la Borda de l’Arena Basera de la Borda de l'Arena 42.48333 1.46667 T CLF AD 00 0 1148 Europe/Andorra 1993-12-23
+3041335 Borda de l’Alma Borda de l'Alma 42.58333 1.65 S RUIN AD 00 0 1767 Europe/Andorra 1993-12-23
+3041336 Riu de la Bor Riu de la Bor 42.58333 1.63333 H STM AD 00 0 1722 Europe/Andorra 1993-12-23
+3041337 Gorges de la Bor Gorges de la Bor 42.55 1.58333 T GRGE AD 00 0 1499 Europe/Andorra 1993-12-23
+3041338 Costa del Bony Roig Costa del Bony Roig 42.6 1.61667 T SLP AD 00 0 2271 Europe/Andorra 1993-12-23
+3041339 Planades del Bony Negre Planades del Bony Negre 42.56667 1.45 T UPLD AD 00 0 2137 Europe/Andorra 1993-12-23
+3041340 Canal Gran del Bony de la Pica Canal Gran del Bony de la Pica 42.5 1.46667 H STM AD 00 0 1678 Europe/Andorra 1993-12-23
+3041341 Obaga del Bony de la Costa Obaga del Bony de la Costa 42.56667 1.53333 T SLP AD 00 0 1669 Europe/Andorra 1993-12-23
+3041342 Obaga del Bony Obaga del Bony 42.5 1.58333 T SLP AD 00 0 1888 Europe/Andorra 1993-12-23
+3041343 Boïga del Bony Boiga del Bony 42.56667 1.48333 V CULT AD 00 0 1508 Europe/Andorra 1993-12-23
+3041344 Boïga del Bony Boiga del Bony 42.45 1.53333 V CULT AD 00 0 1859 Europe/Andorra 1993-12-23
+3041345 Canal de les Bons Canal de les Bons 42.53333 1.58333 H STM AD 00 0 1571 Europe/Andorra 1993-12-23
+3041346 Canal de la Boneta Canal de la Boneta 42.5 1.5 H STM AD 00 0 1135 Europe/Andorra 1993-12-23
+3041347 Pont de Bonavida Pont de Bonavida 42.6 1.68333 S BDG AD 00 0 2089 Europe/Andorra 1993-12-23
+3041348 Bombal Bombal 42.6 1.53333 L LCTY AD 00 0 1695 Europe/Andorra 1993-12-23
+3041349 Bosc de la Boixera Bosc de la Boixera 42.53333 1.51667 V FRST AD 00 0 1361 Europe/Andorra 1993-12-23
+3041350 Canal de la Boïgueta Canal de la Boigueta 42.56667 1.51667 H STM AD 00 0 1500 Europe/Andorra 1993-12-23
+3041351 Costa de les Boïgues Costa de les Boigues 42.48333 1.46667 T SLP AD 00 0 1148 Europe/Andorra 1993-12-23
+3041352 Canal de les Boïgues Canal de les Boigues 42.55 1.46667 H STM AD 00 0 1585 Europe/Andorra 1993-12-23
+3041353 Boïgots Boigots 42.55 1.55 L LCTY AD 00 0 2097 Europe/Andorra 1993-12-23
+3041354 Font del Boïgot Font del Boigot 42.5 1.56667 H SPNG AD 00 0 1776 Europe/Andorra 1993-12-23
+3041355 Canal del Boïgot Canal del Boigot 42.5 1.55 H STM AD 00 0 1566 Europe/Andorra 1993-12-23
+3041356 Bosc de Boïga Plana Bosc de Boiga Plana 42.45 1.45 V FRST AD 00 0 1482 Europe/Andorra 1993-12-23
+3041357 Font de la Boïga Mitgera Font de la Boiga Mitgera 42.5 1.46667 H SPNG AD 00 0 1678 Europe/Andorra 1993-12-23
+3041358 Canal dels Boïgals Canal dels Boigals 42.51667 1.5 H STM AD 00 0 1688 Europe/Andorra 1993-12-23
+3041359 Serrat de Boïga Gran Serrat de Boiga Gran 42.48333 1.48333 T SPUR AD 00 0 981 Europe/Andorra 1993-12-23
+3041360 Font de la Boïga del Roi Font de la Boiga del Roi 42.5 1.48333 H SPNG AD 00 0 1316 Europe/Andorra 1993-12-23
+3041361 Roc de Boïga Curta Roc de Boiga Curta 42.51667 1.55 T RK AD 00 0 1322 Europe/Andorra 1993-12-23
+3041362 Estany Blau Estany Blau 42.49666 1.62069 H LK AD 00 0 2560 Europe/Andorra 2011-04-19
+3041363 Roques Blanques Roques Blanques 42.48333 1.48333 T CLF AD 00 0 981 Europe/Andorra 1993-12-23
+3041364 Rocs Blancs Rocs Blancs 42.45 1.45 T SLP AD 00 0 1482 Europe/Andorra 1993-12-23
+3041365 Roca Blanca Roca Blanca 42.56667 1.48333 T RK AD 00 0 1508 Europe/Andorra 1993-12-23
+3041366 La Porteille Blanche La Porteille Blanche La Porteille Blanche,Porteille Blanche d'Andorra,Porteille Blanche d'Andorre,Porteille Blanche d’Andorra,Porteille Blanche d’Andorre,Portella Blanca 42.5 1.73333 T PASS AD 00 0 2686 Europe/Andorra 2011-11-05
+3041367 Font Blanca Font Blanca 42.65 1.53333 H SPNG AD 00 0 2564 Europe/Andorra 1993-12-23
+3041368 Font Blanca Font Blanca 42.58333 1.58333 H SPNG AD 00 0 1993 Europe/Andorra 1993-12-23
+3041369 Canal Blanca Canal Blanca 42.55 1.61667 H RVN AD 00 0 2206 Europe/Andorra 1993-12-23
+3041370 Vial Blanc Vial Blanc 42.48333 1.5 R RD AD 00 0 1631 Europe/Andorra 1993-12-23
+3041371 Roc Blanc Roc Blanc 42.48333 1.53333 T RK AD 00 0 2255 Europe/Andorra 1993-12-23
+3041372 Riu Blanc Riu Blanc 42.53333 1.58333 H STM AD 00 0 1571 Europe/Andorra 1993-12-23
+3041373 Coll Blanc Coll Blanc 42.52961 1.72014 T PK AD 00 0 2400 Europe/Andorra 2011-04-19
+3041374 Carretera de Bixessarri Carretera de Bixessarri 42.48333 1.46667 R RD AD 00 0 1148 Europe/Andorra 1993-12-23
+3041375 Bixessarri Bixessarri Bicisarri,Bixessarri,Bixisarri,Biçisarri,Vixesarri 42.48238 1.45949 P PPL AD 06 0 1178 Europe/Andorra 2011-11-05
+3041376 Bissets Bissets 42.53333 1.53333 L LCTY AD 00 0 1521 Europe/Andorra 1993-12-23
+3041377 Bisset Bisset 42.55 1.53333 L LCTY AD 00 0 1593 Europe/Andorra 1993-12-23
+3041378 Planell del Bisbe Planell del Bisbe 42.48333 1.58333 T UPLD AD 00 0 2349 Europe/Andorra 1993-12-23
+3041379 Font del Bisbe Font del Bisbe 42.55 1.45 H SPNG AD 00 0 1788 Europe/Andorra 1993-12-23
+3041380 Font de la Birena Font de la Birena 42.51667 1.51667 H SPNG AD 00 0 1265 Europe/Andorra 1993-12-23
+3041381 Fontanal del Besurt Fontanal del Besurt 42.53333 1.48333 H SPNG AD 00 0 1677 Europe/Andorra 1993-12-23
+3041382 Roc del Bessó Roc del Besso 42.45 1.46667 T RK AD 00 0 935 Europe/Andorra 1993-12-23
+3041383 Font del Bessó Font del Besso 42.45 1.48333 H SPNG AD 00 0 1111 Europe/Andorra 1993-12-23
+3041384 Costa de Bescaran Costa de Bescaran 42.43333 1.5 T SLP AD 00 0 1804 Europe/Andorra 1993-12-23
+3041385 Portella de Besalà Portella de Besali 42.63333 1.55 T PASS AD 00 0 2053 Europe/Andorra 1993-12-23
+3041386 Pla de Besalà Pla de Besali 42.63333 1.55 T UPLD AD 00 0 2053 Europe/Andorra 1993-12-23
+3041387 Pic de Besalà Pic de Besali 42.63333 1.53333 T PK AD 00 0 2072 Europe/Andorra 1993-12-23
+3041388 Basers de Besalà Basers de Besali 42.63333 1.55 T CLF AD 00 0 2053 Europe/Andorra 1993-12-23
+3041389 Besalà Besali 42.63333 1.53333 A ADMD AD 00 0 2072 Europe/Andorra 1993-12-23
+3041390 Clot de les Berques Clot de les Berques 42.55 1.48333 H RVN AD 00 0 1548 Europe/Andorra 1993-12-23
+3041391 Coma Bella Coma Bella 42.58333 1.68333 T VAL AD 00 0 2294 Europe/Andorra 1993-12-23
+3041392 Riu de la Beixellosa Riu de la Beixellosa 42.53333 1.53333 H STM AD 00 0 1521 Europe/Andorra 1993-12-23
+3041393 Bosc de la Beixellosa Bosc de la Beixellosa 42.53333 1.53333 V FRST AD 00 0 1521 Europe/Andorra 1993-12-23
+3041394 Collada de BeixalÃs Collada de Beixalis 42.53333 1.55 T PASS AD 00 0 1344 Europe/Andorra 1993-12-23
+3041395 Carretera BeixalÃs Carretera Beixalis 42.53333 1.56667 R RD AD 00 0 1418 Europe/Andorra 1993-12-23
+3041396 Bosc de BeixalÃs Bosc de Beixalis 42.53333 1.55 V FRST AD 00 0 1344 Europe/Andorra 1993-12-23
+3041397 Bordes de BeixalÃs Bordes de Beixalis 42.53333 1.55 S FRMS AD 00 0 1344 Europe/Andorra 1993-12-23
+3041398 BeixalÃs Beixalis 42.53333 1.55 A ADMD AD 00 0 1344 Europe/Andorra 1993-12-23
+3041399 Comes Beçoses Comes Becoses 42.51667 1.6 H RVN AD 00 0 2085 Europe/Andorra 1993-12-23
+3041400 Planell dels Beços Planell dels Becos 42.61667 1.56667 T UPLD AD 00 0 2228 Europe/Andorra 1993-12-23
+3041401 Bosc del Becet Bosc del Becet 42.56667 1.53333 V FRST AD 00 0 1669 Europe/Andorra 1993-12-23
+3041402 Vial del Beç Vial del Bec 42.53333 1.46667 R TRL AD 00 0 1846 Europe/Andorra 1993-12-23
+3041403 Solana dels Batallats Solana dels Batallats 42.56667 1.51667 T SLP AD 00 0 1500 Europe/Andorra 1993-12-23
+3041404 Roc dels Batallassos Roc dels Batallassos 42.56667 1.6 T RK AD 00 0 1655 Europe/Andorra 1993-12-23
+3041405 Coll del Bast Coll del Bast 42.48333 1.48333 T PK AD 00 0 981 Europe/Andorra 1993-12-23
+3041406 Basses del Siscaró Basses del Siscaro 42.58333 1.7 L LCTY AD 00 0 2584 Europe/Andorra 1993-12-23
+3041407 Basses dels Basers Basses dels Basers 42.58333 1.7 L LCTY AD 00 0 2584 Europe/Andorra 1993-12-23
+3041408 Pales de les Basses de les Salamandres Pales de les Basses de les Salamandres 42.61667 1.66667 T SLP AD 00 0 2536 Europe/Andorra 1993-12-23
+3041409 Basses de la Burna Basses de la Burna 42.6 1.48333 T RKS AD 00 0 2441 Europe/Andorra 1993-12-23
+3041410 Planell de les Basses Planell de les Basses 42.55 1.58333 T UPLD AD 00 0 1499 Europe/Andorra 1993-12-23
+3041411 Pla de la Bassa de les Granotes Pla de la Bassa de les Granotes 42.58333 1.43333 T UPLD AD 00 0 2412 Europe/Andorra 1993-12-23
+3041412 Basers de l’Estany de Més Amunt Basers de l'Estany de Mes Amunt 42.6 1.46667 L LCTY AD 00 0 2421 Europe/Andorra 1993-12-23
+3041413 Basers de Font Blanca Basers de Font Blanca 42.65 1.55 L LCTY AD 00 0 2181 Europe/Andorra 1993-12-23
+3041414 Coll de Basers Coll de Basers 42.5 1.48333 T RDGE AD 00 0 1316 Europe/Andorra 1993-12-23
+3041415 Baser Negre Baser Negre 42.63333 1.46667 L LCTY AD 00 0 2324 Europe/Andorra 1993-12-23
+3041416 Cap del Baser de la Llonga Cap del Baser de la Llonga 42.56667 1.51667 T SPUR AD 00 0 1500 Europe/Andorra 1993-12-23
+3041417 Cap del Baser Cap del Baser 42.56667 1.51667 T SPUR AD 00 0 1500 Europe/Andorra 1993-12-23
+3041418 Canal de Bartreta Canal de Bartreta 42.55 1.6 H RVN AD 00 0 2210 Europe/Andorra 1993-12-23
+3041419 Bosc de les Bartres Bosc de les Bartres 42.51667 1.5 V FRST AD 00 0 1688 Europe/Andorra 1993-12-23
+3041420 Bosc de la Bartra Bosc de la Bartra 42.5 1.51667 V FRST AD 00 0 1410 Europe/Andorra 1993-12-23
+3041421 Pont dels Barrons Pont dels Barrons 42.61667 1.55 S BDG AD 00 0 2007 Europe/Andorra 1993-12-23
+3041422 Torrent del Barreró Torrent del Barrero 42.48333 1.46667 H STM AD 00 0 1148 Europe/Andorra 1993-12-23
+3041423 Bosc del Barrer d’Areny Bosc del Barrer d'Areny 42.58333 1.46667 V FRST AD 00 0 1643 Europe/Andorra 1993-12-23
+3041424 Barrer d’Areny Barrer d'Areny 42.58333 1.46667 L GRAZ AD 00 0 1643 Europe/Andorra 1993-12-23
+3041425 Roc del Barrer Roc del Barrer 42.55 1.53333 T SPUR AD 00 0 1593 Europe/Andorra 1993-12-23
+3041426 Canal del Barrer Canal del Barrer 42.56667 1.51667 H STM AD 00 0 1500 Europe/Andorra 1993-12-23
+3041427 Riu de la Barraca Cremada Riu de la Barraca Cremada 42.53333 1.7 H STM AD 00 0 2357 Europe/Andorra 1993-12-23
+3041428 Solà de Barra Sola de Barra 42.58333 1.65 T SLP AD 00 0 1767 Europe/Andorra 1993-12-23
+3041429 Prats de la Baronia Prats de la Baronia 42.53333 1.61667 L GRAZ AD 00 0 2237 Europe/Andorra 1993-12-23
+3041430 Planell de la Baronia Planell de la Baronia 42.53333 1.61667 T UPLD AD 00 0 2237 Europe/Andorra 1993-12-23
+3041431 Borda de la Baronia Borda de la Baronia 42.53333 1.61667 S HUT AD 00 0 2237 Europe/Andorra 1993-12-23
+3041432 Canal dels Banys Canal dels Banys 42.53333 1.5 H STM AD 00 0 1357 Europe/Andorra 1993-12-23
+3041433 Bosc dels Banys Bosc dels Banys 42.53333 1.5 V FRST AD 00 0 1357 Europe/Andorra 1993-12-23
+3041434 Port de Banyell Port de Banyell 42.64218 1.5777 T PASS AD 00 0 2365 Europe/Andorra 2011-04-19
+3041435 Font de Banyell Font de Banyell 42.63333 1.56667 H SPNG AD 00 0 2394 Europe/Andorra 1993-12-23
+3041436 Banyell Banyell 42.63333 1.56667 L LCTY AD 00 0 2394 Europe/Andorra 1993-12-23
+3041437 Bosc dels Bancs Bosc dels Bancs 42.48333 1.46667 V FRST AD 00 0 1148 Europe/Andorra 1993-12-23
+3041438 Riu del Bancal Vedeller Riu del Bancal Vedeller 42.6 1.46667 H STM AD 00 0 2421 Europe/Andorra 1993-12-23
+3041439 Basers del Bancal Vedeller Basers del Bancal Vedeller 42.6 1.45 T CLF AD 00 0 2174 Europe/Andorra 1993-12-23
+3041440 Plana del Banc Plana del Banc 42.43333 1.5 T UPLD AD 00 0 1804 Europe/Andorra 1993-12-23
+3041441 Font del Baladre Font del Baladre 42.58333 1.48333 H SPNG AD 00 0 1809 Europe/Andorra 1993-12-23
+3041442 Pont de la Baladosa Pont de la Baladosa 42.6 1.68333 S BDG AD 00 0 2089 Europe/Andorra 1993-12-23
+3041443 Baladosa Baladosa 42.58333 1.68333 L LCTY AD 00 0 2294 Europe/Andorra 1993-12-23
+3041444 Collades Baixes d’Emportona Collades Baixes d'Emportona 42.51667 1.65 T PASS AD 00 0 2633 Europe/Andorra 1993-12-23
+3041445 Collades Baixes Collades Baixes 42.5 1.63333 T PASS AD 00 0 2545 Europe/Andorra 1993-12-23
+3041446 Baixant Baixant 42.55 1.48333 L LCTY AD 00 0 1548 Europe/Andorra 1993-12-23
+3041447 Pleta de Baix Pleta de Baix 42.51667 1.61667 L GRAZ AD 00 0 2254 Europe/Andorra 1993-12-23
+3041448 Pleta de Baix Pleta de Baix 42.48333 1.43333 L GRAZ AD 00 0 1938 Europe/Andorra 1993-12-23
+3041449 Estany de Baix Estany de Baix 42.58333 1.7 H LK AD 00 0 2584 Europe/Andorra 1993-12-23
+3041450 Font de Baiter Font de Baiter 42.55 1.51667 H SPNG AD 00 0 1397 Europe/Andorra 1993-12-23
+3041451 Port de Baiau Port de Baiau Port de Baiau 42.6 1.43333 T PASS AD 00 0 2667 Europe/Andorra 2011-11-05
+3041452 Pic de Baiau Pic de Baiau Pic de Baiau 42.58333 1.43333 T PK AD 00 0 2412 Europe/Andorra 2011-11-05
+3041453 Agulla de Baiau Agulla de Baiau Agulla de Baiau 42.58333 1.43333 T PK AD 00 0 2412 Europe/Andorra 2011-11-05
+3041454 Planells de Baell Planells de Baell 42.48333 1.6 T UPLD AD 00 0 2250 Europe/Andorra 1993-12-23
+3041455 Font de Baell Font de Baell 42.5 1.61667 H SPNG AD 00 0 2560 Europe/Andorra 1993-12-23
+3041456 Pleta de les Bacives Pleta de les Bacives 42.5 1.65 L GRAZ AD 00 0 2542 Europe/Andorra 1993-12-23
+3041457 Serra de l’ Avier Serra de l' Avier 42.6 1.5 T RDGE AD 00 0 1923 Europe/Andorra 1993-12-23
+3041458 Plana de l’ Avier Plana de l' Avier 42.6 1.5 T UPLD AD 00 0 1923 Europe/Andorra 1993-12-23
+3041459 Obaga de l’ Avier Obaga de l' Avier 42.48333 1.53333 T SLP AD 00 0 2255 Europe/Andorra 1993-12-23
+3041460 Costa de l’ Avier Costa de l' Avier 42.56667 1.55 T SLP AD 00 0 1996 Europe/Andorra 1993-12-23
+3041461 Camà de l’ Avier Cami de l' Avier 42.48333 1.55 R TRL AD 00 0 2233 Europe/Andorra 1993-12-23
+3041462 Bosc de l’ Avier Bosc de l' Avier 42.48333 1.53333 V FRST AD 00 0 2255 Europe/Andorra 1993-12-23
+3041463 Torrent de l’ Aviar Torrent de l' Aviar 42.53333 1.56667 H STM AD 00 0 1418 Europe/Andorra 1993-12-23
+3041464 Canal de l’ Avetar Canal de l' Avetar 42.58333 1.65 H STM AD 00 0 1767 Europe/Andorra 1993-12-23
+3041465 Canal de l’ Avetar Canal de l' Avetar 42.5 1.48333 H STM AD 00 0 1316 Europe/Andorra 1993-12-23
+3041466 Bosc de l’ Avetar Bosc de l' Avetar 42.55 1.55 V FRST AD 00 0 2097 Europe/Andorra 1993-12-23
+3041467 Costa de Avet Costa de Avet 42.5 1.56667 T SLP AD 00 0 1776 Europe/Andorra 1993-12-23
+3041468 Canal de l’ Avet Canal de l' Avet 42.55 1.5 H STM AD 00 0 1292 Europe/Andorra 1993-12-23
+3041469 Costa de l’ Ave Maria Costa de l' Ave Maria 42.61667 1.53333 T SLP AD 00 0 1609 Europe/Andorra 1993-12-23
+3041470 Solà de l’ Avellanet Sola de l' Avellanet 42.58333 1.48333 T SLP AD 00 0 1809 Europe/Andorra 1993-12-23
+3041471 Costa dels Avellaners Costa dels Avellaners 42.56667 1.61667 T SLP AD 00 0 1920 Europe/Andorra 1993-12-23
+3041472 Canal dels Avellaners Canal dels Avellaners 42.58333 1.46667 H RVN AD 00 0 1643 Europe/Andorra 1993-12-23
+3041473 Coma Aubosa Coma Aubosa 42.58333 1.5 T SLP AD 00 0 1595 Europe/Andorra 1993-12-23
+3041474 Riu d’ Aubinyà Riu d' Aubinya 42.45 1.48333 H STM AD 00 0 1111 Europe/Andorra 1993-12-23
+3041475 Aubinyà Aubinya Aubinya,Aubinyà ,Auvinya 42.45447 1.48761 P PPL AD 06 0 1159 Europe/Andorra 2011-11-05
+3041476 Aubinyà Aubinya 42.45 1.5 A ADMD AD 00 0 1614 Europe/Andorra 1993-12-23
+3041477 Roc de les Aubes Roc de les Aubes 42.51667 1.55 T SPUR AD 00 0 1322 Europe/Andorra 1993-12-23
+3041478 Riu de les Aubes Riu de les Aubes 42.55 1.53333 H STM AD 00 0 1593 Europe/Andorra 1993-12-23
+3041479 Costa de l’ Aubell Costa de l' Aubell 42.56667 1.53333 T SLP AD 00 0 1669 Europe/Andorra 1993-12-23
+3041480 Aubaderes Aubaderes 42.5 1.48333 L LCTY AD 00 0 1316 Europe/Andorra 1993-12-23
+3041481 Roc de l’ Auba Roc de l' Auba 42.56667 1.5 T RK AD 00 0 1636 Europe/Andorra 1993-12-23
+3041482 Canal dels Astrells Canal dels Astrells 42.48333 1.56667 H STM AD 00 0 2231 Europe/Andorra 1993-12-23
+3041483 Riu de l’ Astrell Riu de l' Astrell 42.55 1.55 H STM AD 00 0 2097 Europe/Andorra 1993-12-23
+3041484 Cap de l’ Astrell Cap de l' Astrell 42.56667 1.56667 T SPUR AD 00 0 2089 Europe/Andorra 1993-12-23
+3041485 Bosc de l’ Astrell Bosc de l' Astrell 42.56667 1.56667 V FRST AD 00 0 2089 Europe/Andorra 1993-12-23
+3041486 Canals dels Assaladors dels Pletius Canals dels Assaladors dels Pletius 42.5 1.46667 H STM AD 00 0 1678 Europe/Andorra 1993-12-23
+3041487 Assaladors del Planell Gran Assaladors del Planell Gran 42.56667 1.46667 L LCTY AD 00 0 1673 Europe/Andorra 1993-12-23
+3041488 Assaladors de Cabana Sorda Assaladors de Cabana Sorda 42.6 1.66667 T PKS AD 00 0 1858 Europe/Andorra 1993-12-23
+3041489 Canal de l’ Assalador de Rei Canal de l' Assalador de Rei 42.55 1.46667 H STM AD 00 0 1585 Europe/Andorra 1993-12-23
+3041490 Bosc de l’ Assalador Bosc de l' Assalador 42.61667 1.65 V FRST AD 00 0 2567 Europe/Andorra 1993-12-23
+3041491 Bosc de l’ Assalador Bosc de l' Assalador 42.56667 1.6 V FRST AD 00 0 1655 Europe/Andorra 1993-12-23
+3041492 Bosc de l’ Assalador Bosc de l' Assalador 42.56667 1.58333 V FRST AD 00 0 1919 Europe/Andorra 1993-12-23
+3041493 Serra del Cap dels Aspres de Banyell Serra del Cap dels Aspres de Banyell 42.63333 1.56667 T MT AD 00 0 2394 Europe/Andorra 1993-12-23
+3041494 Aspres de Banyell Aspres de Banyell 42.63333 1.56667 L LCTY AD 00 0 2394 Europe/Andorra 1993-12-23
+3041495 Pic dels Aspres Pic dels Aspres Pic dels Aspres 42.56667 1.45 T PK AD 00 0 2562 2137 Europe/Andorra 2011-11-05
+3041496 Rocs de l’ Aspra Rocs de l' Aspra 42.53333 1.53333 T RKS AD 00 0 1521 Europe/Andorra 1993-12-23
+3041497 Riu de l’ Aspra Riu de l' Aspra 42.55 1.55 H STM AD 00 0 2097 Europe/Andorra 1993-12-23
+3041498 Clots de l’ Aspra Clots de l' Aspra 42.51667 1.63333 H RVN AD 00 0 2379 Europe/Andorra 1993-12-23
+3041499 Alt de l’ Aspra Alt de l' Aspra 42.51667 1.65 T SLP AD 00 0 2633 Europe/Andorra 1993-12-23
+3041500 Canals d’ Aspones Canals d' Aspones 42.61667 1.7 H RVN AD 00 0 2285 Europe/Andorra 1993-12-23
+3041501 Torrent dels Aspedius Torrent dels Aspedius 42.48333 1.53333 H STM AD 00 0 2255 Europe/Andorra 1993-12-23
+3041502 Comella Ascura Comella Ascura 42.45 1.45 H RVN AD 00 0 1482 Europe/Andorra 1993-12-23
+3041503 Rocs de l’ Ascobet Rocs de l' Ascobet 42.61667 1.51667 T RKS AD 00 0 1716 Europe/Andorra 1993-12-23
+3041504 Ascobar de Puntal Ascobar de Puntal 42.63333 1.55 L LCTY AD 00 0 2053 Europe/Andorra 1993-12-23
+3041505 Canal de les Asclades Canal de les Asclades 42.5 1.53333 H STM AD 00 0 1574 Europe/Andorra 1993-12-23
+3041506 Serrat de l’ Ascladella Serrat de l' Ascladella 42.53333 1.46667 T RDGE AD 00 0 1846 Europe/Andorra 1993-12-23
+3041507 Fontanal de l’ Ascladella Fontanal de l' Ascladella 42.53333 1.46667 H SPNG AD 00 0 1846 Europe/Andorra 1993-12-23
+3041508 Coma de l’ Ascladella Coma de l' Ascladella 42.56667 1.48333 T SLP AD 00 0 1508 Europe/Andorra 1993-12-23
+3041509 Torrent dels Artics Torrent dels Artics 42.55 1.58333 H STM AD 00 0 1499 Europe/Andorra 1993-12-23
+3041510 Artic de Capell Artic de Capell 42.58333 1.6 L LCTY AD 00 0 1828 Europe/Andorra 1993-12-23
+3041511 Font de l’ Artic Font de l' Artic 42.48333 1.5 H SPNG AD 00 0 1631 Europe/Andorra 1993-12-23
+3041512 Bony de l’ Artic Bony de l' Artic 42.55 1.55 T SPUR AD 00 0 2097 Europe/Andorra 1993-12-23
+3041513 Serrat de l’ Arna Tova Serrat de l' Arna Tova 42.58333 1.46667 T SPUR AD 00 0 1643 Europe/Andorra 1993-12-23
+3041514 Arna Tova Arna Tova 42.58333 1.46667 L LCTY AD 00 0 1643 Europe/Andorra 1993-12-23
+3041515 Bordes de l’ Armiana Bordes de l' Armiana 42.58333 1.6 S HUTS AD 00 0 1828 Europe/Andorra 1993-12-23
+3041516 Font de l’ Arinsola Font de l' Arinsola 42.48333 1.41667 H SPNG AD 00 0 1920 Europe/Andorra 1993-12-23
+3041517 Riu d’ Arinsal Riu d' Arinsal Riu d' Arinsal,Riu d' Arinsul,Riu d’ Arinsal,Riu d’ Arinsul 42.5456 1.51523 H STM AD 00 0 1257 Europe/Andorra 2011-11-05
+3041518 Port d’ Arinsal Port d' Arinsal Port d' Arinsal,Port d’ Arinsal 42.6 1.46667 T PASS AD 00 0 2421 Europe/Andorra 2011-11-05
+3041519 Arinsal Arinsal Arinsal,ÐринÑал 42.57205 1.48453 P PPL AD 04 1419 1655 Europe/Andorra 2010-01-29
+3041520 Canal de Argelagosa Canal de Argelagosa 42.51667 1.53333 H STM AD 00 0 1460 Europe/Andorra 1993-12-23
+3041521 Roc de l’ Areny Roc de l' Areny 42.56667 1.6 T PROM AD 00 0 1655 Europe/Andorra 1993-12-23
+3041522 Rec d’ Areny Rec d' Areny 42.58333 1.46667 H STM AD 00 0 1643 Europe/Andorra 1993-12-23
+3041523 Coll d’ Arenes Coll d' Arenes 42.6 1.58333 T PASS AD 00 0 2461 Europe/Andorra 1993-12-23
+3041524 Bassa de l’ Arena Bassa de l' Arena 42.51667 1.63333 H STMH AD 00 0 2379 Europe/Andorra 1993-12-23
+3041525 Font d’ Arduix Font d' Arduix Font d' Arduix,Font d’ Arduix 42.45 1.45 H SPNG AD 00 0 1482 Europe/Andorra 2011-11-05
+3041526 Solana d’ Arcavell Solana d' Arcavell Solana d' Arcabell,Solana d' Arcavell,Solana d’ Arcabell,Solana d’ Arcavell 42.43333 1.51667 T SLP AD 00 0 2031 Europe/Andorra 2011-11-05
+3041527 Serra d’ ArcalÃs Serra d' Arcalis 42.61667 1.5 T RDGE AD 00 0 2390 Europe/Andorra 1993-12-23
+3041528 Roc d’ ArcalÃs Roc d' Arcalis 42.63333 1.5 T RK AD 00 0 1979 Europe/Andorra 1993-12-23
+3041529 Riu d’ ArcalÃs Riu d' Arcalis 42.63333 1.5 H STM AD 00 0 1979 Europe/Andorra 1993-12-23
+3041530 Portella d’ ArcalÃs Portella d' Arcalis 42.61667 1.48333 T PASS AD 00 0 2470 Europe/Andorra 1993-12-23
+3041531 Pont d’ ArcalÃs Pont d' Arcalis 42.63333 1.5 S BDG AD 00 0 1979 Europe/Andorra 1993-12-23
+3041532 Pic d’ ArcalÃs Pic d' Arcalis 42.61575 1.4904 T PK AD 00 0 2431 Europe/Andorra 2011-04-19
+3041533 Feixans d’ ArcalÃs Feixans d' Arcalis 42.63333 1.5 V CULT AD 00 0 1979 Europe/Andorra 1993-12-23
+3041534 Collades d’ ArcalÃs Collades d' Arcalis 42.63333 1.51667 T PASS AD 00 0 1894 Europe/Andorra 1993-12-23
+3041535 Cabana d’ ArcalÃs Cabana d' Arcalis 42.63333 1.5 S HUT AD 00 0 1979 Europe/Andorra 1993-12-23
+3041536 Basers d’ ArcalÃs Basers d' Arcalis 42.61667 1.5 T CLF AD 00 0 2390 Europe/Andorra 1993-12-23
+3041537 Port de l’ Albeille Port de l' Albeille Port de l' Albeille,Port de l' Albelle,Port de l' Arbeille,Port de l' Arbella,Port de l’ Albeille,Port de l’ Albelle,Port de l’ Arbeille,Port de l’ Arbella,Porteille de l' Albelle,Porteille de l’ Albelle 42.65 1.5 T PASS AD 00 0 2455 Europe/Andorra 2011-11-05
+3041538 Canal de l’ Arbeguer Canal de l' Arbeguer 42.48333 1.43333 H STM AD 00 0 1938 Europe/Andorra 1993-12-23
+3041539 Pont d’ Arans Pont d' Arans 42.58333 1.51667 S BDG AD 00 0 1722 Europe/Andorra 1993-12-23
+3041540 Canals d’ Arans Canals d' Arans 42.58333 1.5 H RVN AD 00 0 1595 Europe/Andorra 1993-12-23
+3041541 Arans Arans Arans 42.58226 1.51844 P PPL AD 05 0 1722 Europe/Andorra 2011-11-05
+3041542 Coll de la Quell Coll de la Quell Coll de l' Aquell,Coll de la Quell,Coll de l’ Aquell 42.48333 1.41667 T PASS AD 00 0 1920 Europe/Andorra 2011-11-05
+3041543 Anyós Anyos 42.53458 1.52672 P PPL AD 04 0 1491 Europe/Andorra 2011-04-19
+3041544 Bosc Gran de l’ Any de la Part Bosc Gran de l' Any de la Part 42.55 1.51667 V FRST AD 00 0 1397 Europe/Andorra 1993-12-23
+3041545 Planell d’ Antònia Planell d' Antonia 42.51667 1.55 T UPLD AD 00 0 1322 Europe/Andorra 1993-12-23
+3041546 Ansalonga Ansalonga Ansalonga 42.56919 1.52285 P PPL AD 05 0 1500 Europe/Andorra 2011-11-05
+3041547 Serra d’ Anrodat Serra d' Anrodat 42.61667 1.68333 T RDGE AD 00 0 2406 Europe/Andorra 1993-12-23
+3041548 Pic de la Coume d’Enfer Pic de la Coume d'Enfer Pic d' Anrodat,Pic de la Coume d'Enfer,Pic de la Coume d’Enfer,Pic d’ Anrodat 42.61667 1.68333 T RDGE AD 00 0 2406 Europe/Andorra 2011-11-05
+3041549 Estany d’ Anrodat Estany d' Anrodat 42.61667 1.68333 H LK AD 00 0 2406 Europe/Andorra 1993-12-23
+3041550 Coll d’ Anrodat Coll d' Anrodat Coll d' Anrodat,Coll d’ Anrodat 42.61667 1.7 T PASS AD 00 0 2285 Europe/Andorra 2011-11-05
+3041551 Anrodat Anrodat 42.61667 1.68333 A ADMD AD 00 0 2406 Europe/Andorra 1993-12-23
+3041552 Riu de l’ Angonella Riu de l' Angonella 42.6 1.53333 H STM AD 00 0 1695 Europe/Andorra 1993-12-23
+3041553 Port de l’ Angonella Port de l' Angonella Port de l' Angonella,Port de l’ Angonella 42.61667 1.46667 T PASS AD 00 0 2442 Europe/Andorra 2011-11-05
+3041554 Pleta de l’ Angonella Pleta de l' Angonella 42.6 1.5 L GRAZ AD 00 0 1923 Europe/Andorra 1993-12-23
+3041555 Pas de l’ Angonella Pas de l' Angonella 42.6 1.5 T PASS AD 00 0 1923 Europe/Andorra 1993-12-23
+3041556 Estret del l’ Angonella Estret del l' Angonella 42.6 1.5 T GRGE AD 00 0 1923 Europe/Andorra 1993-12-23
+3041557 Estanys de l’ Angonella Estanys de l' Angonella 42.6 1.48333 H LKS AD 00 0 2441 Europe/Andorra 1993-12-23
+3041558 Basers de l’ Angonella Basers de l' Angonella 42.61667 1.5 T CLF AD 00 0 2390 Europe/Andorra 1993-12-23
+3041559 Pic de les Angleves Pic de les Angleves 42.55 1.53333 T PK AD 00 0 1593 Europe/Andorra 1993-12-23
+3041560 Solà de Angleva Sola de Angleva 42.56667 1.48333 T SLP AD 00 0 1508 Europe/Andorra 1993-12-23
+3041561 Planell de Andreuet Planell de Andreuet 42.51667 1.6 T UPLD AD 00 0 2085 Europe/Andorra 1993-12-23
+3041562 Barranc de l’ Andorrana Barranc de l' Andorrana 42.55 1.43333 H STM AD 00 0 1949 Europe/Andorra 1993-12-23
+3041563 Andorra la Vella Andorra la Vella Ando-la-Vyey,Andora,Andora la Vela,Andora la Velja,Andora lja Vehl'ja,Andoro Malnova,Andorra,Andorra Tuan,Andorra a Vella,Andorra la Biella,Andorra la Vella,Andorra la Vielha,Andorra-a-Velha,Andorra-la-Vel'ja,Andorra-la-Vielye,Andorre-la-Vieille,Andò-la-Vyèy,Andòrra la Vièlha,an dao er cheng,andolalabeya,andwra la fyla,ΑνδόÏÏα,Ðндора ла ВелÑ,Ðндора ла Веља,Ðндора Ð»Ñ Ð’ÑльÑ,Ðндорра-ла-ВельÑ,×× ×“×•×¨×” לה וולה,أندورا لا Ùيلا,አንዶራ ላ ቬላ,アンドラ・ラ・ヴェリャ,安é“爾城,안ë„ë¼ë¼ë² 야 42.50779 1.52109 P PPLC AD 07 20430 1073 Europe/Andorra 2010-05-30
+3041564 Rec d’ Andorra Rec d' Andorra 42.51667 1.51667 H CNL AD 00 0 1265 Europe/Andorra 1993-12-23
+3041565 Principality of Andorra Principality of Andorra Andora,Andoro,Andorra,Andorre,Andorrë,Andurra,Andòrra,Andóra,L'Andorre,Landoraen,Landorän,Les Vallees d' Andorre,Les Vallées d’ Andorre,L’Andorre,Principado de Andorra,Principality of Andorra,Principat d' Andorra,Principat d’ Andorra,Principaute d' Andorre,Principauté d’ Andorre,Vallees et Suzerainetes d' Andorre,Valls d' Andorra,Valls d’ Andorra,Vallées et Suzerainetés d’ Andorre,an dao er,andola,andora,andwra,antora,endora,prathes xandxrra,xandxrra,yandwrra,ΑνδόÏα,ΑνδόÏÏα,Ðндора,Ðндорра,Ô±Õ¶Õ¤Õ¸Ö€Õ¡,×× ×“×•×¨×”,آندورا,أندورا,ئاندوررا,اندورا,انډورا,ÜܢܕܘܪÜ,अंडोरा,अनà¥à¤¡à¥‹à¤°à¤¾,à¤à¤£à¥à¤¡à¥‹à¤°à¤¾,অà§à¦¯à¦¾à¦¨à§à¦¡à§‹à¦°à¦¾,আনà§à¦¡à§‹à¦°à¦¾,à¦à¦¨à§à¦¡à§‹à¦°à¦¾,அனà¯à®Ÿà¯‹à®°à®¾,à´…à´¨àµâ€à´Ÿàµ‹à´±,ประเทศà¸à¸±à¸™à¸”à¸à¸£à¹Œà¸£à¸²,à¸à¸±à¸™à¸”à¸à¸£à¹Œà¸£à¸²,àºàº±àº™àº”à»àº¥àº²,ཨེན་ཌོ་རà¼,áƒáƒœáƒ“áƒáƒ áƒ,አንዶራ,អង់ដូររា,អានដូរ៉ា,アンドラ,安é“å°”,安é“爾,안ë„ë¼ 42.5 1.5 A PCLI AD 00 84000 1135 Europe/Andorra 2011-11-05
+3041566 Parròquia d'Andorra la Vella Parroquia d'Andorra la Vella Andorra la Vella,Andorre-la-Vieille,Parroquia d'Andorra la Vella,Parròquia d'Andorra la Vella 42.5045 1.49414 A ADM1 AD 07 24211 1236 Europe/Andorra 2008-03-17
+3041567 Canal Ampla Canal Ampla 42.48333 1.63333 H STM AD 00 0 2296 Europe/Andorra 1993-12-23
+3041568 Canal Ampla Canal Ampla 42.48333 1.6 H STM AD 00 0 2250 Europe/Andorra 1993-12-23
+3041569 Bosc dels Amorriadors Bosc dels Amorriadors 42.53333 1.48333 V FRST AD 00 0 1677 Europe/Andorra 1993-12-23
+3041570 Solana de l’ Alzinar Solana de l' Alzinar 42.45 1.48333 T SLP AD 00 0 1111 Europe/Andorra 1993-12-23
+3041571 Serrat de l’ Alzinar Serrat de l' Alzinar 42.48333 1.46667 T MT AD 00 0 1148 Europe/Andorra 1993-12-23
+3041572 Canal de l’ Alzina Canal de l' Alzina 42.5 1.5 H STM AD 00 0 1135 Europe/Andorra 1993-12-23
+3041573 Rocs Alts Rocs Alts 42.56667 1.43333 T RKS AD 00 0 2402 Europe/Andorra 1993-12-23
+3041574 Costa de l’ Alt de la Capa Costa de l' Alt de la Capa 42.56667 1.46667 T SLP AD 00 0 1673 Europe/Andorra 1993-12-23
+3041575 Pala Alta Pala Alta 42.6 1.63333 T CLF AD 00 0 1893 Europe/Andorra 1993-12-23
+3041576 Terregalls de l’ Alt Terregalls de l' Alt 42.56667 1.45 T TAL AD 00 0 2137 Europe/Andorra 1993-12-23
+3041577 Terregalls de l’ Alt Terregalls de l' Alt 42.58333 1.43333 T SPUR AD 00 0 2412 Europe/Andorra 1993-12-23
+3041578 Font de l’ Alt Font de l' Alt 42.56667 1.46667 H SPNG AD 00 0 1673 Europe/Andorra 1993-12-23
+3041579 Cresta de l’ Alt Cresta de l' Alt 42.58333 1.45 T SPUR AD 00 0 2156 Europe/Andorra 1993-12-23
+3041580 Costes de l’ Alt Costes de l' Alt 42.56667 1.45 T SLP AD 00 0 2137 Europe/Andorra 1993-12-23
+3041581 Canals de l’ Alt Canals de l' Alt 42.58333 1.43333 H RVN AD 00 0 2412 Europe/Andorra 1993-12-23
+3041582 Canal de l’ Alt Canal de l' Alt 42.58333 1.45 H STM AD 00 0 2156 Europe/Andorra 1993-12-23
+3041583 Planell dels Alls Planell dels Alls 42.5 1.6 T UPLD AD 00 0 2416 Europe/Andorra 1993-12-23
+3041584 Roca de les Allaus Roca de les Allaus 42.63333 1.53333 T RKS AD 00 0 2072 Europe/Andorra 1993-12-23
+3041585 Bosc de les Allaus Bosc de les Allaus 42.53333 1.6 V FRST AD 00 0 1888 Europe/Andorra 1993-12-23
+3041586 Solà de l’ Allau Sola de l' Allau 42.6 1.53333 T SLP AD 00 0 1695 Europe/Andorra 1993-12-23
+3041587 Planell de l’ Allau Planell de l' Allau 42.56667 1.68333 T UPLD AD 00 0 2340 Europe/Andorra 1993-12-23
+3041588 Planell de l’ Allau Planell de l' Allau 42.51667 1.58333 T UPLD AD 00 0 1994 Europe/Andorra 1993-12-23
+3041589 Camà de l’ Allau Cami de l' Allau 42.58333 1.61667 R TRL AD 00 0 1707 Europe/Andorra 1993-12-23
+3041590 Roc de l’ Àliga Roc de l' Aliga 42.55 1.5 T RK AD 00 0 1292 Europe/Andorra 1993-12-23
+3041591 Roc de l’ Àliga Roc de l' Aliga 42.55 1.46667 T RK AD 00 0 1585 Europe/Andorra 1993-12-23
+3041592 Roc de l’ Àliga Roc de l' Aliga 42.46667 1.5 T RK AD 00 0 1383 Europe/Andorra 1993-12-23
+3041593 Pic de l’ Àliga Pic de l' Aliga 42.5 1.66667 T PK AD 00 0 2441 Europe/Andorra 1993-12-23
+3041594 Canal dels Alegrets Canal dels Alegrets 42.5 1.48333 H STM AD 00 0 1316 Europe/Andorra 1993-12-23
+3041595 Pont de l’ Aldosa Pont de l' Aldosa 42.55 1.51667 S BDG AD 00 0 1397 Europe/Andorra 1993-12-23
+3041596 Carretera de l’ Aldosa Carretera de l' Aldosa 42.58333 1.63333 R RD AD 00 0 1722 Europe/Andorra 1993-12-23
+3041597 Pont d’ Aixovall Pont d' Aixovall 42.48333 1.48333 S BDG AD 00 0 981 Europe/Andorra 1993-12-23
+3041598 Aixovall Aixovall Aixovall 42.46667 1.48333 P PPL AD 06 0 1134 Europe/Andorra 2011-11-05
+3041599 Solà d’ Aixirivall Sola d' Aixirivall 42.46667 1.5 T SLP AD 00 0 1383 Europe/Andorra 1993-12-23
+3041600 Riu d’ Aixirivall Riu d' Aixirivall 42.46667 1.5 H STM AD 00 0 1383 Europe/Andorra 1993-12-23
+3041601 Conreu d’ Aixirivall Conreu d' Aixirivall 42.46667 1.5 V CULT AD 00 0 1383 Europe/Andorra 1993-12-23
+3041602 Carretera d’ Aixirivall Carretera d' Aixirivall 42.45 1.48333 R RD AD 00 0 1111 Europe/Andorra 1993-12-23
+3041603 Bordes d’ Aixirivall Bordes d' Aixirivall 42.45 1.51667 S FRMS AD 00 0 1790 Europe/Andorra 1993-12-23
+3041604 Aixirivall Aixirivall Aixirivali,Aixirivall,Aixirvall,Eixirivall 42.46321 1.5029 P PPL AD 06 0 1357 Europe/Andorra 2011-11-05
+3041605 Riu Aixec Riu Aixec 42.58333 1.66667 H STM AD 00 0 2159 Europe/Andorra 1993-12-23
+3041606 Riu Aixec Riu Aixec 42.55 1.58333 H STM AD 00 0 1499 Europe/Andorra 1993-12-23
+3041607 Riu d’ Aixàs Riu d' Aixas 42.48333 1.46667 H STM AD 00 0 1148 Europe/Andorra 1993-12-23
+3041608 Bosc d’ Aixàs Bosc d' Aixas 42.48333 1.46667 V FRST AD 00 0 1148 Europe/Andorra 1993-12-23
+3041609 Aixàs Aixas 42.48333 1.46667 P PPL AD 06 0 1148 Europe/Andorra 1993-12-23
+3041610 Aixàs Aixas 42.48333 1.46667 A ADMD AD 00 0 1148 Europe/Andorra 1993-12-23
+3041611 Clots d’ Aixades Clots d' Aixades 42.58333 1.58333 H RVN AD 00 0 1993 Europe/Andorra 1993-12-23
+3041612 Coll de l’ Airola Coll de l' Airola 42.48333 1.46667 T PK AD 00 0 1148 Europe/Andorra 1993-12-23
+3041613 Bosc de l’ Airola Bosc de l' Airola 42.56667 1.56667 V FRST AD 00 0 2089 Europe/Andorra 1993-12-23
+3041614 Solà d’ Airet Sola d' Airet 42.45 1.45 T SLP AD 00 0 1482 Europe/Andorra 1993-12-23
+3041615 Bosc d’ Aigües Juntes Bosc d' Aigues Juntes 42.58333 1.46667 V FRST AD 00 0 1643 Europe/Andorra 1993-12-23
+3041616 Aigües Juntes Aigues Juntes 42.58333 1.46667 H CNFL AD 00 0 1643 Europe/Andorra 1993-12-23
+3041617 Pont de l’ Aiguerola Pont de l' Aiguerola 42.53333 1.61667 S BDG AD 00 0 2237 Europe/Andorra 1993-12-23
+3041618 Clots d’ Aigua Vella Clots d' Aigua Vella 42.6 1.63333 H RVN AD 00 0 1893 Europe/Andorra 1993-12-23
+3041619 Canal d’ Aigua Vella Canal d' Aigua Vella 42.6 1.63333 H STM AD 00 0 1893 Europe/Andorra 1993-12-23
+3041620 Basers d’ Aigua Vella Basers d' Aigua Vella 42.6 1.63333 T CLF AD 00 0 1893 Europe/Andorra 1993-12-23
+3041621 Riu d’ Aiguarebre Riu d' Aiguarebre 42.6 1.51667 H STM AD 00 0 1445 Europe/Andorra 1993-12-23
+3041622 Planell d’ Aiguarebre Planell d' Aiguarebre 42.61667 1.51667 T UPLD AD 00 0 1716 Europe/Andorra 1993-12-23
+3041623 Costa d’ Aiguarebre Costa d' Aiguarebre 42.61667 1.51667 T SLP AD 00 0 1716 Europe/Andorra 1993-12-23
+3041624 Costa dels Aiguaders Costa dels Aiguaders 42.5 1.43333 T SLP AD 00 0 1654 Europe/Andorra 1993-12-23
+3041625 Presa d’ Aigua Presa d' Aigua 42.5 1.58333 S DAM AD 00 0 1888 Europe/Andorra 1993-12-23
+3041626 Font de Les Agunes Font de Les Agunes 42.58333 1.46667 H SPNG AD 00 0 1643 Europe/Andorra 1993-12-23
+3041627 Borda de les Agunes Borda de les Agunes 42.58333 1.46667 S FRM AD 00 0 1643 Europe/Andorra 1993-12-23
+3041628 Planell de les Agudelles Planell de les Agudelles 42.56667 1.55 T UPLD AD 00 0 1996 Europe/Andorra 1993-12-23
+3041629 Pont dels Agrels Pont dels Agrels 42.55 1.48333 S BDG AD 00 0 1548 Europe/Andorra 1993-12-23
+3041630 Canal dels Agrels Canal dels Agrels 42.55 1.48333 H STM AD 00 0 1548 Europe/Andorra 1993-12-23
+3041631 Serrat de l’ Agraullet Serrat de l' Agraullet 42.53333 1.55 T RDGE AD 00 0 1344 Europe/Andorra 1993-12-23
+3041632 Riu de les Agols Riu de les Agols 42.53125 1.59204 H STM AD 00 0 1756 Europe/Andorra 2011-04-19
+3041633 Coll dels Abòs Coll dels Abos 42.61667 1.53333 T PK AD 00 0 1609 Europe/Andorra 1993-12-23
+3041634 Riu de l’ Abeurador Riu de l' Abeurador 42.58333 1.65 H STM AD 00 0 1767 Europe/Andorra 1993-12-23
+3041635 Clot de les Abelletes Clot de les Abelletes 42.53333 1.73333 T CRQ AD 00 0 2300 Europe/Andorra 1993-12-23
+3041636 Serra del Cap de l’ Abarsetar de Rialb Serra del Cap de l' Abarsetar de Rialb 42.63333 1.55 T RDGE AD 00 0 2053 Europe/Andorra 1993-12-23
+3041637 Abarsetar de Rialb Abarsetar de Rialb 42.65 1.55 L LCTY AD 00 0 2181 Europe/Andorra 1993-12-23
+3041638 Abarsetar de la Coma Abarsetar de la Coma 42.62793 1.48624 L LCTY AD 07 0 2111 Europe/Andorra 2007-03-04
+3041639 Abarsetar de Ferreroles Abarsetar de Ferreroles 42.6 1.55 L LCTY AD 00 0 2298 Europe/Andorra 1993-12-23
+3041640 Abarsetar d'ArcalÃs Abarsetar d'Arcalis 42.62657 1.50148 L LCTY AD 07 0 1979 Europe/Andorra 2007-03-04
+3041641 Clots de l’ Abarsetar Clots de l' Abarsetar 42.63333 1.55 H RVN AD 00 0 2053 Europe/Andorra 1993-12-23
+3041642 Abarsetar Abarsetar 42.55 1.65 L LCTY AD 00 0 2432 Europe/Andorra 1993-12-23
+3041643 Pla de l’ Abarsa Pla de l' Abarsa 42.43333 1.51667 T UPLD AD 00 0 2031 Europe/Andorra 1993-12-23
+3041644 Costa de l’ Abalançc Costa de l' Abalancc 42.53333 1.53333 T SLP AD 00 0 1521 Europe/Andorra 1993-12-23
+3109332 Riu d’ Ós Riu d' Os Rio Saturia,Rio Seturia,Rio de Os,Riu d' Os,Riu d’ Ós,RÃo Saturia,RÃo Seturia,RÃo de Os 42.46667 1.5 H STM AD 00 0 1383 Europe/Andorra 2011-11-06
+3338529 Parròquia d'Escaldes-Engordany Parroquia d'Escaldes-Engordany Escaldes-Engordany,Parroquia d'Escaldes-Engordany,Parròquia d'Escaldes-Engordany 42.5 1.56667 A ADM1 AD 08 16391 1776 Europe/Andorra 2008-03-17
+6463133 Eurotel Eurotel 42.51286 1.53552 S HTL AD 07 0 1139 Europe/Andorra 2011-04-02
+6463689 Panorama Hotel Panorama Hotel 42.5069 1.5361 S HTL AD 07 0 1350 Europe/Andorra 2007-04-13
+6463694 Roc Blanc Hotel Roc Blanc Hotel 42.50927 1.53862 S HTL AD 07 0 1139 Europe/Andorra 2011-04-02
+6464858 Ahotels Prisma Ahotels Prisma 42.5087 1.5364 S HTL AD 07 0 1139 Europe/Andorra 2007-04-13
+6465286 Andorra Park Hotel Andorra Park Hotel 42.5092 1.5244 S HTL AD 07 0 1097 Europe/Andorra 2007-04-13
+6473225 Coma Coma 42.559 1.533 S HTL AD 07 0 1514 Europe/Andorra 2007-04-17
+6473433 Magic La Massana Magic La Massana 42.546 1.518 S HTL AD 07 0 1397 Europe/Andorra 2007-04-17
+6473450 Art Art 42.5062 1.5216 S HTL AD 07 0 1073 Europe/Andorra 2007-04-17
+6473528 Andorra Center Andorra Center 42.5074 1.52 S HTL AD 07 0 1073 Europe/Andorra 2007-04-17
+6473529 Hotel Cervol Hotel Cervol 42.50262 1.51288 S HTL AD 07 0 1011 Europe/Andorra 2011-04-02
+6473530 Novotel Andorra Novotel Andorra 42.50762 1.52734 S HTL AD 07 0 1205 Europe/Andorra 2011-04-03
+6473617 Roc del Sola Roc del Sola 42.505 1.514 S HTL AD 07 0 1011 Europe/Andorra 2007-04-17
+6473823 L'Angel Blanc L'Angel Blanc 42.577 1.667 S HTL AD 07 0 2159 Europe/Andorra 2007-04-17
+6473970 Refugi dels Isards Refugi dels Isards 42.50616 1.5289 S HTL AD 07 0 1205 Europe/Andorra 2007-04-17
+6474116 Panorama Panorama 42.507 1.535 S HTL AD 07 0 1350 Europe/Andorra 2007-04-17
+6474117 Font d'Argent Font d'Argent 42.542 1.732 S HTL AD 0 2100 Europe/Paris 2009-09-07
+6474170 Reial Pirineus Reial Pirineus 42.5405 1.7313 S HTL AD 0 2187 Europe/Paris 2009-06-28
+6474171 Hotansa Himalaya Hotansa Himalaya 42.5405 1.7313 S HTL AD 0 2187 Europe/Paris 2009-09-07
+6474212 F and G La Cabana F and G La Cabana 42.551 1.533 S HTL AD 07 0 1340 Europe/Andorra 2007-04-17
+6474230 Pic Maia Pic Maia 42.5075 1.5218 S HTL AD 07 0 1073 Europe/Andorra 2007-04-17
+6474307 Marco Polo Marco Polo 42.5411 1.5191 S HTL AD 07 0 1343 Europe/Andorra 2007-04-17
+6474384 Confort Pas de la Casa Confort Pas de la Casa 42.5413 1.7326 S HTL AD 0 2187 Europe/Paris 2009-09-07
+6474447 Magic Pas Magic Pas 42.54303 1.73188 S HTL AD 0 2100 Europe/Paris 2011-04-02
+6474512 Font del Marge Font del Marge 42.5043 1.5146 S HTL AD 07 0 1011 Europe/Andorra 2007-04-17
+6474514 Sant Jordi Sant Jordi 42.5043 1.5146 S HTL AD 07 0 1011 Europe/Andorra 2007-04-17
+6474580 AnyósPark AnyosPark 42.53417 1.52528 S HTL AD 04 0 1491 Europe/Andorra 2011-04-02
+6474582 Alaska Alaska 42.61877 1.53922 S HTL AD 07 0 1704 Europe/Andorra 2007-04-17
+6474659 President President 42.502 1.512 S HTL AD 07 0 1011 Europe/Andorra 2007-04-17
+6474661 Himalaia Soldeu Himalaia Soldeu 42.57647 1.66873 S HTL AD 07 0 2159 Europe/Andorra 2011-04-02
+6474662 Piolets Piolets 42.5769 1.66776 S HTL AD 07 0 2159 Europe/Andorra 2007-04-17
+6475094 Servissim Servissim 42.566 1.596 S HTL AD 07 0 1677 Europe/Andorra 2007-04-17
+6475095 Artic Artic 42.5054 1.5183 S HTL AD 07 0 1073 Europe/Andorra 2007-04-17
+6475301 Magic Ski Magic Ski 42.54557 1.51746 S HTL AD 07 0 1397 Europe/Andorra 2007-04-17
+6475379 Sporting Sporting 42.5075 1.5218 S HTL AD 07 0 1073 Europe/Andorra 2007-04-17
+6483664 Hotel Apsis Florida Hotel Apsis Florida 42.50811 1.52255 S HTL AD 07 0 1073 Europe/Andorra 2007-04-15
+6483820 Hotel Apsis Art Hotel Hotel Apsis Art Hotel 42.5 1.51667 S HTL AD 07 0 1410 Europe/Andorra 2007-04-15
+6491562 Hotel Delfos Hotel Delfos 42.50682 1.5344 S HTL AD 07 0 1350 Europe/Andorra 2011-04-02
+6491674 Hotel Fénix Hotel Fenix 42.5086 1.5394 S HTL AD 07 0 1139 Europe/Andorra 2007-04-15
+6491682 Hotel Comtes d'Urgell Hotel Comtes d'Urgell 42.51028 1.54099 S HTL AD 07 0 1139 Europe/Andorra 2011-04-02
+6492312 Ahotels Princep Ahotels Princep 42.5073 1.5316 S HTL AD 07 0 1205 Europe/Andorra 2007-04-15
+6493558 Club Dorada el Tarter Club Dorada el Tarter 42.5793 1.6414 S HTL AD 07 0 1727 Europe/Andorra 2007-04-14
+6493930 Residence Deusol Residence Deusol 42.6195 1.5389 S HTL AD 07 0 1704 Europe/Andorra 2007-04-14
+6493995 HUSA Centric HUSA Centric 42.5087 1.5283 S HTL AD 07 0 1041 Europe/Andorra 2007-04-14
+6494290 HUSA Xalet Besoli HUSA Xalet Besoli 42.5718 1.4843 S HTL AD 07 0 1655 Europe/Andorra 2007-04-14
+6494345 HUSA Imperial HUSA Imperial 42.472 1.4923 S HTL AD 06 0 1164 Europe/Andorra 2010-01-12
+6494491 Hotel Marco Polo Hotel Marco Polo 42.5423 1.5174 S HTL AD 07 0 1397 Europe/Andorra 2007-04-14
+6494790 Husa Xalet Verdu Husa Xalet Verdu 42.571 1.4715 S HTL AD 07 0 1673 Europe/Andorra 2007-04-14
+6494958 Apsis Arthotel Apsis Arthotel 42.5072 1.5261 S HTL AD 07 0 1205 Europe/Andorra 2007-04-14
+6495028 Hotel Himalaia Pas Hotel Himalaia Pas 42.5403 1.7311 S HTL AD 0 2187 Europe/Paris 2009-07-01
+6495053 Hotel Font Hotel Font 42.5436 1.5117 S HTL AD 07 0 1257 Europe/Andorra 2007-04-14
+6495582 Hotel Austria Hotel Austria 42.5788 1.6686 S HTL AD 07 0 2159 Europe/Andorra 2007-04-14
+6495704 Hotel Magic Canillo Hotel Magic Canillo 42.5638 1.5965 S HTL AD 07 0 1677 Europe/Andorra 2007-04-14
+6495769 Hotel F&G La Cabana Hotel F&G La Cabana 42.5538 1.5319 S HTL AD 07 0 1340 Europe/Andorra 2007-04-14
+6495790 Hotel Princesa Parc Hotel Princesa Parc 42.574 1.4824 S HTL AD 07 0 1508 Europe/Andorra 2007-04-14
+6495826 Hotel Magic La Massana Hotel Magic La Massana 42.5448 1.5163 S HTL AD 07 0 1257 Europe/Andorra 2007-04-14
+6497139 AHotels Confort Patagonia AHotels Confort Patagonia 42.5627 1.4952 S HTL AD 07 0 1430 Europe/Andorra 2007-04-14
+6497391 Hotel Magic Andorra Hotel Magic Andorra 42.5091 1.5297 S HTL AD 07 0 1041 Europe/Andorra 2007-04-14
+6497888 Ahotels Piolets Park & Spa Ahotels Piolets Park & Spa 42.5772 1.6652 S HTL AD 07 0 1925 Europe/Andorra 2007-04-14
+6498453 Hotel Carlton Plaza Hotel Carlton Plaza 42.508 1.5254 S HTL AD 07 0 1205 Europe/Andorra 2007-04-14
+6498890 Hotel Plaza Hotel Plaza 42.5062 1.5296 S HTL AD 07 0 1205 Europe/Andorra 2007-04-14
+6499190 Hotel Ski Plaza Hotel Ski Plaza 42.5657 1.5973 S HTL AD 07 0 1677 Europe/Andorra 2007-04-14
+6500087 Hesperia Andorra la Vella Hesperia Andorra la Vella 42.5089 1.5289 S HTL AD 07 0 1041 Europe/Andorra 2007-04-14
+6501396 Ahotels El Serrat Ahotels El Serrat 42.61652 1.53833 S HTL AD 07 0 1793 Europe/Andorra 2009-06-25
+6502212 Hotel Euro Esqui Hotel Euro Esqui 42.5794 1.6585 S HTL AD 07 0 1925 Europe/Andorra 2007-04-14
+6504216 Abba Xalet Suites Abba Xalet Suites 42.5331 1.516 S HTL AD 07 0 1211 Europe/Andorra 2007-04-14
+6505101 Hotel Valira HOTEL VALIRA 42.5 1.5333 S HTL AD 07 0 1574 Europe/Andorra 2007-04-13
+6508304 Mercure Andorra 4 MERCURE ANDORRA 4 42.5 1.5166 S HTL AD 07 0 1230 Europe/Andorra 2007-04-13
+6520395 Ahotels Confort Patagonia AHOTELS CONFORT PATAGONIA 42.5124 1.5389 S HTL AD 07 0 1139 Europe/Andorra 2007-04-15
+6521569 Ahotels El Serrat AHOTELS EL SERRAT 42.5575 1.5325 S HTL AD 07 0 1340 Europe/Andorra 2007-04-15
+6522685 Salvia D Or Hotel SALVIA D OR HOTEL 42.5 1.5166 S HTL AD 07 0 1230 Europe/Andorra 2007-04-14
+6525900 Roc De Caldes ROC DE CALDES 42.51065 1.54706 S HTL AD 07 0 1227 Europe/Andorra 2011-04-03
+6529214 Metropolis METROPOLIS 42.5166 1.55 S HTL AD 07 0 1498 Europe/Andorra 2007-04-14
+6529355 Diplomatic DIPLOMATIC 42.50521 1.52715 S HTL AD 07 0 1205 Europe/Andorra 2011-04-02
+6529413 Eureka EUREKA 42.50873 1.53989 S HTL AD 07 0 1139 Europe/Andorra 2011-04-02
+6529930 Cassany CASSANY 42.50798 1.5248 S HTL AD 07 0 1073 Europe/Andorra 2011-04-02
+6942550 Andorra Palace ANDORRA PALACE 42.50837 1.52706 S HTL AD 07 0 1041 Europe/Andorra 2009-06-24
+6942551 Annapurna ANNAPURNA 42.55768 1.53255 S HTL AD 07 0 1340 Europe/Andorra 2009-06-24
+6942562 Bringue BRINGUE 42.55768 1.53255 S HTL AD 07 0 1340 Europe/Andorra 2009-06-25
+6942564 Co Princeps CO PRINCEPS 42.46815 1.49329 S HTL AD 06 0 1164 Europe/Andorra 2010-01-12
+6942568 Crowne Plaza Andorra CROWNE PLAZA ANDORRA 42.50574 1.52002 S HTL AD 07 0 1073 Europe/Andorra 2009-06-25
+6942569 Diana Parc Diana Parc 42.5444 1.5115 S HTL AD 07 0 1257 Europe/Andorra 2009-06-25
+6942578 Encamp Encamp 42.53321 1.57914 S HTL AD 0 1571 Europe/Andorra 2009-06-25
+6942579 Diana parc Diana parc 42.61886 1.53939 S HTL AD 07 0 1704 Europe/Andorra 2009-06-25
+6942582 Font d'argent Canillo Font d'argent Canillo 42.57086 1.60782 S HTL AD 0 1655 Europe/Andorra 2011-04-03
+6942589 GRAU ROIG GRAU ROIG 42.5327 1.70116 S HTL AD 0 2357 Europe/Andorra 2009-06-25
+6942604 Husa Patagonia Husa Patagonia 42.57139 1.48566 S HTL AD 07 0 1655 Europe/Andorra 2009-06-26
+6942646 Ibis Andorra Ibis Andorra 42.51252 1.55059 S HTL AD 07 0 1498 Europe/Andorra 2011-04-03
+6942647 Lake placid Lake placid 42.54119 1.73333 S HTL AD 0 2187 Europe/Paris 2009-06-28
+6942648 Les closes Les closes 42.5087 1.53993 S HTL AD 07 0 1139 Europe/Andorra 2009-06-28
+6942649 L Isard L Isard 42.50775 1.52288 S HTL AD 07 0 1073 Europe/Andorra 2009-06-28
+6942650 Paris Paris 42.528 1.56927 S HTL AD 0 1418 Europe/Andorra 2009-06-28
+6942651 Pere D Urg Pere D Urg 42.5347 1.58012 S HTL AD 0 1309 Europe/Andorra 2009-06-28
+6942667 Prat de les mines Prat de les mines 42.59406 1.52684 S HTL AD 07 0 1695 Europe/Andorra 2009-06-28
+6942674 Rialb Rialb 42.61886 1.53939 S HTL AD 07 0 1704 Europe/Andorra 2009-06-28
+6942675 Rutllan Rutllan 42.54738 1.51345 S HTL AD 04 0 1257 Europe/Andorra 2009-06-28
+6942676 Sant Eloi Sant Eloi 42.45793 1.48717 S HTL AD 0 1159 Europe/Madrid 2011-04-02
+6942677 Shusski Shusski 42.5338 1.58577 S HTL AD 0 1490 Europe/Andorra 2009-06-28
+6942678 Solana Solana 42.58099 1.5193 S HTL AD 0 1722 Europe/Andorra 2009-06-28
+6942680 Somriu Comapedrosa Somriu Comapedrosa 42.58099 1.5193 S HTL AD 0 1722 Europe/Andorra 2009-06-28
+6942681 Somriu Galanthus Somriu Galanthus 42.5769 1.66776 S HTL AD 07 0 2159 Europe/Andorra 2009-06-28
+6942682 Les Terres Les Terres 42.57916 1.63023 S HTL AD 0 1722 Europe/Andorra 2011-04-02
+6942683 Somriu Segle Xx SOMRIU SEGLE XX 42.58118 1.63827 S HTL AD 0 1727 Europe/Andorra 2009-09-08
+6942684 Somriu Solana Del Ransol SOMRIU SOLANA DEL RANSOL 42.58002 1.64432 S HTL AD 07 0 1737 Europe/Andorra 2009-06-28
+6942685 Somriu Tivoli SOMRIU TIVOLI 42.5076 1.53223 S HTL AD 07 0 1205 Europe/Andorra 2009-06-28
+6942686 Somriu Vall Ski Somriu Vall Ski 42.57723 1.66752 S HTL AD 07 0 2159 Europe/Andorra 2009-06-28
+6942696 Sport Sport 42.57688 1.66688 S HTL AD 07 0 2159 Europe/Andorra 2009-06-29
+6942697 Sport Hermitage SPORT HERMITAGE 42.57727 1.6672 S HTL AD 07 0 2159 Europe/Andorra 2009-06-29
+6942698 Sport Village Sport Village 42.57688 1.66688 S HTL AD 07 0 2159 Europe/Andorra 2009-06-29
+6942740 APARTAMENTS TURISTICS GLAÇ APARTAMENTS TURISTICS GLAC 42.58 1.64623 S HTL AD 07 0 1737 Europe/Andorra 2009-06-30
+6942759 Aparthotel Cosmos Aparthotel Cosmos 42.51 1.541 S HTL AD 07 0 1139 Europe/Andorra 2009-06-30
+6942761 Carlemany Carlemany 42.509 1.538 S HTL AD 07 0 1139 Europe/Andorra 2009-06-30
+6942762 Cims Andorra Cims Andorra 42.5085 1.5307 S HTL AD 07 0 1041 Europe/Andorra 2009-06-30
+6942764 Folch Folch 42.471 1.493 S HTL AD 06 0 1164 Europe/Andorra 2010-01-12
+6942766 Hotel La Solana Hotel La Solana 42.533 1.593 S HTL AD 07 0 1756 Europe/Andorra 2009-09-07
+6942767 Phoebus Phoebus 42.54103 1.72985 S HTL AD 0 2187 Europe/Paris 2009-06-30
+6942768 Pol Pol 42.465 1.491 S HTL AD 06 0 1045 Europe/Andorra 2009-06-30
+6942770 Subira Subira 42.632 1.5 S HTL AD 0 1979 Europe/Andorra 2009-06-30
+6942771 Vip Plus Vip Plus 42.535 1.588 S HTL AD 0 1490 Europe/Andorra 2009-06-30
+6942793 Acta Arthotel Acta Arthotel 42.50728 1.52609 S HTL AD 07 0 1205 Europe/Andorra 2009-07-01
+6942794 Ahotels Patagonia Austral Ahotels Patagonia Austral 42.57246 1.48436 S HTL AD 07 0 1655 Europe/Andorra 2009-07-01
+6942796 Del Tarter Del Tarter 42.58035 1.64893 S HTL AD 07 0 1737 Europe/Andorra 2009-07-01
+6942797 Hotel Llop Gris Hotel Llop Gris 42.57804 1.64845 S HTL AD 07 0 1737 Europe/Andorra 2009-07-01
+6948955 Apartamentos Xixerella APARTAMENTOS XIXERELLA 42.55309 1.48746 S HTL AD 04 0 1520 Europe/Andorra 2009-09-07
+6948956 Apartaments Gla APARTAMENTS GLA 42.56 1.67396 S HTL AD 0 1963 Europe/Andorra 2009-09-07
+6948957 Boston Boston 42.6083 1.5394 S HTL AD 07 0 1821 Europe/Andorra 2009-09-07
+6948958 Coma Bella COMA BELLA 42.46487 1.49115 S HTL AD 06 0 1045 Europe/Andorra 2009-09-07
+6948959 Confort Soldeu CONFORT SOLDEU 42.5769 1.66776 S HTL AD 07 0 2159 Europe/Andorra 2009-09-07
+6948960 Coray CORAY 42.535 1.584 S HTL AD 0 1490 Europe/Andorra 2009-09-07
+6948963 Del Clos Del Clos 42.6187 1.5392 S HTL AD 07 0 1704 Europe/Andorra 2009-09-07
+6948965 El Xalet EL XALET 42.58035 1.64892 S HTL AD 07 0 1737 Europe/Andorra 2009-09-07
+6948966 Els Llacs ELS LLACS 42.56012 1.68173 S HTL AD 0 2094 Europe/Andorra 2009-09-07
+6948967 Els Meners ELS MENERS 42.566 1.596 S HTL AD 07 0 1677 Europe/Andorra 2009-09-07
+6948968 Espel Espel 42.509 1.542 S HTL AD 07 0 1227 Europe/Andorra 2009-09-07
+6948969 Euro Ski Euro Ski 42.6187 1.5392 S HTL AD 07 0 1704 Europe/Andorra 2009-09-07
+6948970 Guillen Guillen 42.536 1.583 S HTL AD 0 1309 Europe/Andorra 2009-09-07
+6948971 Hotansa Austria HOTANSA AUSTRIA 42.56012 1.68173 S HTL AD 0 2094 Europe/Andorra 2009-09-07
+6948972 Iglu IGLU 42.53263 1.70035 S HTL AD 0 2357 Europe/Andorra 2009-09-07
+6948973 Kandahar KANDAHAR 42.5413 1.7325 S HTL AD 0 2187 Europe/Paris 2009-09-07
+6948974 L Obaga Blanca L OBAGA BLANCA 42.5617 1.60352 S HTL AD 0 1969 Europe/Andorra 2009-09-07
+6948975 Montecarlo MONTECARLO 42.528 1.569 S HTL AD 0 1418 Europe/Andorra 2009-09-07
+6948976 Naudi Naudi 42.6187 1.5392 S HTL AD 07 0 1704 Europe/Andorra 2009-09-07
+6948977 Nordic NORDIC 42.58035 1.64892 S HTL AD 07 0 1737 Europe/Andorra 2009-09-07
+6948991 Hotel Oros Hotel Oros 42.54564 1.73176 S HTL AD 0 2100 Europe/Paris 2011-04-03
+6948993 Palome Palome 42.56148 1.49741 S HTL AD 07 0 1430 Europe/Andorra 2009-09-08
+6948995 Paradis Blanc PARADIS BLANC 42.54152 1.73378 S HTL AD 0 2385 Europe/Paris 2009-09-08
+6948996 Rutllan Xalet De Muntanya RUTLLAN XALET DE MUNTANYA 42.5479 1.51319 S HTL AD 04 0 1257 Europe/Andorra 2009-09-08
+6948997 Sant Bernat Apartments SANT BERNAT APARTMENTS 42.56609 1.5967 S HTL AD 07 0 1677 Europe/Andorra 2009-09-08
+6948998 Solana de ransol Solana de ransol 42.57831 1.6352 S HTL AD 0 1727 Europe/Andorra 2009-09-08
+6948999 Soldeu Maistre Soldeu Maistre 42.5769 1.66776 S HTL AD 07 0 2159 Europe/Andorra 2009-09-08
+6949002 St Gothard ST GOTHARD 42.5723 1.484 S HTL AD 07 0 1655 Europe/Andorra 2009-09-08
+6949004 Univers Univers 42.53647 1.58195 S HTL AD 0 1309 Europe/Andorra 2009-09-08
+6949005 Velvet Velvet 42.7467 1.7081 S HTL AD 0 1563 Europe/Paris 2009-09-08
+6949010 Xalet Montana Xalet Montana 42.57701 1.66627 S HTL AD 07 0 1925 Europe/Andorra 2009-09-08
+7114070 andorra magica andorra magica 42.50727 1.52202 S HTL AD 07 0 1073 Europe/Andorra 2009-12-02
+7284857 Apartamentos L Angel Blanc Apartamentos L Angel Blanc 42.577 1.667 S HTL AD 07 0 2159 Europe/Andorra 2010-04-01
+7284858 Apartamentos Giberga Apartamentos Giberga 42.552 1.51081 S HTL AD 0 1400 Europe/Andorra 2010-04-01
+7284859 Aparthotel l'Alba Aparthotel l'Alba 42.5787 1.6532 S HTL AD 02 0 1767 Europe/Andorra 2010-04-01
+7284866 Magic Canillo Apartments Magic Canillo Apartments 42.5669 1.60041 S HTL AD 02 0 1655 Europe/Andorra 2010-04-01
+7284867 Apartaments Sant Romà Apartaments Sant Roma 42.5736 1.48311 S HTL AD 0 1508 Europe/Andorra 2010-04-01
+7284869 Saporo Saporo 42.5432 1.73327 S HTL AD 03 0 2100 Europe/Paris 2010-04-01
+7284872 Aparthotel Casa Vella Aparthotel Casa Vella 42.5537 1.53215 S HTL AD 0 1340 Europe/Andorra 2010-04-01
+7284874 Caldea Centre Termolùdic d' Andorra Caldea Centre Termoludic d' Andorra 42.5117 1.5367 S HTL AD 07 0 1139 Europe/Andorra 2010-04-01
+7284875 Comabella Hotel Comabella Hotel 42.5 1.5166 S HTL AD 07 0 1230 Europe/Andorra 2010-04-01
+7284915 Hotel Galanthus Hotel Galanthus 42.5829 1.66268 S HTL AD 02 0 1925 Europe/Andorra 2010-04-02
+7284920 Hotel Cims Pas Hotel Cims Pas 42.5428 1.73479 S HTL AD 03 0 2230 Europe/Paris 2010-04-02
+7284921 Hotel Cims Pas de La Casa Hotel Cims Pas de La Casa 42.5428 1.73479 S HTL AD 03 0 2230 Europe/Paris 2010-04-02
+7284925 Hotel del Clos Hotel del Clos 42.5786 1.65121 S HTL AD 02 0 1767 Europe/Andorra 2010-04-02
+7284926 Hotel Erts Hotel Erts 42.5454 1.51909 S HTL AD 07 0 1397 Europe/Andorra 2010-04-02
+7284927 Hotel Font De Ferro Hotel Font De Ferro 42.5902 1.52436 S HTL AD 0 1525 Europe/Andorra 2010-04-02
+7284952 Magic Ski La Massana Hotel Magic Ski La Massana Hotel 42.5457 1.51838 S HTL AD 07 0 1397 Europe/Andorra 2010-04-04
+7284953 Hotel Metropolis Hotel Metropolis 42.5102 1.54086 S HTL AD 07 0 1139 Europe/Andorra 2010-04-04
+7284954 Hotel Palarine Hotel Palarine 42.5763 1.5187 S HTL AD 0 1722 Europe/Andorra 2010-04-04
+7284955 Hotel Paris Londres Hotel Paris Londres 42.5087 1.54083 S HTL AD 07 0 1139 Europe/Andorra 2010-04-04
+7284956 Hotel Parma Hotel Parma 42.5432 1.73297 S HTL AD 03 0 2100 Europe/Paris 2010-04-04
+7284957 Residència Daina Residencia Daina 42.5615 1.49775 S HTL AD 0 1430 Europe/Andorra 2010-04-04
+7284958 Hotel Roc del Castell Hotel Roc del Castell 42.566 1.596 S HTL AD 07 0 1677 Europe/Andorra 2010-04-04
+7284959 Hotel Siracusa Hotel Siracusa 42.509 1.54305 S HTL AD 07 0 1227 Europe/Andorra 2010-04-04
+7284960 Somriu Hotel Refugi dels Isards Somriu Hotel Refugi dels Isards 42.5433 1.73494 S HTL AD 03 0 2230 Europe/Paris 2010-04-04
+7284961 Sport Hotel Hermitage & Spa Sport Hotel Hermitage & Spa 42.5763 1.66991 S HTL AD 07 0 2159 Europe/Andorra 2010-04-04
+7284962 Hotel Tristaina Hotel Tristaina 42.6189 1.53714 S HTL AD 0 1704 Europe/Andorra 2010-04-04
+7287697 Hotel Montane Hotel Montane 42.5454 1.51909 S HTL AD 07 0 1397 Europe/Andorra 2010-04-06
+7287698 Hotel Pitiusa Hotel Pitiusa 42.5089 1.53258 S HTL AD 07 0 1041 Europe/Andorra 2010-04-06
+7287699 Hotel PrÃncep Hotel Princep 42.5087 1.54083 S HTL AD 07 0 1139 Europe/Andorra 2010-04-06
+7287700 Hotel I Termes Carlemany Hotel I Termes Carlemany 42.5092 1.54409 S HTL AD 07 0 1227 Europe/Andorra 2010-04-06
+7287701 Hotel Viena Hotel Viena 42.5069 1.52004 S HTL AD 07 0 1073 Europe/Andorra 2010-04-06
+7302102 La Margineda La Margineda 42.484 1.49242 P PPL AD 07 0 1353 Europe/Andorra 2010-05-26
+7730819 Andorra la Vella Heliport Andorra la Vella Heliport ALV 42.5005 1.51712 S AIRH AD 0 1073 Europe/Andorra 2011-03-17
+7733010 Grau Roig Grau Roig 42.53251 1.69923 P PPL AD 0 2204 Europe/Andorra 2011-04-07
+251130 WÄdÄ« Siqattah Wadi Siqattah Wadi Siqatta,Wadi Siqattah,WÄdÄ« Siqatta,WÄdÄ« Siqattah 25.6225 56.2225 H WAD AE 00 0 99 Asia/Dubai 2011-11-06
+286280 Suhaylah Suhaylah Suhaylah,Suheila 24.80388 56.19449 P PPL AE 02 0 238 Asia/Dubai 2011-11-06
+288716 WÄdÄ« al Bīḩ Wadi al Bih Wadi al Bih,WÄdÄ« al Bīḩ 25.77361 56.04389 H WAD AE 05 0 49 Asia/Dubai 2011-11-06
+290399 Zuyūd Zuyud Zuyud,Zuyūd 25.2 56.21667 L TRB AE 04 0 223 Asia/Dubai 2011-11-06
+290400 Z̧uwayhir Zuwayhir Dhawaihir,Duwaihir,Zuwayhir,Z̧uwayhir 23.28333 53.2 P PPL AE AE 01 0 170 Asia/Dubai 2011-11-06
+290401 Z̧uwayhir Zuwayhir Dhuwaiher,Zuwayhir,Zuweihir,Z̧uwayhir 23.13916 53.6934 P PPL AE 01 0 104 Asia/Dubai 2011-11-06
+290402 Zuwayghir Zuwayghir Zuwaighar,Zuwayghir 24.08333 55.26667 H WLL AE AE 01 0 167 Asia/Dubai 2011-11-06
+290403 WÄdÄ« Zuqaybah Wadi Zuqaybah Wadi Zuqaybah,WÄdÄ« Zuqaybah 25.40753 56.12592 H WAD AE 04 0 383 Asia/Dubai 2011-11-06
+290404 Ţawī Z̧ulaymah Tawi Zulaymah Dhalaima,Dulaima,Tawi Dhalaima,Tawi Dhelaimah,Tawi Dulaymah,Tawi Zeleimah,Tawi Zulaymah,Ţawī Dhalaima,Ţawī Dulaymah,Ţawī Z̧ulaymah 24.67083 55.53083 H WLLQ AE AE 01 0 208 Asia/Dubai 2011-11-06
+290405 Z̧ulaymah Zulaymah Dulaymah,Zulaymah,Z̧ulaymah 24.65 55.53333 T TRGD AE AE 03 0 230 Asia/Dubai 2011-11-06
+290406 Ruqq az Zukum Ruqq az Zukum Rak al Lakum,Rak az Zakum,Rig az Zakum,Ruqq az Zaqqum,Ruqq az Zaqqūm,Ruqq az Zukum 24.8 53.7 H SHOL AE AE 01 0 -9999 Asia/Dubai 2011-11-06
+290407 Zubyah Zubyah Zabia,Zubyah 24.96667 55.06667 T SAND AE AE 03 0 20 Asia/Dubai 2011-11-06
+290408 Jabal al ‘Azab Jabal al `Azab Jabal Azab,Jabal Zubb al `Azab,Jabal Zubb al ‘Azab,Jabal al `Azab,Jabal al ‘Azab 25.16139 55.83861 T DUNE AE 06 0 275 Asia/Dubai 2011-11-06
+290409 ZubÄrah Zubarah Zubara,Zubarah,ZubÄra,ZubÄrah 25.40487 56.35971 P PPL AE 04 0 -9999 Asia/Dubai 2011-11-06
+290410 ZirkÅ«h Zirkuh Az Zarqa',Az ZarqÄ’,Jazirat Zarka,Jazirat Zirku,Jaztal Zarakkuh,Jaztal ZarakkÅ«h,JazÄ«rat ZarkÄ,JazÄ«rat ZÄ«rkÅ«,Jezirat Zirko,JezÄ«rat Zirko,Zarakkawh,Zarakkuh,Zarqa,Zirko Island,Zirkuh,ZirkÅ«h 24.88417 53.07222 T ISL AE AE 01 0 161 Asia/Dubai 2011-11-06
+290411 Zirđah Zira`ah Zira`ah,Zirđah 24.06667 55.53333 T SAND AE 01 0 182 Asia/Dubai 2011-11-06
+290412 Zirđ Zira` Zira`,Zirđ 23.76822 54.20993 H WLL AE 01 0 116 Asia/Dubai 2011-11-06
+290413 Sabkhat ZinÄd Sabkhat Zinad Sabkhat Zinad,Sabkhat ZinÄd 24.48293 55.22135 H SBKH AE 01 0 145 Asia/Dubai 2011-11-06
+290414 ZinÄd Zinad Zinad,ZinÄd 24.5 55.23333 T SAND AE 01 0 151 Asia/Dubai 2011-11-06
+290415 Zimmat Ḩalamah Zimmat Halamah Zimmat Halamah,Zimmat Ḩalamah 24.13333 55.48333 T DUNE AE 01 0 187 Asia/Dubai 2011-11-06
+290416 Zimmat ‘Ankah Zimmat `Ankah Zimmat `Ankah,Zimmat ‘Ankah 24.16667 55.33333 T DUNE AE 01 0 173 Asia/Dubai 2011-11-06
+290417 WÄdÄ« Zikt Wadi Zikt Wadi Zikt,WÄdÄ« Zikt 25.52536 56.31864 H WAD AE 04 0 140 Asia/Dubai 2011-11-06
+290418 Jabal Zikt Jabal Zikt Jabal Zikt 25.51435 56.31373 T HLL AE 04 0 285 Asia/Dubai 2011-11-06
+290419 Zikt Zikt Zikt 25.5118 56.32328 P PPL AE 04 0 41 Asia/Dubai 2011-11-06
+290420 Ziffah Ziffah Ziffah 25.02385 56.28954 V CULT AE 04 0 99 Asia/Dubai 2011-11-06
+290421 Zidm Zidm Zidm 25.48333 56.15 S RUIN AE 04 0 507 Asia/Dubai 2011-11-06
+290422 Zibara Zibara Zibara,Zibarah,ZibÄrah 24.61889 54.63417 T DUNE AE 01 0 11 Asia/Dubai 2011-11-06
+290423 Zi‘Äb Zi`ab Za`ab,Za‘Äb,Zi`ab,Zi‘Äb 25.03333 56.36667 L TRB AE 06 0 -9999 Asia/Dubai 2011-11-06
+290424 ZayqÄt Zayqat Zaiqat,Zayqat,ZayqÄt 23.36667 52.15 S OILW AE AE 01 0 52 Asia/Dubai 2011-11-06
+290425 ZayqÄt Zayqat Zayqat,ZayqÄt 23.35 52.15 S CMPQ AE 01 0 53 Asia/Dubai 2011-11-06
+290426 MÄ«nÄ’ ZÄyid Mina' Zayid Mina Zayed,Mina' Zayid,MÄ«nÄ’ ZÄyid,Port Zayed,mynaʾ zayd,ميناء زايد 24.52518 54.38651 L PRT AE 01 0 -9999 Asia/Dubai 2011-11-06
+290427 Ramlat Zayd Ramlat Zayd Ramlat Zaid,Ramlat Zayd 24.21667 55.2 T DUNE AE AE 01 0 150 Asia/Dubai 2011-11-06
+290428 Bi’r Zayd Bi'r Zayd Bada` Zaid,Bada‘ Zaid,Bi'r Zayd,Bir Zaid,Bi’r Zayd 24.2 55.35 H WLL AE 01 0 168 Asia/Dubai 2011-11-06
+290429 Bid‘ Zayd Bid` Zayd Bada' Zaid,Bada’ Zaid,Bid` Zayd,Bid‘ Zayd 24.21667 55.11667 H WLL AE 01 0 118 Asia/Dubai 2011-11-06
+290430 Khawr Zawrah Khawr Zawrah Khawr Zawrah,Khawr Zora,Khawr az Zawra,Khawr az ZawrÄ 25.44417 55.47944 H INLT AE AE 02 0 -9999 Asia/Dubai 2011-11-06
+290431 JazÄ«rat Zawrah Jazirat Zawrah Al-Zura,Al-ZÅ«rÄ,Jazirat Zawrah,JazÄ«rat Zawrah,Zora Island 25.43778 55.46472 T ISL AE AE 00 0 8 Asia/Dubai 2011-11-06
+290432 Zawr Zawr Zawr 25.5275 55.59667 L LCTY AE 07 0 19 Asia/Dubai 2011-11-06
+290433 Z̧awÄhir Zawahir Dhawahir,DhawÄhir,Dhuwahir,Zawahir,Z̧awÄhir 24.33333 55.58333 L TRB AE AE 01 0 208 Asia/Dubai 2011-11-06
+290434 ZÄrÅ«b Zarub Zarub,ZarÅ«b,ZÄrÅ«b 25.01806 56.21 V CULT AE AE 06 0 406 Asia/Dubai 2011-11-06
+290435 ZarqÄ’ Zarqa' Zarqa',ZarqÄ’ 25.34622 55.87143 L LCTY AE 07 0 136 Asia/Dubai 2011-11-06
+290436 ZarÄrah Zararah Zararah,Zarrara,Zarrarah,Zarta,ZarÄrah 22.66667 54.13333 L OILF AE AE 01 0 145 Asia/Dubai 2011-11-06
+290437 ZarÄrah Zararah Zararah,ZarÄrah 22.87043 53.83424 T DPR AE 01 0 51 Asia/Dubai 2011-11-06
+290438 ZarÄf Zaraf Zaraf,ZarÄf 23.79064 54.21261 H WLL AE 01 0 84 Asia/Dubai 2011-11-06
+290439 Qarn Zaqīq Qarn Zaqiq Qarn Bu Naidar,Qarn Zaqiq,Qarn Zaqīq,Qarn al Khabta 24.31463 52.59967 T HLL AE 01 0 129 Asia/Dubai 2011-11-06
+290440 Jabal az̧ Z̧annah Jabal az Zannah Az Zannah,Az̧ Z̧annah,Djebel Dhanna,Jabal Danna,Jabal Dhannah,Jabal Dhanni,Jabal az Zannah,Jabal az̧ Z̧annah 24.1709 52.59488 T HLL AE 01 0 111 Asia/Dubai 2011-11-06
+290441 Dawḩat az̧ Z̧annah Dawhat az Zannah Dawhat az Zannah,Dawḩat az̧ Z̧annah 24.15252 52.71794 H BGHT AE 01 0 -9999 Asia/Dubai 2011-11-06
+290442 Z̧anḩah Zanhah Ghob,Zanhah,Z̧anḩah 25.5659 56.20217 P PPL AE 04 0 93 Asia/Dubai 2011-11-06
+290443 Ţawī Za‘lah Tawi Za`lah Tawi Za`lah,Ţawī Za‘lah 24.34848 55.43925 H WLLQ AE 01 0 178 Asia/Dubai 2011-11-06
+290444 Sayḩ Za‘lah Sayh Za`lah Sayh Za`lah,Sayḩ Za‘lah 24.33804 55.4268 T TRGD AE 01 0 179 Asia/Dubai 2011-11-06
+290445 Sayḩ Za‘lah Sayh Za`lah Sayh Za`lah,Sayḩ Za‘lah 24.2894 55.41804 T TRGD AE 01 0 175 Asia/Dubai 2011-11-06
+290446 Sayḩ Za‘lah Sayh Za`lah Sayh Za`lah,Sayḩ Za‘lah 24.28333 55.41667 T TRGD AE 01 0 163 Asia/Dubai 2011-11-06
+290447 ZÄkhir Zakhir Zakhir,ZÄkhir 24.11667 55.68333 S HSE AE 01 0 246 Asia/Dubai 2011-11-06
+290448 Ţawī ZĒid Tawi Za'id Tawi Za'id,Ţawī ZĒid 25.59556 55.88444 H WLL AE 07 0 35 Asia/Dubai 2011-11-06
+290449 Z̧ahūriyīn Zahuriyin Zahuriyin,Z̧ahūriyīn 26.05 56.13333 L TRB AE 05 0 680 Asia/Dubai 2011-11-06
+290450 Zaḩūm Zahum Zahum,Zaḩūm,Zihum 25.25 56.06667 L TRB AE AE 00 0 285 Asia/Dubai 2011-11-06
+290451 ZahrÄnÄ« Zahrani Zahrani,ZahrÄnÄ« 23.21667 54.18333 H WLL AE 01 0 116 Asia/Dubai 2011-11-06
+290452 Bū Ţabr Bu Tabr Bu Tabr,Bū Ţabr,Dahar,Dhahar,Zahr,Z̧ahr 24.35944 52.60583 S FRM AE AE 01 0 -9999 Asia/Dubai 2011-11-06
+290453 WÄdÄ« Z̧aḩah Wadi Zahah Wadi Zahah,WÄdÄ« Z̧aḩah 25.57036 56.20654 H WAD AE 04 0 76 Asia/Dubai 2011-11-06
+290454 Z̧afÄ«r Zafir Dafir,Dhafir,DhafÄ«r,Zafir,Z̧afÄ«r,á¸Äfir 23.12732 53.75439 P PPL AE 01 0 198 Asia/Dubai 2011-11-06
+290455 Z̧afīr Zafir Zafir,Z̧afīr 23.12027 53.75554 T DPR AE 01 0 82 Asia/Dubai 2011-11-06
+290456 Qarn Zabut Qarn Zabut Qarn Zabut 23.99048 54.07328 T HLL AE 01 0 20 Asia/Dubai 2011-11-06
+290457 Za‘bīl Za`bil Za`bil,Za‘bīl 25.22402 55.30452 S PAL AE 03 0 33 Asia/Dubai 2011-11-06
+290458 Å¢awÄ« Za‘ÄbÄ«yah Tawi Za`abiyah Tawi Za`abiyah,Å¢awÄ« Za‘ÄbÄ«yah 25.24917 55.88472 H WLL AE 06 0 128 Asia/Dubai 2011-11-06
+290459 Za‘Äb Za`ab Za`ab,Za‘Äb 25.68751 55.84732 L TRB AE 07 0 16 Asia/Dubai 2011-11-06
+290460 Ţawī Yudayyah Tawi Yudayyah Bir Yidayah,Tawi Yudayyah,Yidaiya,Ţawī Yudayyah 24.88904 55.78333 H WLL AE 06 0 203 Asia/Dubai 2011-11-06
+290461 Jabal YÄ«s Jabal Yis Jabal Yis,Jabal YÄ«s 25.35781 56.1109 T MT AE 04 0 683 Asia/Dubai 2011-11-06
+290462 Yinas Yinas Yinas 25.73158 56.13405 P PPL AE 05 0 1079 Asia/Dubai 2011-11-06
+290463 Yilak Yilak Yilak 23.06607 53.67436 T DPR AE 01 0 75 Asia/Dubai 2011-11-06
+290464 Yilaiyis Yilaiyis Yilaiyis 23.86184 55.43317 T DUNE AE 01 0 152 Asia/Dubai 2011-11-06
+290465 WÄdÄ« Yifan Wadi Yifan Wadi Yifan,WÄdÄ« Yifan 25.06066 56.30444 H WAD AE 04 0 38 Asia/Dubai 2011-11-06
+290466 Jabal Yibir Jabal Yibir Jabal Yibir 25.66752 56.13572 T MT AE 05 0 1527 1485 Asia/Dubai 2011-02-09
+290467 YÄsÄt ÅžaghÄ«rah Yasat Saghirah Yasat Saghirah,YÄsÄt ÅžaghÄ«rah 24.15912 52.0007 T ISL AE 01 0 6 Asia/Dubai 2011-11-06
+290468 Al YÄsÄt as Suflá Al Yasat as Sufla Al Yasat as Sufla,Al YÄsÄt as Suflá,Yasat Safli,YÄsÄt SaflÄ« 24.18675 51.9948 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290469 Al YÄsÄt al ‘UlyÄ Al Yasat al `Ulya Al Yasat al `Ulya,Al YÄsÄt al ‘UlyÄ,Yasat `Ali,YÄsÄt ‘AlÄ« 24.23662 52.01234 T ISL AE 01 0 10 Asia/Dubai 2011-11-06
+290470 Yarīrah Yarirah Yarirah,Yarīrah 22.8707 54.22656 T DPR AE 01 0 94 Asia/Dubai 2011-11-06
+290471 WÄdÄ« YamÄn Wadi Yaman Wadi Yaman,WÄdÄ« YamÄn 25.38499 56.32647 H WAD AE 06 0 53 Asia/Dubai 2011-11-06
+290472 Å¢awÄ« YÄl Tawi Yal Tawi Yal,Å¢awÄ« YÄl 25.42336 56.10511 H WLL AE 04 0 302 Asia/Dubai 2011-11-06
+290473 YÄkhÅ«n Yakhun Yakhun,YÄkhÅ«n 24.88795 55.72161 T DUNE AE 06 0 210 Asia/Dubai 2011-11-06
+290474 Ya‘rid Ya`rid Ya`rid,Yairad,Ya‘rid,Yerad 24.80324 55.03569 T SAND AE 01 0 28 Asia/Dubai 2011-11-06
+290475 WÄdÄ« Yaif Wadi Yaif Wadi Yaif,WÄdÄ« Yaif 24.93722 56.1025 H WAD AE 05 0 295 Asia/Dubai 2011-11-06
+290476 Yaif Yaif Yaif 24.94 56.09722 V CULT AE 05 0 530 Asia/Dubai 2011-11-06
+290477 Yahli Yahli Yahli 23.9879 54.70761 H WLL AE 01 0 106 Asia/Dubai 2011-11-06
+290478 Ţawī Yaḩfar Tawi Yahfar Tawi Yahfar,Ţawī Yaḩfar 25.02556 55.83361 H WLL AE 06 0 172 Asia/Dubai 2011-11-06
+290479 Sayḩ YÄfÅ«kh Sayh Yafukh Sayh Yafukh,Sayḩ YÄfÅ«kh 23.6458 55.49207 T TRGD AE 01 0 167 Asia/Dubai 2011-11-06
+290480 Yafnah Yafnah Yafnah,Yifnah 25.73424 56.09919 V CULT AE 05 0 766 Asia/Dubai 2011-11-06
+290481 Jazīrat Yabr Jazirat Yabr Jazirat Yabr,Jazīrat Yabr 24.31856 52.71939 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290482 Ţawī Yabbah Tawi Yabbah Tawi Yabbah,Ţawī Yabbah 25.35306 56.05111 H WLL AE 04 0 266 Asia/Dubai 2011-11-06
+290483 Ya‘alla Ya`alla Ya`alla,Ya‘alla 23.90646 54.99539 T DUNE AE 01 0 135 Asia/Dubai 2011-11-06
+290484 WÄdÄ« Ya’a Wadi Ya'a Wadi Ya'a,WÄdÄ« Ya’a 25.09611 56.26028 H WAD AE 04 0 224 Asia/Dubai 2011-11-06
+290485 Jabal Wutayd Jabal Wutayd Jabal Witeid,Jabal Wutaid,Jabal Wutayd 23.93615 52.29663 T HLL AE 01 0 40 Asia/Dubai 2011-11-06
+290486 Å¢awÄ« WushÄḩ Tawi Wushah Tawi Wishah,Tawi Wushah,TÄwÄ« Wishah,Wusha,Å¢awÄ« WushÄḩ 25.22834 55.91456 H WLL AE 06 0 143 Asia/Dubai 2011-11-06
+290487 WÄdÄ« Wurayyah Wadi Wurayyah Wadi Waraiya,Wadi Wurayyah,WÄdÄ« Waraiya,WÄdÄ« Wurayyah 25.38343 56.26224 H WAD AE 04 0 415 Asia/Dubai 2011-11-06
+290488 Wuqnah Wuqnah Wuqnah 23.0326 53.67397 T DPR AE 01 0 86 Asia/Dubai 2011-11-06
+290489 Wuḩaydah Wuhaydah Wuhaydah,Wuḩaydah 23.13333 53.93333 L OAS AE 01 0 98 Asia/Dubai 2011-11-06
+290490 Wuḩaydah Wuhaydah Wuhaida,Wuhaydah,Wuḩaydah 23.11764 53.77261 L OAS AE 01 0 194 Asia/Dubai 2011-11-06
+290491 WudibsÄ Wudibsa Wudibsa,WudibsÄ 23.73726 52.25189 T SAND AE 01 0 32 Asia/Dubai 2011-11-06
+290492 WÄdÄ« WiqÄ’ Wadi Wiqa' Wadi Wiqa',Wadi al Amlah,WÄdÄ« WiqÄ’,WÄdÄ« al Amlaḩ 25.19143 56.04543 H WAD AE 05 0 210 Asia/Dubai 2011-11-06
+290493 Ţawī Widd Tawi Widd Tawi Wid,Tawi Widd,Ţawī Wid,Ţawī Widd 25.63296 56.01934 H WLL AE 05 0 108 Asia/Dubai 2011-11-06
+290494 Webb Rock Webb Rock Webb Rock 24.08437 52.2437 T RK AE 01 0 -9999 Asia/Dubai 2011-11-06
+290495 WÄdÄ« Wayqah Wadi Wayqah Wadi Wayqah,WÄdÄ« Wayqah 25.32211 56.12861 H WAD AE 04 0 403 Asia/Dubai 2011-11-06
+290496 Watigh Watigh Watigh 23.68728 55.07948 T DUNE AE 01 0 139 Asia/Dubai 2011-11-06
+290497 Watauq Watauq Watauq 24.30306 54.91357 H WLL AE 01 0 70 Asia/Dubai 2011-11-06
+290498 Raml WÄsiÅ£ Raml Wasit Raml Wasit,Raml WÄsiÅ£,Wasit,WÄsit 25.3425 55.47167 T SAND AE AE 06 0 21 Asia/Dubai 2011-11-06
+290499 WÄsiÅ£ Wasit Wasit,WÄsiÅ£ 25.72194 55.87806 H WLL AE 05 0 32 Asia/Dubai 2011-11-06
+290500 WÄsiÅ£ Wasit Wasit,WÄsiÅ£ 25.60698 56.2548 P PPL AE 04 0 9 Asia/Dubai 2011-11-06
+290501 WÄsiÅ£ Wasit Wasit,WÄsiÅ£ 23.0036 53.44942 T DPR AE 01 0 176 Asia/Dubai 2011-11-06
+290502 Wasaţ Wasat Wasat,Wasaţ 22.80611 53.31093 H WLL AE 01 0 70 Asia/Dubai 2011-11-06
+290503 WarÄ«sÄn Warisan Warisan,WarÄ«sÄn 25.16744 55.40708 P PPL AE 03 0 20 Asia/Dubai 2011-11-06
+290504 Ţawī Waraqah Tawi Waraqah Tawi Waraqah,Ţawī Waraqah 24.77782 56.14991 H WLL AE 03 0 341 Asia/Dubai 2011-11-06
+290505 Khaţm Waraq Khatm Waraq Khatm Waraq,Khaţm Waraq 24.36667 55.45 T DUNE AE 01 0 158 Asia/Dubai 2011-11-06
+290506 WarÄq Waraq Waraq,WarÄq 22.97996 54.18115 T DPR AE 01 0 98 Asia/Dubai 2011-11-06
+290507 WÄdÄ« Wamm Wadi Wamm Wadi Wamm,WÄdÄ« Wamm 25.60512 56.22705 H WAD AE 04 0 42 Asia/Dubai 2011-11-06
+290508 Jabal Wamm Jabal Wamm Jabal Wamm 25.6021 56.19906 T MT AE 04 0 490 Asia/Dubai 2011-11-06
+290509 Wamm Wamm Wamm 25.60031 56.22838 P PPL AE 04 0 42 Asia/Dubai 2011-11-06
+290510 Walters Shoal Walters Shoal Walters Shoal 24.39524 52.47387 H RF AE 01 0 -9999 Asia/Dubai 2011-11-06
+290511 Sayḩ al Wakrah Sayh al Wakrah Sayh al Wakrah,Sayḩ al Wakrah 24.59461 54.96476 T TRGD AE 01 0 57 Asia/Dubai 2011-11-06
+290512 Wahala Wahala Wahala,Wahlah,Waḩlah 24.90897 56.30316 P PPL AE 02 0 71 Asia/Muscat 2011-11-06
+290513 WÄdÄ« WahÄ«yah Wadi Wahiyah Wadi Wahiya,Wadi Wahiyah,WÄdÄ« Wahiya,WÄdÄ« WahÄ«yah 24.8183 56.15931 H WAD AE 02 0 282 Asia/Dubai 2011-11-06
+290514 Jabal Waḩīd Jabal Wahid Jabal Wahid,Jabal Waḩīd,The Hummock 24.31115 52.61141 T HLL AE 01 0 45 Asia/Dubai 2011-11-06
+290515 WÄḩid Wahid Wahid,WÄḩid 24.82444 56.08111 V CULT AE 02 0 339 Asia/Dubai 2011-11-06
+290516 WaharmÄ Waharma Waharma,WaharmÄ 22.75519 53.44766 T DPR AE 01 0 66 Asia/Dubai 2011-11-06
+290517 Wafd Wafd Qutuf,Quţūf,Waafit,Wafd,Wafid,Wefid 23.10262 53.71159 P PPL AE 01 0 84 Asia/Dubai 2011-11-06
+290518 Wad Wid Wad Wid Wad Wid 25.62515 56.01396 P PPL AE 05 0 17 Asia/Dubai 2011-11-06
+290519 WÄdÄ« ShÄ« Wadi Shi Wadi Shi,WÄdÄ« ShÄ« 25.35 56.31667 P PPL AE 06 0 77 Asia/Dubai 2011-11-06
+290520 Ḩabl WÄdÄ« ÅžafÄ Habl Wadi Safa Habl Wadi Safa,Wadi Safa,WÄdÄ« ÅžafÄ,Ḩabl WÄdÄ« ÅžafÄ 25.06092 55.27055 T DUNE AE 03 0 33 Asia/Dubai 2011-11-06
+290521 Wadhīl Wadhil Wadhil,Wadhīl,Wedheil,Wudhayl 23.0474 54.13332 P PPL AE 01 0 99 Asia/Dubai 2011-11-06
+290522 WÄdÄ« Wa‘bayn Wadi Wa`bayn Wadi Wa`bayn,WÄdÄ« Wa‘bayn 25.57261 56.12374 H WAD AE 04 0 400 Asia/Dubai 2011-11-06
+290523 Wa‘bayn Wa`bayn Wa'abain,Wa`bayn,Wa‘bayn,Wa’abain 25.57046 56.13536 P PPL AE 04 0 357 Asia/Dubai 2011-11-06
+290524 ‘Uzlah `Uzlah `Uzalah,`Uzlah,‘Uzalah,‘Uzlah 22.99545 54.16649 T DPR AE 01 0 91 Asia/Dubai 2011-11-06
+290525 WÄdÄ« al ‘Uyaynah Wadi al `Uyaynah Wadi Ayeina,Wadi al `Uyaynah,WÄdÄ« Ayeina,WÄdÄ« al ‘Uyaynah 25.4742 56.18514 H WAD AE 04 0 176 Asia/Dubai 2011-11-06
+290526 GhaffÄt al ‘Uwayyirah Ghaffat al `Uwayyirah Ghaffat al `Uwayyirah,GhaffÄt al ‘Uwayyirah 24.46667 55.31667 T DUNE AE 01 0 152 Asia/Dubai 2011-11-06
+290527 Jabal al ‘Uwayyin Jabal al `Uwayyin Jabal al `Uwayyin,Jabal al ‘Uwayyin 25.36083 56.32395 T MT AE 06 0 583 Asia/Dubai 2011-11-06
+290528 Ţawī ‘Uwayyah Tawi `Uwayyah Tawi `Uwayyah,Ţawī ‘Uwayyah 25.58472 55.76028 H WLL AE 07 0 26 Asia/Dubai 2011-11-06
+290529 ‘Uwayyah `Uwayyah `Uwayyah,‘Uwayyah 25.11278 55.30367 L LCTY AE 03 0 24 Asia/Dubai 2011-11-06
+290530 Qarn ‘Uwayşim Qarn `Uwaysim Qarn `Uwaysim,Qarn ‘Uwayşim 23.86667 53.43333 T HLL AE 01 0 70 Asia/Dubai 2011-11-06
+290531 ‘Uwayşim `Uwaysim `Uwaisim,`Uwaysim,‘Uwaisim,‘Uwayşim 23.88333 53.38333 H WLL AE 01 0 66 Asia/Dubai 2011-11-06
+290532 Sabkhat ‘Uwayrah Sabkhat `Uwayrah Sabkhat `Uwayrah,Sabkhat ‘Uwayrah 23.95006 55.3068 H SBKH AE 01 0 131 Asia/Dubai 2011-11-06
+290533 NiqyÄn ‘Uwayrah Niqyan `Uwayrah Niqyan `Uwayrah,NiqyÄn ‘Uwayrah 23.96497 55.28962 T DUNE AE 01 0 181 Asia/Dubai 2011-11-06
+290534 Ţawī al ‘Uwaynīyah Tawi al `Uwayniyah Tawi al `Uwayniyah,Ţawī al ‘Uwaynīyah 25.31667 55.76667 H WLL AE 06 0 86 Asia/Dubai 2011-11-06
+290535 ‘Uwayjir `Uwayjir `Uwayjir,‘Uwayjir 24.71667 55.16667 T HLL AE 03 0 87 Asia/Dubai 2011-11-06
+290536 ‘Uwayj al ‘Abīd `Uwayj al `Abid `Uwayj al `Abid,‘Uwayj al ‘Abīd 24.11667 55.06667 T DUNE AE 01 0 119 Asia/Dubai 2011-11-06
+290537 ‘Uwayj al ‘Abīd `Uwayj al `Abid `Uwayj al `Abid,‘Uwayj al ‘Abīd 24.13333 55.06667 T DPR AE 01 0 125 Asia/Dubai 2011-11-06
+290538 Jabal ‘Uwaybil Jabal `Uwaybil Jabal `Uwaybil,Jabal ‘Uwaybil 25.44021 55.96991 T DUNE AE 05 0 189 Asia/Dubai 2011-11-06
+290539 Jabal al ‘Uţayfah Jabal al `Utayfah Jabal al `Utayfah,Jabal al ‘Utayfah,Jabal al ‘Uţayfah 25.51024 56.02862 T HLL AE 04 0 278 Asia/Dubai 2011-11-06
+290540 ‘Ushsh `Ushsh 'Ishsh,Al Isha,Jazirat `Ish,Jazīrat ‘Ish,Ushsh,`Ashsh,`Ish,`Ushsh,‘Ashsh,‘Ish,‘Ushsh,’Ishsh 24.30488 52.87712 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290541 WÄdÄ« Ushayl Wadi Ushayl Wadi Ushail,Wadi Ushayl,WÄdÄ« Ushail,WÄdÄ« Ushayl 24.90515 56.08586 H WAD AE 05 0 287 Asia/Dubai 2011-11-06
+290542 WÄdÄ« ‘Usaylah Wadi `Usaylah Wadi `Usaylah,WÄdÄ« ‘Usaylah 25.69178 56.03764 H WAD AE 05 0 48 Asia/Dubai 2011-11-06
+290543 Sabkhat al ‘Urūq Sabkhat al `Uruq Sabkhat al `Uruq,Sabkhat al ‘Urūq 23.90811 54.18872 H SBKH AE 01 0 40 Asia/Dubai 2011-11-06
+290544 ‘UrqÅ«b SibÄ’ `Urqub Siba' Sbaa,Siba`,SibÄ‘,`Urqub Siba',‘UrqÅ«b SibÄ’ 25.27824 55.47043 L LCTY AE 03 0 24 Asia/Dubai 2011-11-06
+290545 ‘Urqūb Juwayzah `Urqub Juwayzah `Urqub Juwayzah,‘Urqūb Juwayzah 24.90586 55.4608 T SCRP AE 03 0 107 Asia/Dubai 2011-11-06
+290546 ‘Urqūb Juwayza `Urqub Juwayza `Urqub Juwayza,‘Urqūb Juwayza 24.93333 55.46667 P PPL AE 03 0 102 Asia/Dubai 2011-11-06
+290547 ‘Uraykah `Uraykah `Uraykah,‘Uraykah 24.36667 55.45 T TRGD AE 01 0 158 Asia/Dubai 2011-11-06
+290548 ‘Uraykah `Uraykah 'Ureika,`Uraykah,‘Uraykah,’Ureika 24.33333 55.46667 T HLL AE 01 0 199 Asia/Dubai 2011-11-06
+290549 WÄdÄ« ‘Urayf Wadi `Urayf Wadi `Urayf,WÄdÄ« ‘Urayf 25.49385 56.06209 H WAD AE 04 0 147 Asia/Dubai 2011-11-06
+290550 ‘Uraybī `Uraybi Araibi,`Uraybi,‘Uraybī 25.78945 55.97665 P PPLX AE 05 0 20 Asia/Dubai 2011-11-06
+290551 ‘Uqayyiq `Uqayyiq `Uqayyiq,‘Uqayyiq 24.53333 54.75 H WLL AE 01 0 33 Asia/Dubai 2011-11-06
+290552 ‘Uqayyiq `Uqayyiq `Uqayyiq,‘Uqayyiq 24.52079 54.66317 T DUNE AE 01 0 7 Asia/Dubai 2011-11-06
+290553 Ţawī ‘Uqayr Tawi `Uqayr Tawi `Uqayr,Ţawī ‘Uqayr 23.78033 55.4708 H WLL AE 01 0 146 Asia/Dubai 2011-11-06
+290554 ‘Uqayr `Uqayr `Uqayr,‘Uqayr 25.28302 56.36435 P PPL AE 06 0 23 Asia/Dubai 2011-11-06
+290555 ‘UqaydÄt `Uqaydat Al `Uqaydat,Al ‘UqaydÄt,`Uqaydat,‘UqaydÄt 24.78556 55.78972 V TREE AE 06 0 275 Asia/Dubai 2011-11-06
+290556 Jabal ‘UqaybÄt Jabal `Uqaybat Jabal `Uqaybat,Jabal ‘UqaybÄt 25.1275 56.31278 T HLL AE 04 0 155 Asia/Dubai 2011-11-06
+290557 United Arab Emirates United Arab Emirates Ab'adnanya Arabskia Emiraty,Al Imarat al `Arabiyah al Muttahidah,Al ImÄrÄt al ‘ArabÄ«yah al Muttaḩidah,Aontas na nEimiriochtai Arabacha,Aontas na nÉimÃrÃochtaà Arabacha,Apvienotie Arabu Emirati,Apvienotie ArÄbu EmirÄti,Araabia UEhendemiraadid,Araabia Ãœhendemiraadid,Arab Federation of Gulf States,Arab Gulf Federation,Arabiar Emirerri Batuak,Arabiar Emirrerri Batuak,Arabiemiirikunnat,Birlashgan Arab Amirliglar,Birlesik Arap Emirlikleri,BirleÅŸik Arap Emirlikleri,Cac Tieu Vuong quoc A-rap Thong nhat,Cac Tieu vuong quoc A rap Thong nhat,Các Tiểu VÆ°Æ¡ng quốc A-ráºp Thống nhất,Các Tiểu vÆ°Æ¡ng quốc Ả ráºp Thống nhất,Dawlat Ittihad al Imarat al `Arabiyah,Dawlat IttiḩÄd al ImÄrÄt al ‘ArabÄ«yah,De forente arabiske emirater,Dei sameinte arabiske emirata,Egyesuelt Arab Emiratus,Egyesuelt Arab Emirsegek,Egyesült Arab Emirátus,Egyesült Arab EmÃrségek,Emira Arab Ini,Emirados Arabes Unidos,Emirados Ãrabes Unidos,Emiraethau Arabaidd Unedig,Emiratele Arabe Unite,Emiratet Arabe te Bashkuara,Emiratet e Bashkuara Arabe,Emirati Arabi Uniti,Emirati Gharab Maqghuda,Emirati Għarab Maqgħuda,Emiratos Arabe Unite,Emiratos Arabes Unidos,Emiratos Arabes Unitos,Emiratos Ãrabes Unidos,Emiratos Ãrabes Unidos - الإمارات العربيّة المتّØدة,Emirats Arabes Unis,Emirats Arabis Units,Emirats Arabs Units,Emirats arabes units,Emirats arabos unis,Emirats Àrabs Units,Emiratus Arabi Uniti,Emirelezhiou Arab Unanet,Emirelezhioù Arab Unanet,Emiriah Arab Bersatu,Enomena Arabika Emirata,Falme za Kiarabu,Federation of Arab Emirates,Federation of Arabian Emirates,Federation of Arabian Gulf Emirates,Feriene Arabyske Emiraten,Foerenade Arabemiraten,Forenede Arabiske Emirater,Förenade Arabemiraten,Imaaraadka Carabta ee Midoobay,Jungtiniai Arabu Emyratai,Jungtiniai Arabų Emyratai,Lemiraens Pebaloel Larabaenik,Lemiräns Pebalöl Larabänik,Mirnisinen Erebi yen Yekbuyi,Muugano wa Falme za Nchi za Kiarabu,Mîrnişînên Erebî yên Yekbûyî,OAEH,Ob"edinjonnye Arabskie Ehmiraty,Obedineni Arabski Emirstva,Obedineti Arapski Emirati,Obuedinennye Arabskie Ehmiraty,Ovttastuvvan Arabaemirahtat,Ovttastuvvan Arábaemiráhtat,Pennternasedh Unys Arabek,Sameindu Emirrikini,Sameindu EmirrÃkini,Sameinudu arabisku furstadaemin,Sameinuðu arabÃsku furstadæmin,Spojene arabske emiraty,Spojené arabské emiráty,Trucial States,UAE,Ujedineni Arapski Emirati,Ujedinjeni Arapski Emirati,Uni Emirat Arab,Unio dels Emirats Arabs,Union of Arab Emirates,Unionita Araba Emirati,United Arab Emirates,Unió dels Emirats Àrabs,Unuigintaj Arabaj Emirlandoj,Unuigintaj Arabaj Emirlandos,UnuiÄintaj Arabaj Emirlandoj,UnuiÄintaj Arabaj Emirlandos,Vereenegt Arabesch Emirater,Vereenigte Araabsche Emiraten,Vereinegde Arabische Emirate,Vereinigte Arabische Emirate,Verenigde Arabiese Emirate,Verenigde Arabische Emiraten,Zdruzeni arabski emirati,Združeni arabski emirati,Zjednocene Arabske Emiraty,Zjednoczone Emiraty Arabskie,Zjednoćene Arabske Emiraty,a la bo lian he qiu zhang guo,aikkiya arapu amirakam,aikkiya arapu kuttatci,alab-emiliteu,arabetis gaertianebuli saamiroebi,arabu shou zhang guo lian bang,sanyukta arab rastram,sanyukta araba amirata,shrath xahrab xe mi rets,Èmirats arabes units,Èmirats arabos unis,Émirats Arabes Unis,ΗνωμÎνα ΑÏαβικά ΕμιÏάτα,Ðб'ÑÐ´Ð½Ð°Ð½Ñ‹Ñ ÐрабÑÐºÑ–Ñ Ðміраты,Имороти Муттаҳидаи Ðраб,ОÐÐ,Об'єднані ÐрабÑькі Емірати,Обʼєднані ÐрабÑькі Емірати,Обединени ÐрабÑки ЕмирÑтва,Обединети ÐрапÑки Емирати,Объединенные ÐрабÑкие Ðмираты,Объединённые ÐрабÑкие Ðмираты,Уједињени ÐрапÑки Емирати,Õ„Õ«Õ¡ÖÕµÕ¡Õ¬ Ô±Ö€Õ¡Õ¢Õ¡Õ¯Õ¡Õ¶ Ô·Õ´Õ«Ö€Õ¡Õ©Õ¶Õ¥Ö€,×יחוד ×”×מירויות הערביות,×יחוד × ×¡×™×›×•×™×•×ª ערב,ברית ×”×מירויות הערביות,ئەرەب بىرلەشمە خەلىپىلىكى,الإمارات العربية المتØدة,الامارات العربية المتØدة,امارات متØده عربی,امارات متØدهٔ عربی,عمارات متØده ÛŒ عربی,متØده عرب امارات,متØØ¯Û Ø¹Ø±Ø¨ امارات,ÜÜ¡ÜÜªÜ˜Ü¬Ü Ü¥ÜªÜ’ÜÜ¬Ü ÜšÜ•ÜܬÜ,संयà¥à¤•à¥à¤¤ अरब अमीरात,সংযà§à¦•à§à¦¤ আরব আমিরাত,à®à®•à¯à®•à®¿à®¯ அரப௠அமீரகமà¯,à®à®•à¯à®•à®¿à®¯ அரப௠கூடà¯à®Ÿà®¾à®Ÿà¯à®šà®¿,à´à´•àµà´¯ അറബൠഎമിരേറàµà´±àµà´•à´³àµâ€â€Œ,സംയàµà´•àµà´¤ അറബൠരാഷàµà´Ÿàµà´°à´‚,สหรัà¸à¸à¸²à¸«à¸£à¸±à¸šà¹€à¸à¸¡à¸´à¹€à¸£à¸•à¸ªà¹Œ,ສະຫະລັດàºàº²àº«àº¥àº±àºšà»€àºàº¡àº´à»€àº¥àº”,ཡུ་ནའི་ཊེཊ་ཨ་ར བ་ཨེ་མི་རེཊསི,ཨ་རབ༠ཨི་མི་རཊ྄༠ཆིག་སྒྲིལ་རྒྱལ་à½à½–à¼,áƒáƒ áƒáƒ‘ეთის გáƒáƒ”რთიáƒáƒœáƒ”ბული ემირáƒáƒ¢áƒ”ბი,áƒáƒ áƒáƒ‘ეთის გáƒáƒ”რთიáƒáƒœáƒ”ბული სáƒáƒáƒ›áƒ˜áƒ áƒáƒ”ბი,የተባበሩት አረብ ኤáˆáˆ¬á‰µáˆµ,អáŸáž˜áž¸ážšáŸ‰áŸ‚ទអារ៉ាប់រួម,アラブ首長国連邦,阿拉伯è”åˆé…‹é•¿å›½,ì•„ëžì—미리트 24 54 A PCLI AE 00 4975593 12 Asia/Dubai 2011-11-06
+290558 Umm Åžayd Umm Sayd Umm Sayd,Umm Åžayd 22.94932 53.78481 T DPR AE 01 0 44 Asia/Dubai 2011-11-06
+290559 Umm Qays Umm Qays Umm Qays,Umm Qayz,Umm Qayz̧,Umm Qaz,Umm Qaz̧ 22.92996 53.41542 H WLL AE 01 0 65 Asia/Dubai 2011-11-06
+290560 Umm Qays Umm Qays Umm Qays,Umm Qayz,Umm Qayz̧ 22.92593 53.4138 T DPR AE 01 0 65 Asia/Dubai 2011-11-06
+290561 Umm JaÅŸÅŸÄr Umm Jassar Umm Jassar,Umm JaÅŸÅŸÄr,Umm Qasar,Umm Qassar,Umm QaÅŸÄr,Umm QaÅŸÅŸÄr,`Umm Gassar,‘Umm GaṣṣÄr 24.3914 52.77794 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290562 Umm Minhad Umm Minhad Umm Minhad 24.99359 55.3636 T SAND AE 03 0 40 Asia/Dubai 2011-11-06
+290564 Fasht Umm Jannah Fasht Umm Jannah Fasht Umm Janna,Fasht Umm Jannah,Janna 24.56959 51.5546 H RF AE 01 0 -9999 Asia/Dubai 2011-11-06
+290565 Qarn Umm Ḩaşá Qarn Umm Hasa Qarn Umm Hasa,Qarn Umm Ḩaşá 25.11385 55.38284 T DUNE AE 03 0 49 Asia/Dubai 2011-11-06
+290566 Umm ḨafÄt Umm Hafat Umm Hafaf,Umm Hafat,Umm ḨafÄf,Umm ḨafÄt 23.84889 53.67889 H WLL AE AE 01 0 76 Asia/Dubai 2011-11-06
+290567 Umm Khafat Umm Khafat Umm Hafaf,Umm Hafat,Umm Kafat,Umm Khafat,Umm ḨafÄf,Umm ḨafÄt 23.85336 53.69666 T HLL AE 01 0 95 89 Asia/Dubai 2011-11-06
+290568 Umm ḨÄbil Umm Habil Umm Habil,Umm ḨÄbil 22.99242 54.08237 T DPR AE 01 0 213 Asia/Dubai 2011-11-06
+290569 Ţawī Umm Ghuwayr Tawi Umm Ghuwayr Tawi Umm Ghuwayr,Ţawī Umm Ghuwayr 24.25341 55.0425 H WLL AE 01 0 125 Asia/Dubai 2011-11-06
+290570 Umm Ghaythah Umm Ghaythah Umm Gaita,Umm Ghaythah 24.10556 55.67583 T DPR AE AE 01 0 244 Asia/Dubai 2011-11-06
+290571 JazÄ«rat Umm YafÄ«nah Jazirat Umm Yafinah Jazirat Umm Yafinah,JazÄ«rat Umm YafÄ«nah,Umm Fiyin,Umm FÄ«yÄ«n,jzyrt am yfynt,جزيرة أم ÙŠÙينة 24.48752 54.45009 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290572 Umm Dhuwaylah Umm Dhuwaylah Umm Dhuwaylah 24.45801 54.7294 H WLL AE 01 0 26 Asia/Dubai 2011-11-06
+290573 Umm Dhuwaylah Umm Dhuwaylah Umm Dhuwaylah 24.4692 54.723 T SAND AE 01 0 36 Asia/Dubai 2011-11-06
+290574 Umm Dasīs Umm Dasis Umm Dasis,Umm Dasīs,Umm Daysis,Umm Daysīs 23.81981 53.53876 L GVL AE 01 0 109 Asia/Dubai 2011-11-06
+290575 WÄdÄ« Umm ad Daqqayn Wadi Umm ad Daqqayn Wadi Umm Daqqayn,Wadi Umm ad Daqqayn,WÄdÄ« Umm Daqqayn,WÄdÄ« Umm ad Daqqayn 24.80556 56.20722 H WAD AE AE 00 0 271 Asia/Dubai 2011-11-06
+290576 Kharaj Umm BiyÄt Kharaj Umm Biyat Kharaj Umm Bayat,Kharaj Umm BayÄt,Kharaj Umm Biyat,Kharaj Umm BiyÄt 25.15 55.4 H WLL AE AE 03 0 7 Asia/Dubai 2011-11-06
+290577 Ţawī Umm Baraz Tawi Umm Baraz Tawi Umm Baraz,Ţawī Umm Baraz 22.94415 54.96468 H WLL AE 01 0 137 Asia/Dubai 2011-11-06
+290578 Sabkhat Umm Baraz Sabkhat Umm Baraz Sabkhat Umm Baraz 22.93458 55.03856 H SBKH AE 01 0 99 Asia/Dubai 2011-11-06
+290579 Umm Baraz Umm Baraz Umm Baraz 23.05 54.95 H WLL AE 01 0 125 Asia/Dubai 2011-11-06
+290580 Umm az Zumūl Umm az Zumul Umm Zamul,Umm Zamūl,Umm al Zamul,Umm az Zumul,Umm az Zumūl,Umm az-Zamul 22.70559 55.21205 H WLL AE 01 0 121 Asia/Dubai 2011-11-06
+290581 Umm Suqaym Umm Suqaym Umm Suqaym,Umm as Suqaym 25.15015 55.20587 P PPLX AE 03 0 26 Asia/Dubai 2011-11-06
+290582 Ḩaql Umm ash Shayf Haql Umm ash Shayf Haql Umm ash Shayf,Umm Shaif,Umm al-Shayf,Umm al-Sheif,Umm ash Sha'if,Umm ash ShÄ’if,Ḩaql Umm ash Shayf 25.2 53.2 L OILF AE AE 01 0 -9999 Asia/Dubai 2011-11-06
+290583 Umm ar Raml Umm ar Raml Umm ar Raml 25.19658 55.41034 L LCTY AE 03 0 22 Asia/Dubai 2011-11-06
+290584 Umm ar Raml Umm ar Raml Umm ar Raml 25.23333 55.38333 T DUNE AE 03 0 29 Asia/Dubai 2011-11-06
+290585 WÄdÄ« Umm an NughÅ«l Wadi Umm an Nughul Wadi Umm an Nughul,WÄdÄ« Umm an NughÅ«l 25.34985 55.84553 H WAD AE 07 0 111 Asia/Dubai 2011-11-06
+290586 Ţawī Umm an Nughūl Tawi Umm an Nughul Tawi Umm an Nughul,Ţawī Umm an Nughūl 25.36333 55.87019 H WLL AE 07 0 92 Asia/Dubai 2011-11-06
+290587 Umm an NÄr Umm an Nar Jazirat Umm an Nar,JazÄ«rat Umm an NÄr,Umm an Nar,Umm an NÄr,`Umm al-Nar,am alnar,أم النار,‘Umm al-NÄr 24.44248 54.50948 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290588 Umm ‘Amīm Umm `Amim Jazirat Umm `min,Jazīrat Umm ‘mīn,Umm `Amim,Umm ‘Amīm 24.24128 53.39448 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290589 Umm al Qurayn Umm al Qurayn Umm Grain,Umm al Qurayn,`Umm Qrein,‘Umm Qrein 23.1 53.71667 P PPL AE AE 01 0 181 Asia/Dubai 2011-11-06
+290590 Umm al Qurayn Umm al Qurayn Umm al Qurayn 23.09087 53.72477 L OAS AE 01 0 101 Asia/Dubai 2011-11-06
+290591 Umm al Qiţa‘ Umm al Qita` Umm al Qita`,Umm al Qiţa‘ 23.05522 53.53183 L OAS AE 01 0 127 Asia/Dubai 2011-11-06
+290592 Umm al Qird Umm al Qird Umm al Fa'iyah,Umm al FÄ’iyah,Umm al Qird 24.20527 54.79192 T SAND AE 01 0 66 Asia/Dubai 2011-11-06
+290593 Khawr Umm al Qaywayn Khawr Umm al Qaywayn Khawr Umm al Qaywayn 25.56 55.57972 H BAY AE 07 0 -9999 Asia/Dubai 2011-11-06
+290594 Umm al Qaywayn Umm al Qaywayn Um al Quweim,Umm al Qaiwain,Umm al Qawain,Umm al Qaywayn,Yumul al Quwain,am alqywyn,أم القيوين 25.56473 55.55517 P PPLA AE 07 44411 8 Asia/Dubai 2011-11-06
+290595 Umm al Qaywayn Umm al Qaywayn Oumm al Qaiwain,Oumm al Qaïwaïn,Skeikhdom of Umm al Qaiwain,Umm Al Quwain,Umm al Qawain,Umm al Qaywayn,Umm al Qiwain,am alqywyn,أم القيوين 25.5 55.75 A ADM1 AE 07 56253 65 Asia/Dubai 2011-11-05
+290596 Kharīmat Umm al Muwayghir Kharimat Umm al Muwayghir Kharimat Umm al Muwayghir,Kharīmat Umm al Muwayghir 24.10497 54.80762 T DPR AE 01 0 74 Asia/Dubai 2011-11-06
+290597 Umm al Kurkum Umm al Kurkum Umm Kirkum,Umm Kurkum,Umm al Kurkum 24.39273 52.76497 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290598 Umm al Ḩişn Umm al Hisn Umm al Hisn,Umm al Ḩişn 23.01691 53.41646 S FT AE 01 0 118 Asia/Dubai 2011-11-06
+290599 Umm al Ḩişn Umm al Hisn Umm al Hisn,Umm al Ḩişn 23.01994 53.44238 T DPR AE 01 0 89 Asia/Dubai 2011-11-06
+290600 Umm al HiryÄn Umm al Hiryan Umm al Hiryan,Umm al HiryÄn 24.31722 55.79722 H WLL AE 01 0 280 Asia/Dubai 2011-11-06
+290601 Umm al Ḩaţab Umm al Hatab Jazirat Umm al Hatab,Jazīrat Umm al Ḩaţab,Umm al Halab Island,Umm al Hatab,Umm al Ḩaţab,Umm el Halab 24.21623 51.86389 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290602 Umm al Ghurūl Umm al Ghurul Umm al Ghurul,Umm al Ghurūl 23.84161 53.21056 L GVL AE 01 0 97 Asia/Dubai 2011-11-06
+290603 Umm al GhirbÄn Umm al Ghirban Umm al Gharban,Umm al GharbÄn,Umm al Ghirban,Umm al GhirbÄn 23.03841 53.55597 T DPR AE 01 0 71 Asia/Dubai 2011-11-06
+290604 WÄdÄ« Umm al GhÄt Wadi Umm al Ghat Wadi Umm al Ghat,WÄdÄ« Umm al GhÄt 24.87975 56.2778 H WAD AE 05 0 89 Asia/Dubai 2011-11-06
+290605 Jabal Umm al FurfÄr Jabal Umm al Furfar Jabal Umm al Farfar,Jabal Umm al FarfÄr,Jabal Umm al Furfar,Jabal Umm al FurfÄr 25.12448 56.22754 T MT AE 04 0 735 Asia/Dubai 2011-11-06
+290606 Umm al Birak Umm al Birak Umm al Barak,Umm al BarÄk,Umm al Birak,Umm al-Berak 24.56699 54.58394 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290607 Umm al BanÄdÄ«q Umm al Banadiq Umm al Banadig,Umm al Banadiq,Umm al BanÄdÄ«q 24.08705 55.27527 H WLL AE 01 0 151 Asia/Dubai 2011-11-06
+290608 Umm al AshÅ£Än Umm al Ashtan Umm al Ashtan,Umm al AshÅ£Än 23.58333 52.48333 H WLL AE 01 0 75 Asia/Dubai 2011-11-06
+290609 Umm al AshÅ£Än Umm al Ashtan Umm al Ashtan,Umm al AshÅ£Än,Umm al Lishtan,Umm al LishtÄn 23.76667 52.66667 T SAND AE AE 01 0 79 Asia/Dubai 2011-11-06
+290610 Umm al AshÅ£Än Umm al Ashtan Umm al Ashtan,Umm al AshÅ£Än,Umm al Ishtan,Umm al IshÅ£Än 23.65248 52.45047 S CMPQ AE 01 0 64 Asia/Dubai 2011-11-06
+290611 Umm ‘Alaqah Umm `Alaqah Um `Alaqa,Um ‘Alaqa,Umm `Alaqah,Umm ‘Alaqah 24.0024 53.39048 T HLL AE 01 0 23 Asia/Dubai 2011-11-06
+290612 Ruqq Umm al ‘Anbar Ruqq Umm al `Anbar Ruqq Um el Umber,Ruqq Umm al `Anbar,Ruqq Umm al ‘Anbar,Umbar 24.60999 51.8836 H SHOL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290613 Sabkhat Umm al ‘Alqah Sabkhat Umm al `Alqah Sabkhat Umm al Alqa,Sabkhat Umm al `Alqah,Sabkhat Umm al ‘Alqah 23.63234 54.85535 H SBKH AE 01 0 115 Asia/Dubai 2011-11-06
+290614 Umm al ‘Alqah Umm al `Alqah Umm al Alqa,Umm al `Alqah,Umm al ‘Alqah 23.68333 54.83333 H WLL AE 01 0 105 Asia/Dubai 2011-11-06
+290615 Umm al Abyaḑ Umm al Abyad Umm al Abyad,Umm al Abyaḑ 25.09157 55.2481 H WLLS AE 03 0 26 Asia/Dubai 2011-11-06
+290616 Umm ad Dalkh Umm ad Dalkh Umm Addalkh,Umm ad Dalkh,Umm al Dalkh 24.53655 54.14598 L OILF AE 01 0 -9999 Asia/Dubai 2011-11-06
+290617 Ghuyūţ ‘Ulayyah Ghuyut `Ulayyah Ghuyut `Ulayyah,Ghuyūţ ‘Ulayyah 23.85 54.73333 T DPR AE 01 0 96 Asia/Dubai 2011-11-06
+290618 ‘Ūd Umm KhÄlid `Ud Umm Khalid `Ud Umm Khaldi,`Ud Umm Khalid,‘Ūd Umm KhaldÄ«,‘Ūd Umm KhÄlid 25.1375 55.39861 V TREE AE 03 0 35 Asia/Dubai 2011-11-06
+290619 Ra’s al ‘Udayd Ra's al `Udayd Al Odaid,Al `Udayd,Al ‘Udayd,Ra's al `Udayd,Ra’s al ‘Udayd 24.61667 51.43333 T PT AE 01 0 -9999 Asia/Dubai 2011-11-06
+290620 Khawr al ‘Udayd Khawr al `Udayd Khawr al Wutayd,Khawr al Wuţayd,Khawr al `Udayd,Khawr al `Uwayd,Khawr al ‘Udayd,Khawr al ‘Uwayd,Khor al Odaid,Khor al Odeid,Khor al Ubeid,Khor al Wutaid,Khor al `Udaid,Khor al `Udeid,Khor al ‘Udaid,Khor al ‘Udeid 24.6 51.4 H INLT AE AE 06 0 -9999 Asia/Dubai 2011-11-06
+290622 ‘Ūd al Maţīnah `Ud al Matinah Aud al Matina,Awad al Matinah,Matina,Matinah,Matīna,Maţīnah,`Ud al Matinah,‘Ūd al Maţīnah 25.25583 55.44611 H WLLS AE 03 0 24 Asia/Dubai 2011-11-06
+290623 ‘Ūd al Maţīnah `Ud al Matinah `Ud al Matinah,‘Ūd al Maţīnah 25.23815 55.4741 L LCTY AE 03 0 39 Asia/Dubai 2011-11-06
+290624 ‘Ūd al BayḑÄ’ `Ud al Bayda' Ud al Beida,`Ud al Bayda',‘Ūd al BayḑÄ’ 25.01625 55.45533 P PPL AE 03 0 95 Asia/Dubai 2011-11-06
+290625 ‘Ūd al Atham `Ud al Atham `Ud al Atham,‘Ūd al Atham 25.15 55.71667 V TREE AE 06 0 124 Asia/Dubai 2011-11-06
+290626 ‘Ubaydil `Ubaydil `Ibeidil,`Ubaydhil,`Ubaydil,‘Ibeidil,‘Ubaydhil,‘Ubaydil 24.51667 51.33333 H WLL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290627 WÄdÄ« Å¢uwayyah Wadi Tuwayyah Wadi Tuwayyah,WÄdÄ« Å¢uwayyah 24.25722 55.68778 H WAD AE 01 0 267 Asia/Dubai 2011-11-06
+290628 Sayḩ Ţuwayyah Sayh Tuwayyah Sayh Tuwayyah,Sayḩ Ţuwayyah 24.39139 55.8275 T PLN AE 00 0 327 Asia/Dubai 2011-11-06
+290629 Sayḩ Tuwaysah Sayh Tuwaysah Sayh Tuways,Sayh Tuwaysah,Sayḩ Tuways,Sayḩ Tuwaysah 24.29278 55.505 T DPR AE AE 01 0 195 Asia/Dubai 2011-11-06
+290630 Ţawī Ţuwayli‘ Tawi Tuwayli` Tawi Tawaila,Tawi Tuwayli`,Tawi Tuwayyilah,Ţawī Tawaila,Ţawī Ţuwayli‘,Ţawī Ţuwayyilah 24.97679 55.7508 H WLL AE 06 0 171 Asia/Dubai 2011-11-06
+290631 Kharīmat Ţuwaylah Kharimat Tuwaylah Kharimat Tawaila,Kharimat Tuwaylah,Kharmat Tuwaylah,Kharmat Ţuwaylah,Kharīmat Ţuwaylah 24.1361 54.82632 T TRGD AE 01 0 92 Asia/Dubai 2011-11-06
+290632 Tuwayhil Tuwayhil Tuwayhil 23.4594 53.29148 H WLL AE 01 0 160 Asia/Dubai 2011-11-06
+290633 Jabal Tu‘ūs Jabal Tu`us Jabal Tu`us,Jabal Tus,Jabal Tu‘ūs 25.29958 56.11017 T HLL AE 04 0 550 Asia/Dubai 2011-11-06
+290634 Ţurayf Turayf Turayf,Ţurayf 23.0742 53.80161 T DPR AE 01 0 70 Asia/Dubai 2011-11-06
+290635 Ţunayq Tunayq Tanaij,Tanaiq,Tunaij,Tunayq,Ţunayq 25.86476 56.04169 L TRB AE 05 0 435 Asia/Dubai 2011-11-06
+290636 Tunayq Tunayq Tanaij,Tanaiq,Tunaij,Tunayq 25.26139 55.94944 L TRB AE 06 0 156 Asia/Dubai 2011-11-06
+290637 ‘Aqabat Tūmaytayn `Aqabat Tumaytayn `Aqabat Tumaytayn,‘Aqabat Tūmaytayn 25.47656 56.35033 T PASS AE 04 0 17 Asia/Dubai 2011-11-06
+290638 Ţawī Ţubūl Tawi Tubul Tawi Tubul,Ţawī Ţubūl 24.22687 55.03957 H WLL AE 01 0 133 Asia/Dubai 2011-11-06
+290639 Jabal Ţubayqah Jabal Tubayqah Jabal Tubayqah,Jabal Ţubayqah 24.07825 56.00668 T HLL AE 01 0 429 Asia/Dubai 2011-11-06
+290640 Trucial Coast Trucial Coast Al Sahil,Al SÄḩil,Arab Coast,Pirate Coast,Sahil `Oman,Sahil `Uman,Sahil as Sulh al Bahri,Shamal,ShamÄl,SÄhil ‘OmÄn,SÄhil ‘UmÄn,SÄḩil aÅŸ Åžulḩ al BaḩrÄ«,Trucial Coast,Trucial Oman,Trucial `Uman,Trucial ‘Uman 24 53 L RGN AE AE 00 0 37 Asia/Dubai 2011-11-06
+290641 Tina Tina Tina 23.81243 55.37423 T DUNE AE 01 0 182 Asia/Dubai 2011-11-06
+290642 Sabkhat Thuwaymah Sabkhat Thuwaymah Sabkhat Thuwaymah 24.0275 55.66806 L SALT AE 01 0 227 Asia/Dubai 2011-11-06
+290643 ‘UrqÅ«b ThurayyÄ `Urqub Thurayya `Urqub Thurayya,‘UrqÅ«b ThurayyÄ 24.9 55.46667 T DUNE AE 03 0 139 Asia/Dubai 2011-11-06
+290644 Ţawī ath Thuqbah Tawi ath Thuqbah Tawi Thuqbah,Tawi ath Thuqbah,Ţawī Thuqbah,Ţawī ath Thuqbah 25.34611 55.84722 H WLL AE AE 07 0 111 Asia/Dubai 2011-11-06
+290645 Ţawī Thuqaybah Tawi Thuqaybah Tawi Thuqaybah,Ţawī Thuqaybah 24.94829 55.81388 H WLL AE 06 0 190 Asia/Dubai 2011-11-06
+290646 Ţawī Thuqaybah Tawi Thuqaybah Tawi Thuqaybah,Ţawī Thuqaybah 23.55 55.28333 H WLL AE 01 0 181 Asia/Dubai 2011-11-06
+290647 Sabkhat Thuqaybah Sabkhat Thuqaybah Sabkhat Thuqaybah 23.58997 55.19693 H SBKH AE 01 0 114 Asia/Dubai 2011-11-06
+290648 Khawr Thumayrīyah Khawr Thumayriyah Khawr Thumayriyah,Khawr Thumayrīyah,Themairiyyah 24.15274 53.0014 H CHNM AE 01 0 -9999 Asia/Dubai 2011-11-06
+290649 Thumayrīyah Thumayriyah Themairiyya,Themeiriyyah,Thimairiyah,Thumayriyah,Thumayrīyah 24.15033 53.0169 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290650 Thubaybah Thubaybah Thubaybah 23.68333 54.61667 H WLL AE 01 0 117 Asia/Dubai 2011-11-06
+290651 WÄdÄ« Thayb Wadi Thayb Wadi Thayb,Wadi Theeb,WÄdÄ« Thayb 25.24914 56.35124 H WAD AE 04 0 96 Asia/Dubai 2011-11-06
+290652 Jabal Thayb Jabal Thayb Jabal Thaib,Jabal Thayb 25.25854 56.31202 T MT AE 04 0 386 Asia/Dubai 2011-11-06
+290653 Thawrīyah Thawriyah Thawriyah,Thawrīyah 23.02531 53.9109 T DPR AE 01 0 68 Asia/Dubai 2011-11-06
+290654 Thawrīyah Thawriyah Thawriyah,Thawrīyah 22.99797 53.76585 T DPR AE 01 0 60 Asia/Dubai 2011-11-06
+290655 Khabb ath Thawr Khabb ath Thawr Khabb ath Thawr 24.2597 54.64343 T SAND AE 01 0 17 Asia/Dubai 2011-11-06
+290656 WÄdÄ« ThawbÄn Wadi Thawban Wadi Thauban,Wadi Thawban,WÄdÄ« Thauban,WÄdÄ« ThawbÄn 25.28582 56.04058 H WAD AE 04 0 225 Asia/Dubai 2011-11-06
+290657 Jabal ThawbÄn Jabal Thawban Jabal Thawban,Jabal ThawbÄn 25.32944 56.10306 T MT AE 04 0 726 Asia/Dubai 2011-11-06
+290658 TharwÄnÄ«yah Tharwaniyah Tharwaniyah,Tharwaniyya,Tharwaniyyah,TharwÄniyya,TharwÄniyyah,TharwÄnÄ«yah 23.11088 54.01572 P PPL AE 01 0 191 Asia/Dubai 2011-11-06
+290659 Thara’awn Thara'awn Thara'awn,Thara’awn 22.91004 54.32293 T DPR AE 01 0 162 Asia/Dubai 2011-11-06
+290660 Jabal ThÄnÄ« Jabal Thani Jabal Thanais,Jabal Thani,Jabal ThÄnÄ« 25.02249 55.78912 T HLL AE 06 0 267 Asia/Dubai 2011-11-06
+290661 Thamūd Thamud Thamud,Thamūd 24.78333 55.28333 T TRGD AE 03 0 88 Asia/Dubai 2011-11-06
+290662 Barqat ThÄmir Barqat Thamir Barqat Thamir,Barqat ThÄmir 23.79619 52.66627 T DUNE AE 01 0 74 Asia/Dubai 2011-11-06
+290663 Bid‘at ThallÄb Bid`at Thallab Bid`at Thallab,Bid`ath Thalab,Bid‘at ThallÄb,Bid‘ath ThalÄb 23.83333 53.3 H WLL AE 01 0 89 Asia/Dubai 2011-11-06
+290664 Ţayyibah Tayyibah Taiyibah,Tayibah,Tayiban,Tayyibah,Ţayyibah 25.41228 56.17075 P PPL AE 04 0 430 Asia/Dubai 2011-11-06
+290665 Å¢awÄ« Å¢ayy Tawi Tayy Tawi Tai,Tawi Tayy,Å¢awÄ« Å¢ayy,Å¢ÄwÄ« Tai 25.23333 55.55 H WLL AE 03 0 42 Asia/Dubai 2011-11-06
+290666 Ţawī Ţayrī Tawi Tayri Tawi Tayri,Ţawī Ţayrī 25.45472 55.60611 H WLL AE 07 0 16 Asia/Dubai 2011-11-06
+290667 Ḩadd aţ Ţayr Hadd at Tayr Hadd at Tayr,Ḩadd aţ Ţayr 24.3713 51.83258 H RF AE 01 0 -9999 Asia/Dubai 2011-11-06
+290668 Nadd aÅ£ Å¢arÅ«sh Nadd at Tarush Nadd Tawsha,Nadd Tawshah,Nadd at Tarush,Nadd aÅ£ Å¢arÅ«sh,Nadd Å¢awshah,Nadd Å¢awshÄ 25.14929 55.37296 T DUNE AE 03 0 22 Asia/Dubai 2011-11-06
+290669 WÄdÄ« Å¢awÄ«yayn Wadi Tawiyayn Wadi Tawiyayn,WÄdÄ« Å¢awÄ«yayn 25.5575 56.07694 H WAD AE 04 0 185 Asia/Dubai 2011-11-06
+290670 Ţawīyayn Tawiyayn Tawiyain,Tawiyayn,Tawyayn,Tuwiyain,Ţawīyayn 25.55778 56.07667 H WLL AE AE 04 0 185 Asia/Dubai 2011-11-06
+290671 Ţawī Bin ‘Asīl Tawi Bin `Asil Tawi Bin `Asil,Ţawī Bin ‘Asīl 24.20368 54.6095 L LCTY AE 01 0 31 Asia/Dubai 2011-11-06
+290672 Ţawī Bid‘ Sa‘īd Tawi Bid` Sa`id Tawi Bid` Sa`id,Ţawī Bid‘ Sa‘īd 24.45084 54.74048 T SAND AE 01 0 33 Asia/Dubai 2011-11-06
+290673 WÄdÄ« TawÄh Wadi Tawah Wadi Tawah,WÄdÄ« TawÄh 24.98978 56.1243 H WAD AE 05 0 295 Asia/Dubai 2011-11-06
+290674 Jabal TawÄh Jabal Tawah Jabal Tawah,Jabal TawÄh 24.99639 56.12398 T MT AE 05 0 306 Asia/Dubai 2011-11-06
+290675 Ţawī Tasharawīyah Tawi Tasharawiyah Tawi Tasharawiyah,Ţawī Tasharawīyah 25.28942 55.89526 H WLL AE 06 0 105 Asia/Dubai 2011-11-06
+290676 Ţarūqah Taruqah Taruqah,Ţarūqah 23.02725 53.88404 T DPR AE 01 0 69 Asia/Dubai 2011-11-06
+290677 Ţarūfah Tarufah Tarufa,Tarufah,Ţarūfah 23.08936 53.83218 L OAS AE 01 0 86 Asia/Dubai 2011-11-06
+290678 Ţawī Tarish Tawi Tarish Tawi Tarish,Ţawī Tarish 23.58333 54.61667 H WLL AE 01 0 140 Asia/Dubai 2011-11-06
+290679 Ţarīqat Ja‘d Tariqat Ja`d Tariqat Ja`d,Ţarīqat Ja‘d 25.52852 56.15144 P PPL AE 04 0 357 Asia/Dubai 2011-11-06
+290680 Å¢arÄ«f KalbÄ Tarif Kalba Tarif Kalba,Å¢arÄ«f KalbÄ 25.0695 56.33115 P PPL AE 06 0 30 Asia/Dubai 2011-11-06
+290681 Ţarīf Tarif Al-Tarif,Al-Tarīf,At Tarif,At Turayf,Aţ Ţarīf,Aţ Ţurayf,Taraif,Tarif,Ţarīf 24.05399 53.76347 P PPL AE 01 0 24 Asia/Dubai 2011-11-06
+290682 Ţarīf Tarif Tarif,Ţarīf 24.03333 53.76667 T HLL AE 01 0 13 Asia/Dubai 2011-11-06
+290683 Qurayn aţ Ţarib Qurayn at Tarib Qurayn at Tarib,Qurayn aţ Ţarib 25.09414 55.81301 T HLL AE 06 0 216 Asia/Dubai 2011-11-06
+290684 Sayḩ Å¢arfÄ’ Sayh Tarfa' Sayh Tarfa',Sayḩ Å¢arfÄ’ 23.21358 55.18286 T DPR AE 01 0 154 Asia/Dubai 2011-11-06
+290685 MushÄsh Å¢arfÄ’ Mushash Tarfa' Mushash Tarfa',MushÄsh Å¢arfÄ’ 24.04622 51.69787 H WLL AE 01 0 34 Asia/Dubai 2011-11-06
+290686 Qarn at Tarb Qarn at Tarb Qarn al Tarab,Qarn at Tarb 24.45094 55.67408 T HLL AE 01 0 306 Asia/Dubai 2011-11-06
+290687 Ţaraq Taraq Taraq,Tereg,Ţaraq 23.11656 53.60697 P PPL AE 01 0 181 Asia/Dubai 2011-11-06
+290688 Å¢arÄhÄ«f Tarahif Tarahif,Å¢arÄhÄ«f 22.91769 53.33204 T DPR AE 01 0 179 Asia/Dubai 2011-11-06
+290689 WÄdÄ« aÅ£ Å¢araf Wadi at Taraf Wadi at Taraf,WÄdÄ« aÅ£ Å¢araf 25.41486 56.32874 H WAD AE 04 0 69 Asia/Dubai 2011-11-06
+290690 WÄdÄ« Tarabat Wadi Tarabat Wadi Tarabat,WÄdÄ« Tarabat 24.10167 55.71444 H WAD AE 01 0 235 Asia/Dubai 2011-11-06
+290691 Tall FÄḩah Tall Fahah Tall Fahah,Tall FÄḩah 23.95216 52.35299 L LCTY AE 01 0 14 Asia/Dubai 2011-11-06
+290692 Ḩadd aţ Ţallah Hadd at Tallah Hadd al Tahlei,Hadd at Tahli,Hadd at Tallah,Hadd at Thalei,Ḩadd at Tahlī,Ḩadd aţ Ţallah 24.66667 54.55 H SHOL AE AE 01 0 -9999 Asia/Dubai 2011-11-06
+290693 Dawḩat Tallah Dawhat Tallah Dawhat Tallah,Dawhat Tullah,Dawḩat Tallah,Dawḩat Tullah 24.42605 51.3286 H BGHT AE 01 0 1 Asia/Dubai 2011-11-06
+290694 Dawḩat Å¢allÄb Dawhat Tallab Dawhat Talab,Dawhat Tallab,Dawhat an Nakhlah,Dawḩat an Nakhlah,Dawḩat Å¢alab,Dawḩat Å¢allÄb,Dohat Tallab,Dohat Tullab,Dohat TullÄb,Dohat an Nakhala,Dohat ṬallÄb,Duhat an Nakhalah 24.2708 51.64849 H BAY AE 01 0 -9999 Asia/Dubai 2011-11-06
+290695 Sydney Hill Sydney Hill Sydney Hill 24.33333 52.6 T HLL AE 01 0 124 Asia/Dubai 2011-11-06
+290696 NaqÄ SuwayÅ£ah Naqa Suwaytah Naqa Suwaytah,NaqÄ SuwayÅ£ah 24.34939 55.59034 T DUNE AE 01 0 247 Asia/Dubai 2011-11-06
+290697 Å¢awÄ« SuwayḩÄn Tawi Suwayhan Tawi Suwayhan,Å¢awÄ« SuwayḩÄn 24.43584 55.25248 H WLL AE 01 0 123 Asia/Dubai 2011-11-06
+290698 Sayḩ SuwayḩÄn Sayh Suwayhan Sayh Suwayhan,Sayḩ SuwayḩÄn 24.44981 55.28275 H WAD AE 01 0 158 Asia/Dubai 2011-11-06
+290699 Ramlat SuwayḩÄn Ramlat Suwayhan Ramlat Suwaihan,Ramlat Suwayhan,Ramlat SuwayḩÄn 24.46087 55.26387 T DUNE AE 01 0 149 Asia/Dubai 2011-11-06
+290700 Ra’s Suwayfah Ra's Suwayfah Ra's Suwayfah,Ra’s Suwayfah 25.59594 56.35239 T PT AE 04 0 -9999 Asia/Dubai 2011-11-06
+290701 Farīq Suwayfah Fariq Suwayfah Fariq Suwayfah,Farīq Suwayfah 25.59256 56.34525 S CMP AE 04 0 60 Asia/Dubai 2011-11-06
+290702 Suwayfah Suwayfah Suwayfah 25.59043 56.36261 L LCTY AE 04 0 -9999 Asia/Dubai 2011-11-06
+290703 SuwaydÄn Suwaydan Suwaydan,SuwaydÄn 25.12436 55.7975 L AREA AE 06 0 138 Asia/Dubai 2011-11-06
+290704 WÄdÄ« SuwaydÄ’ Wadi Suwayda' Wadi Suwayda',WÄdÄ« SuwaydÄ’ 24.45696 55.54523 T TRGD AE 01 0 261 Asia/Dubai 2011-11-06
+290705 Ţawī SuwaydĒ Tawi Suwayda' Tawi Suwayda',Ţawī SuwaydĒ 25.14194 55.29972 H WLL AE 03 0 24 Asia/Dubai 2011-11-06
+290706 SuwaydÄ’ Suwayda' Suwaida,Suwayda',SuwaydÄ’ 25.11667 55.3 L LCTY AE 03 0 6 Asia/Dubai 2011-11-06
+290707 Sut Sut Sut 23.71667 54.53333 H WLL AE 01 0 133 Asia/Dubai 2011-11-06
+290708 Surayţ Surayt Serait,Surayt,Surayţ 23.12132 53.95075 L OAS AE 01 0 94 Asia/Dubai 2011-11-06
+290709 WÄdÄ« SÅ«r Wadi Sur Wadi Sur,WÄdÄ« SÅ«r 25.08333 56.36667 H WAD AE 06 0 -9999 Asia/Dubai 2011-11-06
+290710 Şūr Sur Sur,Şūr 25.09406 56.34827 P PPL AE 06 0 23 Asia/Dubai 2011-11-06
+290711 Suqayyah Suqayyah Suqayyah 24.57218 55.55891 L LCTY AE 01 0 253 Asia/Dubai 2011-11-06
+290712 Sunayyim Sunayyim Sunayyim 23.96236 55.40653 T DUNE AE 01 0 145 Asia/Dubai 2011-11-06
+290713 Baḩr Sunayţ Bahr Sunayt Bahr Sunayt,Baḩr Sunayţ 25.61667 56.25 H WAD AE 00 0 7 Asia/Dubai 2011-11-06
+290714 Sumbrair Sumbrair Sumbrair,Sumbrayir,Åžumbrayir 25.60082 56.2844 P PPL AE 04 0 21 Asia/Dubai 2011-11-06
+290715 Ra’s Sumayrah Ra's Sumayrah Ra's Sumayrah,Ras Semaira,Ras Sumaira,Ra’s Sumayrah,RÄs Semaira 24.32243 51.44653 T PT AE 01 0 -9999 Asia/Dubai 2011-11-06
+290716 ImshÄsh as Sumayrah Imshash as Sumayrah Imshash Semaira,Imshash al-Semeirah,Imshash as Sumayrah,ImshÄsh Semaira,ImshÄsh al-Semeirah,ImshÄsh as Sumayrah,Tawi Sumayrah,Å¢awÄ« Sumayrah 24.27873 51.42068 H WLL AE 01 0 51 Asia/Dubai 2011-11-06
+290717 Dawḩat as Sumayrah Dawhat as Sumayrah Al Sumaira,Dawhat as Sumayrah,Dawḩat as Sumayrah 24.31884 51.54839 H BAY AE 01 0 -9999 Asia/Dubai 2011-11-06
+290718 Sayḩ as Sumayḩ Sayh as Sumayh Sayh as Sumayh,Sayḩ as Sumayḩ,Sih al-Semeih,Sih as Semeih,Sih as Sumayh,Sumayh,Sumayḩ,Sīḥ al-Semeiḥ,Sīḩ as Sumayḩ 24.7278 54.78697 T TRGD AE 01 0 16 Asia/Dubai 2011-11-06
+290719 Birkat Sumayḩ Birkat Sumayh Birkat Sumaih,Birkat Sumayh,Birkat Sumayḩ,Samaih,Semaih,Smeih 24.72276 54.77993 H WLL AE 01 0 18 Asia/Dubai 2011-11-06
+290720 Å¢awÄ« SulÅ£Än SÄlim Tawi Sultan Salim Tawi Sultan Salim,Å¢awÄ« SulÅ£Än SÄlim 25.02181 55.8195 H WLL AE 06 0 170 Asia/Dubai 2011-11-06
+290721 JazÄ«rat aÅŸ ŞīlÄ«yÄ Jazirat as Siliya Jazirat Sulayyah,Jazirat as Siliya,JazÄ«rat aÅŸ ŞīlÄ«yÄ,JazÄ«rat Åžulayyah 24.18286 52.8921 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290722 Å¢awÄ« SulaymÄt Tawi Sulaymat Al-Seleimat,Al-SeleimÄt,Tawi Sulaymat,Tawi Suleimat,TÄwÄ« Suleimat,Å¢awÄ« SulaymÄt 24.23064 55.59382 H WLL AE 01 0 251 Asia/Dubai 2011-11-06
+290723 Sayḩ SulaymÄt Sayh Sulaymat Sayh Sulaymat,Sayḩ SulaymÄt 24.19639 55.56278 T TRGD AE 01 0 224 Asia/Dubai 2011-11-06
+290724 Sayḩ SulaymÄn Sayh Sulayman Sayh Sulayman,Sayḩ SulaymÄn 24.67704 55.47051 T TRGD AE 03 0 149 Asia/Dubai 2011-11-06
+290725 Ḩadabat Sukhub Hadabat Sukhub Hadabat Sakhub,Hadabat Sukhub,Ḩadabat Sakhub,Ḩadabat Sukhub 24.82094 55.53095 T DUNE AE 03 0 157 Asia/Dubai 2011-11-06
+290726 Å¢awÄ« Suhaylah Tawi Suhaylah Tawi Saheila,Tawi Suhaylah,Tawi Suheila,TÄwÄ« Saheila,TÄwÄ« Suheila,Å¢awÄ« Suhaylah 25.36667 55.95 H WLL AE 07 0 184 Asia/Dubai 2011-11-06
+290727 Suḩaybah Suhaybah Suhaybah,Suḩaybah 24.93877 56.15754 P PPL AE 05 0 351 Asia/Dubai 2011-11-06
+290728 WÄdÄ« Suftah Wadi Suftah Wadi Suftah,WÄdÄ« Suftah 25.46364 56.11519 H WAD AE 05 0 297 Asia/Dubai 2011-11-06
+290729 Şufayrī Sufayri Sufayri,Şufayrī 24.81168 56.12646 P PPL AE 02 0 309 Asia/Dubai 2011-11-06
+290730 Sayḩ Şubrah Sayh Subrah Sayh Subrah,Sayḩ Şubrah 24.05023 55.49348 T TRGD AE 01 0 196 Asia/Dubai 2011-11-06
+290731 ‘Aqabat as Subaykhah `Aqabat as Subaykhah `Aqabat as Subaykhah,‘Aqabat as Subaykhah 25.5763 56.33881 T PASS AE 04 0 35 Asia/Dubai 2011-11-06
+290732 Subaykhah Subaykhah Subaykhah 25.5695 56.33907 L LCTY AE 04 0 256 Asia/Dubai 2011-11-06
+290733 Subayḩīyah Subayhiyah Subayhiyah,Subayḩīyah 25.40028 56.36417 V CULT AE 06 0 -9999 Asia/Dubai 2011-11-06
+290734 Stutter Shoal Stutter Shoal Stutter Shoal 24.23777 52.42787 H SHOL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290735 Stokes Bluff Stokes Bluff Stokes Bluff 24.3 52.63333 T CLF AE 01 0 6 Asia/Dubai 2011-11-06
+290736 Mount Stewart Mount Stewart Mount Stewart 24.33288 52.59674 T HLL AE 01 0 60 Asia/Dubai 2011-11-06
+290737 South YÄsÄt Channel South Yasat Channel South Yasat Channel,South YÄsÄt Channel 24.13797 51.98182 H CHNM AE 01 0 -9999 Asia/Dubai 2011-11-06
+290738 South Faraydat South Faraydat Faraijdat,Fereijid,South Faraydat,South Furayjidat,South FurayjidÄt 24.38333 51.71667 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290740 Å¢awÄ« Sirrah Tawi Sirrah Tawi Sirra,Tawi Sirrah,TÄwÄ« Sirra,Å¢awÄ« Sirrah 25.45114 55.61266 H WLL AE 07 0 31 Asia/Dubai 2011-11-06
+290741 Şīr Bū Nu‘ayr Sir Bu Nu`ayr Jazirat Siri Bu Naybar,Jazīrat Sīrī Bū Naybar,Jezirat Sir Bu Na`air,Jezirat Sir Bu Na‘air,Sir Abu Nu`air,Sir Abu Nu`ayr,Sir Abu Nu‘air,Sir Bu Nu`air,Sir Bu Nu`ayr,Sir bu Na`air Island,Sīr bu Na‘air Island,Şīr Abū Nu‘ayr,Şīr Bū Nu‘ayr,Ṣīr Bū Nu‘air 25.23305 54.2181 T ISL AE 01 0 15 Asia/Dubai 2011-11-06
+290742 Şīr BanÄ« YÄs Sir Bani Yas Al Yas,Al YÄs,Jezirat Yas,JezÄ«rat Yas,Sir Bani Yas,Sir Banias,Sir Beni Yas,Yas Island,Şīr BanÄ« YÄs 24.32589 52.60128 T ISL AE 01 0 124 Asia/Dubai 2011-11-06
+290743 SÄ«rat al Khawr Sirat al Khawr Sirat al Khawr,SÄ«rat al Khawr 25.35326 56.37784 T ISL AE 04 0 -9999 Asia/Dubai 2011-11-06
+290744 Suwayfat aş Şīr Suwayfat as Sir Suwayfat as Sir,Suwayfat aş Şīr 25.5188 56.36949 T PT AE 04 0 -9999 Asia/Dubai 2011-11-06
+290746 WÄdÄ« Sinnah Wadi Sinnah Wadi Sinnah,WÄdÄ« Sinnah 25.50796 56.19523 H WAD AE 04 0 124 Asia/Dubai 2011-11-06
+290747 Sinnah Sinnah Sinnah 25.50868 56.16772 P PPL AE 04 0 198 Asia/Dubai 2011-11-06
+290748 SinÄdil Sinadil Sinadil,SinÄdil 24.81095 56.02511 P PPL AE 02 0 424 Asia/Dubai 2011-11-06
+290749 Nada Sima Nada Sima Nada Sima 24.18333 55.36667 T DUNE AE 01 0 198 Asia/Dubai 2011-11-06
+290750 Ra’s as Silmīyah Ra's as Silmiyah Ra's as Silmiyah,Ra’s as Silmīyah 24.25278 54.52889 T DUNE AE 01 0 8 Asia/Dubai 2011-11-06
+290751 Silmīyah Silmiyah Silmiya,Silmiyah,Silmīya,Silmīyah 24.2 54.35 T HLL AE AE 01 0 6 Asia/Dubai 2011-11-06
+290752 Silmīyah Silmiyah Al-Silaimiyyah,Silmiyah,Silmīyah 24.22404 54.46374 T DUNE AE 01 0 13 Asia/Dubai 2011-11-06
+290753 Sayḩ Silm Sayh Silm Sayh Silm,Sayḩ Silm 24.41779 55.31025 T TRGD AE 01 0 158 Asia/Dubai 2011-11-06
+290754 Jabal Silḩū Bilḩū Jabal Silhu Bilhu Jabal Silhu Bilhu,Jabal Silḩū Bilḩū 25.15146 56.06771 T MT AE 05 0 607 Asia/Dubai 2011-11-06
+290755 Ra’s as Sila‘ Ra's as Sila` Ra's as Sil`,Ra's as Sila`,Ra’s as Sila‘,Ra’s as Sil‘ 24.05 51.78333 T PT AE 01 0 1 Asia/Dubai 2011-11-06
+290756 Dawḩat as Sila‘ Dawhat as Sila` Dawhat as Sila`,Dawḩat as Sila‘ 23.96667 51.93333 H INLT AE 01 0 -9999 Asia/Dubai 2011-11-06
+290757 WÄdÄ« SÄ«jÄ« Wadi Siji Wadi Nakh,Wadi Siji,Wadi as Siji,WÄdÄ« Nakh,WÄdÄ« SÄ«jÄ«,WÄdÄ« as SÄ«jÄ« 25.2736 56.03543 H WAD AE 00 0 225 Asia/Dubai 2011-11-06
+290758 Jabal Sījī Jabal Siji Jabal Siji,Jabal Sījī 25.2436 56.12194 T MT AE 04 0 664 Asia/Dubai 2011-11-06
+290759 Tawi Siji Tawi Siji Siji,Sījī,Tawi Siji,Tawi as Siji,Ţawī as Sījī 25.24764 56.07719 P PPL AE 04 0 324 Asia/Dubai 2011-11-06
+290760 Wadi Saha Wadi Saha Wadi Saha,Wadi Siha',WÄdÄ« ÅžihÄ’ 25.3828 56.29541 H WAD AE 00 0 320 Asia/Dubai 2011-11-06
+290761 Jabal ÅžihÄ’ Jabal Siha' Jabal Siha',Jabal ÅžihÄ’ 25.33931 56.276 T MT AE 00 0 788 Asia/Dubai 2011-11-06
+290762 WÄdÄ« SifÅ«nÄ« Wadi Sifuni Wadi Sifuni,WÄdÄ« SifÅ«nÄ« 25.19333 56.01389 H WAD AE 05 0 189 Asia/Dubai 2011-11-06
+290763 Sayḩ as Sidrah Sayh as Sidrah Sayh Sadrah,Sayh as Sidrah,Sayḩ Sadrah,Sayḩ as Sidrah,Sidra,Sih as Sidrah,Sīḩ as Sidrah 24.81824 54.9264 T TRGD AE 01 0 31 Asia/Dubai 2011-11-06
+290764 WÄdÄ« Sidr Wadi Sidr Wadi Sidr,WÄdÄ« Sidr 25.42182 56.09854 H WAD AE 04 0 290 Asia/Dubai 2011-11-06
+290765 Jabal Sidr Jabal Sidr Jabal Sidr 25.36833 56.34 T HLL AE 06 0 11 Asia/Dubai 2011-11-06
+290766 WÄdÄ« Sadakh Wadi Sadakh Wadi Sadakh,Wadi Sidakh,WÄdÄ« Sadakh,WÄdÄ« Sidakh 25.56929 56.06399 H WAD AE 04 0 132 Asia/Dubai 2011-11-06
+290767 SÄ«bat al AshkharÄt Sibat al Ashkharat Sibat al Ashkharat,SÄ«bat al AshkharÄt 25.61667 56.26667 S CMTY AE 04 0 19 Asia/Dubai 2011-11-06
+290768 WÄdÄ« Shuway Wadi Shuway Wadi Shuway,Wadi Shuwayy,WÄdÄ« Shuway,WÄdÄ« Shuwayy 25.23142 56.20244 H WAD AE 04 0 233 Asia/Dubai 2011-11-06
+290769 WÄdÄ« Shuways Wadi Shuways Wadi Shuways,WÄdÄ« Shuways 25.18957 56.33323 H WAD AE 04 0 347 Asia/Dubai 2011-11-06
+290770 Jabal Shuways Jabal Shuways Jabal Shuways 25.17617 56.3459 T HLL AE 04 0 171 Asia/Dubai 2011-11-06
+290771 Al Quwayz Al Quwayz Al Quwayz,Chuwais,Kuways,Shuways 25.78102 55.9787 P PPLX AE 05 0 24 Asia/Dubai 2011-11-06
+290772 JazÄ«rat ShuwayhÄt Jazirat Shuwayhat Jazirat Mashat,Jazirat Showayhat,Jazirat Shuwayhat,JazÄ«rat Mashat,JazÄ«rat ShowayhÄt,JazÄ«rat ShuwayhÄt,Shuwaihat,ShuwaihÄt,Shuweihat,ShuweihÄt 24.11391 52.43972 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290773 Bid‘ Shuwaybir Bid` Shuwaybir Bid` Shuwaybir,Bida` Shuwaibah,Bidau' Shuaibar,Bidau' Suaibar,Bidau’ Shuaibar,Bidau’ Suaibar,Bida‘ Shuwaibah,Bid‘ Shuwaybir,Budu` Shuaibar,Budu` Shuwaibir,Budu` Shuwaybir,Budu‘ Shuwaibir,Budū‘ Shuaibar,Budū‘ Shuwaybir,Shawaibir 24.0958 54.58919 H WLL AE 01 0 46 Asia/Dubai 2011-11-06
+290774 Shū Triyyah Shu Triyyah Shu Triyyah,Shū Triyyah 24.24938 54.29978 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290775 Shuray‘ah Shuray`ah Shuray`ah,Shuray‘ah 24.3 53.61667 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290776 Shunayyin Shunayyin Shunayyin 24.05604 54.46374 T SAND AE 01 0 39 Asia/Dubai 2011-11-06
+290777 Shunayyin Shunayyin Shunayyin 24.10632 54.39287 L LCTY AE 01 0 16 Asia/Dubai 2011-11-06
+290778 Shunayyin Shunayyin Shinaiyin,Shunaiyin,Shunayyin 24.21667 54.41667 T HLL AE AE 01 0 3 Asia/Dubai 2011-11-06
+290779 Buday‘ Shumrūkh Buday` Shumrukh Buday` Shumrukh,Buday‘ Shumrūkh,Shumrukh,Shumrūkh 24.77232 55.7849 H WLL AE 01 0 302 Asia/Dubai 2011-11-06
+290780 Sayḩ Shumayrīkh Sayh Shumayrikh Sayh Shumayrikh,Sayḩ Shumayrīkh 24.71557 55.4203 T TRGD AE 03 0 145 Asia/Dubai 2011-11-06
+290781 Shumaylīyah Shumayliyah Ash Shumailiya,Ash Shumailīya,Ash Shumayliyah,Ash Shumaylīyah,Shamailiya,Shamailiyah,Shamailīyah,Shamayliyah,Shamaylīyah,Shumailiyah,Shumayliyah,Shumaylīyah 25.33333 56.33333 L AREA AE AE 06 0 426 Asia/Dubai 2011-11-06
+290782 Jabal Shughayr Jabal Shughayr Jabal Shughayr 25.4 56.33333 T HLL AE 04 0 55 Asia/Dubai 2011-11-06
+290783 Ţawī Shubayşī Tawi Shubaysi Tawi Shubaysi,Ţawī Shubayşī 24.16278 55.05729 H WLL AE 01 0 120 Asia/Dubai 2011-11-06
+290784 Nadd ash ShibÄ Nadd ash Shiba Nad Shibeih,Nadd Shubayh,Nadd Shubayḩ,Nadd ash Shiba,Nadd ash ShibÄ 25.14583 55.33417 P PPL AE AE 03 0 23 Asia/Dubai 2011-11-06
+290785 Shu‘ayb ‘Ūd Shu`ayb `Ud Shu`ayb `Ud,Shu‘ayb ‘Ūd 24.74968 55.79034 V TREE AE 00 0 253 Asia/Dubai 2011-11-06
+290786 Shu‘ayb Şaghīr Shu`ayb Saghir Shu`ayb Saghir,Shu‘ayb Şaghīr 24.74944 55.82028 V TREE AE 01 0 311 Asia/Dubai 2011-11-06
+290787 Sayḩ Shu‘ayb Sayh Shu`ayb Sayh Shu`ayb,Sayh ash Shu`ayb,Sayḩ Shu‘ayb,Sayḩ ash Shu‘ayb,Shu`aib,Shu‘aib,Sih Shu`aib,Sīḩ Shu‘aib 24.89786 54.96311 T TRGD AE 00 0 17 Asia/Dubai 2011-11-06
+290788 Raml ash Shu‘ayb Raml ash Shu`ayb Raml ash Shu`ayb,Raml ash Shu‘ayb 24.8757 55.0429 T SAND AE 03 0 30 Asia/Dubai 2011-11-06
+290789 Shīshah Shishah Shisha,Shishah,Shīshah 24.33635 54.94465 T HLL AE 01 0 65 Asia/Dubai 2011-11-06
+290790 WÄdÄ« ShÄ«ÅŸah Wadi Shisah Wadi Shisa,Wadi Shisah,WÄdÄ« ShÄ«ÅŸah 25.84028 56.1 H WAD AE AE 05 0 321 Asia/Dubai 2011-11-06
+290791 Ramlat Shīşah Ramlat Shisah Ramlat Shisah,Ramlat Shīşah 25.38835 56.02995 T DUNE AE 04 0 304 Asia/Dubai 2011-11-06
+290792 WÄdÄ« ShÄ«s Wadi Shis Wadi Shis,WÄdÄ« ShÄ«s 25.29348 56.24396 H WAD AE 06 0 408 Asia/Dubai 2011-11-06
+290793 Shīs Shis Shis,Shīs 25.29138 56.24549 P PPL AE 06 0 365 Asia/Dubai 2011-11-06
+290794 WÄdÄ« ShimÄl Wadi Shimal Wadi Shimal,WÄdÄ« ShimÄl 25.50089 56.18876 H WAD AE 04 0 158 Asia/Dubai 2011-11-06
+290795 ShimÄl Shimal Shimal,Shimil,ShimÄl 25.8178 56.01088 P PPL AE 05 0 19 Asia/Dubai 2011-11-06
+290796 KhaÅ£mat ash Shiklah Khatmat ash Shiklah Khaim ash Shikla,Khatm al-Shiklah,Khatmat ash Shiklah,KhaÅ£mat ash Shiklah,Khaá¹m al-Shiklah 24.21583 55.95306 T SPUR AE AE 01 0 392 Asia/Dubai 2011-11-06
+290797 Shidq al Kalb Shidq al Kalb Shidq al Kalb,Shudeg al-Kalb,Shudq al Kalb 23.13385 53.73315 L OAS AE 01 0 93 Asia/Dubai 2011-11-06
+290798 WÄdÄ« ShibḩÄt Wadi Shibhat Wadi Shibhat,WÄdÄ« ShibḩÄt 24.45849 55.7685 T TRGD AE 01 0 321 Asia/Dubai 2011-11-06
+290799 Shabahanat al Majann Shabahanat al Majann Ash Shibhanah,Shabahanat al Majann,Shibhanat al Mijann,ShibhÄnat al Mijann 24.01997 51.735 T PLAT AE 01 0 48 Asia/Dubai 2011-11-06
+290800 ShibÄnÄt Shibanat Shibanat,ShibÄnÄt 24.91667 55.66667 L TRB AE 00 0 190 Asia/Dubai 2011-11-06
+290801 Shi‘b al GhÄf Shi`b al Ghaf Shi`b al Ghaf,Shib al Gat,Shi‘b al GhÄf 24.05278 55.71972 P PPL AE 01 0 237 Asia/Dubai 2011-11-06
+290802 ShibÄk Shibak Shibak,ShibÄk 24.59856 55.52346 L LCTY AE 01 0 208 Asia/Dubai 2011-11-06
+290803 Jabal Shi‘Äb ash Shaybah Jabal Shi`ab ash Shaybah Jabal Sha`ab ash Shaybah,Jabal Sha‘Äb ash Shaybah,Jabal Shi`ab ash Shaybah,Jabal Shi‘Äb ash Shaybah 25.40026 56.30431 T MT AE 04 0 410 Asia/Dubai 2011-11-06
+290804 WÄdÄ« ShÄ« Wadi Shi Wadi Shi,WÄdÄ« ShÄ« 25.34983 56.35746 H WAD AE 06 0 40 Asia/Dubai 2011-11-06
+290805 Shaykh ad DimÄth Shaykh ad Dimath Shaikh al Dimath,Shaykh ad Dimath,Shaykh ad DimÄth 24.01056 53.09528 L LCTY AE AE 01 0 29 Asia/Dubai 2011-11-06
+290806 Shaydad Bin Khanfūr Shaydad Bin Khanfur Shaydad Bin Khanfur,Shaydad Bin Khanfūr 24.6932 55.44164 T SAND AE 03 0 141 Asia/Dubai 2011-11-06
+290807 ‘Urūq ash Shaybah `Uruq ash Shaybah Uruq ash Shaibah,Uruq ash Sheibah,`Uruq ash Shaybah,‘Urūq ash Shaybah 22.35 54.91667 T DUNE AE 01 0 161 Asia/Dubai 2011-11-06
+290808 Sayḩ Shawyī Sayh Shawyi Sayh Shawyi,Sayḩ Shawyī 25.65293 56.01207 T PLN AE 05 0 17 Asia/Dubai 2011-11-06
+290809 WÄdÄ« Shawkah Wadi Shawkah Wadi Shaukha,Wadi Shawkah,WÄdÄ« Shawkah 25.26761 55.8668 H WAD AE 06 0 110 Asia/Dubai 2011-11-06
+290810 Ţawī Shawkah Tawi Shawkah Tawi Shawkah,Ţawī Shawkah 25.03056 56.10694 H WLL AE 05 0 699 Asia/Dubai 2011-11-06
+290811 Jabal Shawkah Jabal Shawkah Jabal Shauka,Jabal Shawkah 25.10014 56.04331 T HLL AE 05 0 442 Asia/Dubai 2011-11-06
+290812 Shawkah Shawkah Shauka,Shawkah,Shokah 25.1 56.03333 P PPL AE AE 05 0 283 Asia/Dubai 2011-11-06
+290813 WÄdÄ« Shawiyayn Wadi Shawiyayn Wadi Shawiyayn,WÄdÄ« Shawiyayn 25.27208 56.06068 H WAD AE 04 0 247 Asia/Dubai 2011-11-06
+290814 Shawīyah Shawiyah Shawiyah,Shawīyah 25.26792 56.08149 P PPL AE 04 0 304 Asia/Dubai 2011-11-06
+290815 Å¢awÄ« ShÄÅ£ Tawi Shat Tawi Shat,Å¢awÄ« ShÄÅ£ 24.48333 55.2 H WLLQ AE 01 0 139 Asia/Dubai 2011-11-06
+290816 ShÄt Shat Shat,ShÄt 24.48614 55.19806 T SAND AE 01 0 117 Asia/Dubai 2011-11-06
+290817 Sharqīyīn Sharqiyin Sharqiyan,Sharqiyin,Sharqīyīn 25.25 56.16667 L TRB AE AE 00 0 522 Asia/Dubai 2011-11-06
+290818 Å¢awÄ« SharqÄn Tawi Sharqan Tawi Sharqan,Å¢awÄ« SharqÄn 25.38333 55.4 H WLL AE 06 0 1 Asia/Dubai 2011-11-06
+290819 Jabal Sharmah Jabal Sharmah Jabal Sharmah 25.28406 56.12845 T MT AE 04 0 594 Asia/Dubai 2011-11-06
+290820 Sharm Sharm Sharam,Sharm 25.47078 56.35319 P PPL AE 04 0 14 Asia/Dubai 2011-11-06
+290821 Jabal Sharīyah Jabal Shariyah Jabal Shariyah,Jabal Sharīyah 25.29063 56.14987 T MT AE 04 0 415 Asia/Dubai 2011-11-06
+290822 Sharīyah Shariyah Shariyah,Sharīyah 25.1 56.03333 P PPL AE 05 0 283 Asia/Dubai 2011-11-06
+290823 Sharīyah Shariyah Shariyah,Sharīyah 24.81512 56.0986 P PPL AE 02 0 319 Asia/Dubai 2011-11-06
+290824 Khawr ash ShÄriqah Khawr ash Shariqah Khawr ash Shariqah,Khawr ash ShÄriqah,Khor Sharja,Khor Sharjah,Khor ShÄrja 25.33111 55.38222 H INLT AE AE 06 0 9 Asia/Dubai 2011-11-06
+290825 Sayḩ Sharbū Sayh Sharbu Sayh Sharbu,Sayḩ Sharbū 24.81667 55.41667 T TRGD AE 03 0 125 Asia/Dubai 2011-11-06
+290826 Raml Sharbū Raml Sharbu Raml Sharbu,Raml Sharbū 24.83333 55.41667 T SAND AE 03 0 130 Asia/Dubai 2011-11-06
+290827 Sharaf Tamī Sharaf Tami Sharaf Tami,Sharaf Tamī 23.62836 55.33692 T DUNE AE 01 0 207 Asia/Dubai 2011-11-06
+290828 Sharaf Sawqar Sharaf Sawqar Sharaf Sawqar 24.33333 55.7 L LCTY AE 01 0 275 Asia/Dubai 2011-11-06
+290829 Sharaf Mundassah Sharaf Mundassah Sharaf Mundassah 24.58472 55.73722 V TREE AE 01 0 308 Asia/Dubai 2011-11-06
+290830 Sharaf JabÄrah Sharaf Jabarah Sharaf Jabara,Sharaf Jabarah,Sharaf JabÄrah 24.62804 55.77334 L LCTY AE 01 0 337 Asia/Dubai 2011-11-06
+290831 Sharaf Ḩawrah Sharaf Hawrah Sharaf Hawrah,Sharaf Ḩawrah 24.54521 55.71675 T SAND AE 01 0 318 Asia/Dubai 2011-11-06
+290832 Sharaf á¸abbah Sharaf Dabbah Sharaf Dabbah,Sharaf á¸abbah 24.55321 55.65638 L LCTY AE 01 0 288 Asia/Dubai 2011-11-06
+290833 Sharaf Bin ‘Ubayd Sharaf Bin `Ubayd Sharaf Bin `Ubayd,Sharaf Bin ‘Ubayd 24.91667 55.4 L LCTY AE 03 0 100 Asia/Dubai 2011-11-06
+290834 Sharaf al ‘AfÄr Sharaf al `Afar Sharaf al `Afar,Sharaf al ‘AfÄr 24.9516 55.44056 L LCTY AE 03 0 85 Asia/Dubai 2011-11-06
+290835 WÄdÄ« SharabÄt Wadi Sharabat Wadi Sharabat,WÄdÄ« SharabÄt 24.88063 56.21317 H WAD AE 05 0 142 Asia/Dubai 2011-11-06
+290836 Jabal Sharab Jabal Sharab Jabal Sharab 25.0138 56.0337 T MT AE 05 0 664 Asia/Dubai 2011-11-06
+290837 Jabal Sha‘rÄ’ Jabal Sha`ra' Jabal Sha`arah,Jabal Sha`ra',Jabal Sha‘arah,Jabal Sha‘rÄ’ 24.06667 56.26667 T MT AE 01 0 995 Asia/Dubai 2011-11-06
+290838 WÄdÄ« Shaqq Wadi Shaqq Wadi Shaq,Wadi Shaqq,WÄdÄ« Shaqq 25.84389 56.02139 H WAD AE AE 05 0 26 Asia/Dubai 2011-11-06
+290839 Ţawī Shaqq Tawi Shaqq Tawi Shaqq,Ţawī Shaqq 24.38244 55.60894 H WLL AE 01 0 232 Asia/Dubai 2011-11-06
+290840 Ramlat Shanţūt Bin ‘UmÄn Ramlat Shantut Bin `Uman Ramlat Shantut Bin `Uman,Ramlat Shanţūt Bin ‘UmÄn 24.26667 55.4 T DUNE AE 01 0 195 Asia/Dubai 2011-11-06
+290841 Shanţūt Ibn ‘UmÄn Shantut Ibn `Uman Shantut Bin `Uman,Shantut Ibn `Uman,Shanţūt Bin ‘UmÄn,Shanţūt Ibn ‘UmÄn 24.25432 55.42166 T TRGD AE 01 0 183 Asia/Dubai 2011-11-06
+290842 Shanţūţ Shantut Shantut,Shanţūţ 23.38142 55.30225 T DUNE AE 01 0 154 Asia/Dubai 2011-11-06
+290843 Shantuba Shantuba Shantuba 24.54867 55.73806 L LCTY AE 01 0 322 Asia/Dubai 2011-11-06
+290844 Ra’s Shandaghah Ra's Shandaghah Ra's Shandaghah,Ra’s Shandaghah 25.26667 55.28333 T PT AE 03 0 -9999 Asia/Dubai 2011-11-06
+290845 Shandaghah Shandaghah Shandaghah 25.25833 55.28333 P PPLX AE 03 0 9 Asia/Dubai 2011-11-06
+290846 ‘Araj Shamsī `Araj Shamsi `Araj Shamsi,‘Araj Shamsī 24.18944 54.70361 T DPR AE 01 0 51 Asia/Dubai 2011-11-06
+290847 ShammÄmÄ«yah Shammamiyah Shammamiyah,ShammÄmÄ«yah 23.06374 53.68898 T DPR AE 01 0 76 Asia/Dubai 2011-11-06
+290848 ShÄmis Shamis Shamis,Shams,ShÄmis 23.93333 53.7 L GASF AE AE 01 0 21 Asia/Dubai 2011-11-06
+290849 ShÄmis Shamis Shamis,ShÄmis 23.93854 53.69593 S FCL AE 01 0 41 Asia/Dubai 2011-11-06
+290851 WÄdÄ« ash ShÄmah Wadi ash Shamah Wadi ash Shamah,WÄdÄ« ash ShÄmah 25.41592 56.33835 H WAD AE 00 0 36 Asia/Dubai 2011-11-06
+290852 WÄdÄ« ash Sha‘m Wadi ash Sha`m Wadi ash Sha`m,WÄdÄ« ash Sha‘m 26.03111 56.0975 H WAD AE 05 0 143 Asia/Dubai 2011-11-06
+290853 WÄdÄ« ash ShÄl Wadi ash Shal Wadi ash Shal,WÄdÄ« ash ShÄl 25.38365 55.95383 H WAD AE 07 0 155 Asia/Dubai 2011-11-06
+290854 WÄdÄ« Shakhkh Wadi Shakhkh Wadi Shakh,Wadi Shakhkh,WÄdÄ« Shakh,WÄdÄ« Shakhkh 25.58769 56.14287 H WAD AE 04 0 228 Asia/Dubai 2011-11-06
+290855 Haḑbat Shakhbūţ Hadbat Shakhbut Hadbat Shakhbut,Haḑbat Shakhbūţ 24.29583 54.65722 T HLL AE 01 0 27 Asia/Dubai 2011-11-06
+290856 Shaitham Shaitham Shaitham,Shaithan,ShaithÄn 24.29326 54.85926 H WLL AE 01 0 71 Asia/Dubai 2011-11-06
+290857 Sayḩ Sha‘īl Sayh Sha`il Sayh Sha`il,Sayḩ Sha‘īl 24.68333 55.45 T TRGD AE 03 0 160 Asia/Dubai 2011-11-06
+290858 Qarn ShÄ’i‘ Qarn Sha'i` Qarn Sha'i`,Qarn ShÄ’i‘ 23.83933 53.28344 T HLL AE 01 0 91 Asia/Dubai 2011-11-06
+290859 Å¢awÄ« ShÄhÄ«n Tawi Shahin Tawi Shahin,Å¢awÄ« ShÄhÄ«n 25.61667 55.88333 H WLL AE 05 0 93 Asia/Dubai 2011-11-06
+290860 ShahawÄt Shahawat Sahawat,Shahawat,ShahawÄt 25.96667 56.08333 P PPL AE AE 05 0 18 Asia/Dubai 2011-11-06
+290861 ShahÄ’irah Shaha'irah Shaha'irah,ShahÄ’irah 25.38333 56.13333 L TRB AE 05 0 501 Asia/Dubai 2011-11-06
+290862 WÄdÄ« ShÄh Wadi Shah Wadi Shah,WÄdÄ« ShÄh 25.82949 56.10949 H WAD AE 05 0 202 Asia/Dubai 2011-11-06
+290863 ShÄh Shah Shah,ShÄh 23.13561 53.91652 P PPL AE 01 0 170 Asia/Dubai 2011-11-06
+290864 ShÄh Shah Shah,ShÄh 22.85 53.91667 L OILF AE 01 0 170 Asia/Dubai 2011-11-06
+290865 ShÄh Shah Shah,ShÄh 23.13333 53.91667 T DPR AE 01 0 158 Asia/Dubai 2011-11-06
+290866 ShÄh Shah Shah,ShÄh 25.89861 56.12833 P PPL AE 05 0 715 Asia/Dubai 2011-11-06
+290867 Shabqatayn Shabqatayn Shabqatayn 23.91665 55.20997 T DUNE AE 01 0 178 Asia/Dubai 2011-11-06
+290868 Sha‘bīyah Sha`biyah Sha`biya,Sha`biyah,Sha‘biya,Sha‘bīyah 24.28333 54.48333 T HLL AE 01 0 12 Asia/Dubai 2011-11-06
+290869 Shabakah Shabakah Shabakah 25.03333 56 P PPL AE 05 0 322 Asia/Dubai 2011-11-06
+290870 WÄdÄ« Shabak Wadi Shabak Wadi Shabak,WÄdÄ« Shabak 25.15157 55.45444 T TRGD AE 03 0 22 Asia/Dubai 2011-11-06
+290871 Bid‘ Shabaan Bid` Shabaan Bid` Shabaan,Bid‘ Shabaan 23.35 54.36667 H WLL AE 01 0 133 Asia/Dubai 2011-11-06
+290872 Sha‘athÄn Sha`athan Sha`athan,Sha‘athÄn 24.27375 54.91292 T SAND AE 01 0 73 Asia/Dubai 2011-11-06
+290873 WÄdÄ« Sha‘arah Wadi Sha`arah Wadi Sha`arah,Wadi Sha`areh,WÄdÄ« Sha‘arah,WÄdÄ« Sha‘areh 25.06667 56.36667 H WAD AE 06 0 -9999 Asia/Dubai 2011-11-06
+290874 Sayyidah Sayyidah Sayyidah 24.6884 55.70747 V TREE AE 01 0 281 Asia/Dubai 2011-11-06
+290875 Ramlat Sayyid Ramlat Sayyid Ramlat Saiyin,Ramlat Sayyid,Ramle Sayyid 24.39496 55.60754 T DUNE AE 01 0 304 Asia/Dubai 2011-11-06
+290876 WÄdÄ« Sayraq Wadi Sayraq Wadi Sayraq,WÄdÄ« Sayraq 25.56185 56.05472 H WAD AE 04 0 127 Asia/Dubai 2011-11-06
+290877 Sayḩ MaḩÄrÄ« Sayh Mahari Sayh Mahari,Sayḩ MaḩÄrÄ« 25.38333 55.73333 T DUNE AE 06 0 51 Asia/Dubai 2011-11-06
+290878 Sayḩ aş Şaqlah Sayh as Saqlah Sayh as Saqlah,Sayḩ aş Şaqlah 24.88398 56.16847 P PPL AE 05 0 195 Asia/Dubai 2011-11-06
+290879 Sayḩ al Ḩalamah Sayh al Halamah Sayh al Halamah,Sayh al Halmah,Sayḩ al Ḩalamah,Sayḩ al Ḩalmah 24.25409 54.6919 T DPR AE 01 0 22 Asia/Dubai 2011-11-06
+290880 Sayḩ Sayh Sayh,Sayḩ 25.93333 56.06667 P PPL AE 05 0 196 Asia/Dubai 2011-11-06
+290881 Ţawī Sayfilman Tawi Sayfilman Tawi Sayfilman,Ţawī Sayfilman 23.6 54.6 H WLL AE 01 0 113 Asia/Dubai 2011-11-06
+290882 Ţawī Sayf Tawi Sayf Tawi Sayf,Ţawī Sayf 25.33472 55.81056 H WLL AE 06 0 79 Asia/Dubai 2011-11-06
+290883 Bid‘ Sayf Bid` Sayf Bid` Sayf,Bid‘ Sayf 25.06667 55.58333 H WLL AE 03 0 107 Asia/Dubai 2011-11-06
+290884 Bid‘ Sayf Bid` Sayf Bid` Sayf,Bid‘ Sayf 23.9195 54.93082 T DPR AE 01 0 105 Asia/Dubai 2011-11-06
+290885 Barqat Sayf Barqat Sayf Barqat Sayf,Burga Seif,Burqat Sayf 24.29874 52.58478 T HLL AE 01 0 34 Asia/Dubai 2011-11-06
+290886 Barqat Sayf Barqat Sayf Barqat Sayf 24.03307 53.27185 T HLL AE 01 0 14 Asia/Dubai 2011-11-06
+290887 WÄdÄ« SaybitalmÄ Wadi Saybitalma Wadi Saybitalma,WÄdÄ« SaybitalmÄ 25.23589 56.13664 H WAD AE 05 0 437 Asia/Dubai 2011-11-06
+290888 NaqÄ SawÅ£ah Naqa Sawtah Naqa Sawtah,NaqÄ SawÅ£ah 24.26611 55.55694 T DUNE AE 01 0 197 Asia/Dubai 2011-11-06
+290889 Jabal SawdÄ’ Jabal Sawda' Jaba Sawda',Jaba SawdÄ’,Jabal Sawda',Jabal SawdÄ’ 25.20083 56.33993 T HLL AE 04 0 377 Asia/Dubai 2011-11-06
+290890 Ra’s Abyaḑ QaÅ£Ä Ra's Abyad Qata Ra's Abyad Qata,Ra's Sawami`,Ra’s Abyaḑ QaÅ£Ä,Ra’s ÅžawÄmi‘ 24.14785 53.20015 T PT AE 01 0 -9999 Asia/Dubai 2011-11-06
+290891 Jabal SÄÅ£if Jabal Satif Jabal Satif,Jabal SÄÅ£if 25.49887 56.04789 T MT AE 04 0 374 Asia/Dubai 2011-11-06
+290892 Saţḩ ar RÄzbÅ«t Sath ar Razbut Saath al Raazboot,Satah,Sath ar Razbut,Saţḩ ar RÄzbÅ«t 24.83333 53.16667 L OILF AE AE 01 0 -9999 Asia/Dubai 2011-11-06
+290893 SarÅ«q ZÄhir Saruq Zahir Saruq Zahir,SarÅ«q ZÄhir 24.21007 54.69939 H SBKH AE 01 0 32 Asia/Dubai 2011-11-06
+290894 Sarūq al Jasam Saruq al Jasam Saruq al Jasam,Sarūq al Jasam 24.55 55.43333 T DUNE AE 01 0 181 Asia/Dubai 2011-11-06
+290895 SÄrÅ«q Saruq Saruq,SÄrÅ«q 23.04905 53.73279 T DPR AE 01 0 75 Asia/Dubai 2011-11-06
+290896 Sarūj Saruj Saruj,Sarūj 25.26636 56.30934 P PPL AE 00 0 386 Asia/Dubai 2011-11-06
+290897 Sarūb Sarub Sarub,Sarūb 23.07561 53.69655 T DPR AE 01 0 164 Asia/Dubai 2011-11-06
+290898 Sayḩ Şarm Sayf Sayh Sarm Sayf Sayh Sarm Sayf,Sayḩ Şarm Sayf 23.68333 55.48333 T DPR AE 01 0 183 Asia/Dubai 2011-11-06
+290899 Ţawī ŞarmĒ Tawi Sarma' Tawi Saramin,Tawi Sarma',Tawi Sarmah,Ţawī Şaramin,Ţawī Şarmah,Ţawī ŞarmĒ 24.98018 55.88064 H WLL AE 06 0 203 Asia/Dubai 2011-11-06
+290900 Wuqnat Sarīj Wuqnat Sarij Wuqnat Sarij,Wuqnat Sarīj 22.97483 53.77287 T DPR AE 01 0 55 Asia/Dubai 2011-11-06
+290901 SarÄmÄ« Sarami Sarami,SarÄmÄ« 24.1 54.51667 T HLL AE 01 0 33 Asia/Dubai 2011-11-06
+290902 Ţawī Şaram Tawi Saram Sarm,Tawi Saram,Şarm,Ţawī Şaram 25.4925 56.02583 H WLL AE AE 05 0 114 Asia/Dubai 2011-11-06
+290903 Ra’s Sarab Ra's Sarab Ra's Sarab,Ras as-Sareb,Ra’s Sarab,RÄs as-Sareb 24.26252 51.78124 T PT AE 01 0 17 Asia/Dubai 2011-11-06
+290904 ÅžaqwÄn Saqwan Saqwan,ÅžaqwÄn 23.76608 53.49031 L GVL AE 01 0 105 Asia/Dubai 2011-11-06
+290905 MÄ«nÄ’ Åžaqr Mina' Saqr Mina Saqr Harbour,Mina' Saqr,MÄ«nÄ’ Åžaqr,Port Saqr 25.79167 55.95333 H HBR AE 05 0 -9999 Asia/Dubai 2011-11-06
+290906 WÄdÄ« Saqamqam Wadi Saqamqam Wadi Saqamqam,WÄdÄ« Saqamqam 25.16667 56.33333 H WAD AE 04 0 160 Asia/Dubai 2011-11-06
+290907 Sabkhat Saqamqam Sabkhat Saqamqam Sabkhat Saqamqam 25.15839 56.35618 H SBKH AE 04 0 16 Asia/Dubai 2011-11-06
+290908 Jabal Saqamqam Jabal Saqamqam Jabal Sakamkam,Jabal Saqamqam 25.18982 56.31074 T RDGE AE 04 0 145 Asia/Dubai 2011-11-06
+290909 Saqamqam Saqamqam As Saqamqam,Sakamkam,Saqamqam 25.17467 56.33039 P PPL AE 04 0 160 Asia/Dubai 2011-11-06
+290910 Saqal Saqal Saqal 25.27976 56.1859 V GRVP AE 05 0 386 Asia/Dubai 2011-11-06
+290911 Dawḩat ÅžÄniyah Dawhat Saniyah Dawhat Saniyah,Dawḩat ÅžÄniyah 24.15343 51.77192 H COVE AE 01 0 1 Asia/Dubai 2011-11-06
+290912 Khabrat Sanad Khabrat Sanad Khabrat Sanad 24.08333 51.7 H WLL AE 01 0 7 Asia/Dubai 2011-11-06
+290913 Sanad Sanad Sanad 24.1 51.7 L LCTY AE 01 0 14 Asia/Dubai 2011-11-06
+290914 WÄdÄ« SanÄbil Wadi Sanabil Wadi Sanabil,WÄdÄ« SanÄbil 24.66808 55.55881 T TRGD AE 00 0 221 Asia/Dubai 2011-11-06
+290915 SamnÄn Samnan Samnan,SamnÄn 25.3 55.45 L LCTY AE 00 0 13 Asia/Dubai 2011-11-06
+290916 Å¢awÄ« SamḩÄn Tawi Samhan Tawi Samhan,Tawi Semhan,Tawi Simhan,Å¢awÄ« SamḩÄn 24.82866 55.44335 H WLL AE 03 0 122 Asia/Dubai 2011-11-06
+290917 Raml SamḩÄn Raml Samhan Raml Samhan,Raml SamḩÄn 24.83333 55.46667 T SAND AE 03 0 129 Asia/Dubai 2011-11-06
+290918 SamḩÄn Samhan Al Irma,Samhan,SamḩÄn,Semhan 24.83333 55.46667 T HLL AE AE 03 0 129 Asia/Dubai 2011-11-06
+290919 Å¢awÄ« SamḩÄ’ Tawi Samha' Tawi Samha',Å¢awÄ« SamḩÄ’ 25.56444 55.82694 H WLL AE 07 0 46 Asia/Dubai 2011-11-06
+290920 Samarat Samarat Samarat 25.68907 56.13698 P PPL AE 01 0 1211 Asia/Dubai 2011-11-06
+290921 Sayh Samarah Sayh Samarah Sayh Samarah 24.21929 55.43518 T TRGD AE 01 0 205 Asia/Dubai 2011-11-06
+290922 WÄdÄ« SamÄḩ Wadi Samah Wadi Samah,WÄdÄ« SamÄḩ 25.44621 55.98338 H WAD AE 05 0 125 Asia/Dubai 2011-11-06
+290923 Jabal SamÄḩ Jabal Samah Jabal Samah,Jabal SamÄḩ 25.12605 56.17094 T MT AE 00 0 954 Asia/Dubai 2011-11-06
+290924 Jabal SamÄḩ Jabal Samah Jabal Samah,Jabal SamÄḩ 25.4165 55.96082 T DUNE AE 05 0 204 Asia/Dubai 2011-11-06
+290925 SamÄḩ Samah Samah,SamÄḩ 24.91667 56.3 L TRB AE 00 0 108 Asia/Dubai 2011-11-06
+290926 Salwá Salwa Salwa,Salwah,Salwá,Sawa,Sawá 25.02031 55.14772 L LCTY AE 03 0 20 Asia/Dubai 2011-11-06
+290927 Sayḩ Salmá Sayh Salma Sayh Salma,Sayḩ Salmá 24.16132 55.4748 T TRGD AE 01 0 237 Asia/Dubai 2011-11-06
+290928 Raml as Salmá Raml as Salma Raml as Salma,Raml as Salmá 24.16667 55.48333 T DUNE AE 01 0 243 Asia/Dubai 2011-11-06
+290929 Sayḩ as Salm Sayh as Salm Sayh as Salam,Sayh as Salm,Sayḩ as Salam,Sayḩ as Salm 24.83631 55.29693 T TRGD AE 03 0 88 Asia/Dubai 2011-11-06
+290930 Raml as Salm Raml as Salm Raml as Salam,Raml as Salm 24.85099 55.25704 T DUNE AE 03 0 55 Asia/Dubai 2011-11-06
+290931 WÄdÄ« Sallah Wadi Sallah Wadi Sallah,WÄdÄ« Sallah 24.56329 55.64776 T TRGD AE 01 0 279 Asia/Dubai 2011-11-06
+290932 Sayḩ Sallah Sayh Sallah Sayh Sallah,Sayḩ Sallah 23.93198 55.47704 T TRGD AE 01 0 186 Asia/Dubai 2011-11-06
+290933 Sallah Sallah Sallah 24.57314 55.61947 L LCTY AE 01 0 250 Asia/Dubai 2011-11-06
+290934 WÄdÄ« Sall Wadi Sall Wadi Sal,Wadi Sall,WÄdÄ« Sal,WÄdÄ« Sall 25.84083 56.06722 H WAD AE AE 05 0 75 Asia/Dubai 2011-11-06
+290935 Jabal Sall Jabal Sall Jabal Sal,Jabal Sall 25.76028 56.08861 T MT AE AE 05 0 799 Asia/Dubai 2011-11-06
+290936 Sall Sall Sal,Sall 25.74903 56.09217 V CULT AE 05 0 563 Asia/Dubai 2011-11-06
+290937 Falaj as Salj Falaj as Salj Falaj as Salj 25.44825 55.98449 H STMI AE 05 0 125 Asia/Dubai 2011-11-06
+290938 WÄdÄ« SalÄ«mah Wadi Salimah Wadi Salimah,Wadi Salum,WÄdÄ« SalÄ«mah,WÄdÄ« SalÅ«m 24.72335 55.66265 T TRGD AE 00 0 244 Asia/Dubai 2011-11-06
+290939 Shu‘bat Salīmah Shu`bat Salimah Shu`bat Salimah,Shu`bat Silima,Shu‘bat Salīmah,Shu‘bat Silima 24.0475 55.83278 H WAD AE 01 0 324 Asia/Dubai 2011-11-06
+290940 Baţn Salīmah Batn Salimah Batn Salima,Batn Salimah,Baţn Salima,Baţn Salīmah 24.91893 55.54126 T DPR AE 03 0 166 Asia/Dubai 2011-11-06
+290941 Salīmah Salimah Saleema,Salimah,Salīmah 22.9118 54.3397 T DPR AE 01 0 164 Asia/Dubai 2011-11-06
+290942 Ţawī Salīm Tawi Salim Tawi Salim,Ţawī Salīm 25.33896 55.82837 H WLL AE 07 0 79 Asia/Dubai 2011-11-06
+290943 Sayḩ SalÄ«l Sayh Salil Madiq al-Salil,Maá¸Ä«q al-SalÄ«l,Sayh Salil,Sayḩ SalÄ«l,Sih Salil 23.13333 55.41667 T TRGD AE 00 0 120 Asia/Dubai 2011-11-06
+290944 ÅžÄliḩīyah Salihiyah As Salihiyah,AÅŸ ÅžÄliḩīyah,Salihiyah,ÅžÄliḩīyah 25.72161 55.99081 P PPL AE 05 0 21 Asia/Dubai 2011-11-06
+290945 Saleh Saleh Saleh,Salih,ÅžÄliḩ 26.13333 55.75 L OILF AE 01 0 -9999 Asia/Dubai 2011-11-06
+290946 Jabal SalḩÄl Jabal Salhal Jabal Salhal,Jabal SalḩÄl 25.25969 56.18567 T MT AE 05 0 634 Asia/Dubai 2011-11-06
+290947 Salbūk Salbuk Salbuk,Salbūk 23.87316 53.76852 T DUNE AE 01 0 55 Asia/Dubai 2011-11-06
+290948 SalÄn KhalfÄn Salan Khalfan Salan Khalfan,SalÄn KhalfÄn 23.93776 53.52864 T DUNE AE 01 0 43 Asia/Dubai 2011-11-06
+290949 Sabkhat as Salamīyah Sabkhat as Salamiyah As Salamiyah Sabkhat,Sabkhat as Salamiyah,Sabkhat as Salamīyah 23.99347 53.76611 H SBKH AE 01 0 12 Asia/Dubai 2011-11-06
+290950 SalÄm Salam Salam,SalÄm 25.66583 55.8525 H WLL AE 07 0 66 Asia/Dubai 2011-11-06
+290951 Sabkhat Salal Sabkhat Salal Sabkhat Salal,Sabkhat Salil,Sabkhat Salīl 23.74706 55.12282 H SBKH AE 01 0 103 Asia/Dubai 2011-11-06
+290952 Salala Salala As Salahah,AÅŸ ÅžalÄḩah,Salahah,Salala,ÅžalÄḩah 24.1955 53.53829 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+290953 Bid‘ Salaal Bid` Salaal Bid` Salaal,Bid‘ Salaal 23.9 54.7 H WLL AE 01 0 90 Asia/Dubai 2011-11-06
+290954 Sala Sala Sala 24.16667 55.4 T DUNE AE 01 0 198 Asia/Dubai 2011-11-06
+290955 Jabal Sakhbīrī Jabal Sakhbiri Jabal Sakhbiri,Jabal Sakhbīrī 25.10639 56.03417 T HLL AE 05 0 366 Asia/Dubai 2011-11-06
+290956 SÄ’if Sa'if Sa'if,SÄ’if 25.1842 56.24205 P PPL AE 04 0 415 Asia/Dubai 2011-11-06
+290957 Å¢awÄ« Sa‘īdÄ« Tawi Sa`idi Tawi Sa`idi,Tawi Zaid,Tawi Zayd,Å¢awÄ« Sa‘īdÄ«,Å¢awÄ« Zayd,Å¢ÄwÄ« Zaid 25.54241 55.89153 H WLL AE 05 0 26 Asia/Dubai 2011-11-06
+290958 Å¢awÄ« Sa‘īd Bin HuwaydÄn Tawi Sa`id Bin Huwaydan Tawi Sa`id Bin Huwaydan,Å¢awÄ« Sa‘īd Bin HuwaydÄn 24.97961 55.78755 H WLL AE 06 0 172 Asia/Dubai 2011-11-06
+290959 Bid‘ Sa‘īd Bid` Sa`id Bada Sa`id,Bada Sa‘īd,Bid` Sa`id,Bid‘ Sa‘īd 23.65747 52.49121 H WLL AE 01 0 68 Asia/Dubai 2011-11-06
+290960 SÄ’ibah Sa'ibah Sa'iba,Sa'ibah,Sa’iba,SÄ’ibah 22.95698 54.27151 T DPR AE 01 0 98 Asia/Dubai 2011-11-06
+290961 GhaffÄt SaḩmÄ« Ghaffat Sahmi Ghaffat Sahmi,GhaffÄt SaḩmÄ« 24.5 55.26667 T DUNE AE 01 0 123 Asia/Dubai 2011-11-06
+290962 Sayḩ Sahmah Sayh Sahmah Sayh Sahmah,Sayḩ Sahmah 23.15 55.25 T DPR AE 00 0 104 Asia/Dubai 2011-11-06
+290963 Ḩaql Sahl Haql Sahl Haql Sahl,Sahal,Sahel,Sahil,Ḩaql Sahl 23.70594 54.32028 L OILF AE 01 0 114 Asia/Dubai 2011-11-06
+290964 WÄdÄ« Åžaḩanah Wadi Sahanah Wadi Sahanah,WÄdÄ« Åžaḩanah 25.28025 56.32255 H WAD AE 00 0 63 Asia/Dubai 2011-11-06
+290965 Saḩanah Sahanah Sahanah,Saḩanah 25.28556 56.3084 P PPL AE 06 0 99 Asia/Dubai 2011-11-06
+290966 SaḩÄb Sahab Sahab,SaḩÄb 25.15848 56.08929 L LCTY AE 05 0 286 Asia/Dubai 2011-11-06
+290967 Å¢awÄ« SÄji‘ah Tawi Saji`ah Tawi Saghyah,Tawi Saja'a,Tawi Saja`ah,Tawi Saji`ah,TÄwÄ« Saja’a,Å¢awÄ« Saghyah,Å¢awÄ« SÄja‘ah,Å¢awÄ« SÄji‘ah 25.30552 55.58034 H WLL AE 06 0 39 Asia/Dubai 2011-11-06
+290968 Saghyah Saghyah Saghyah,Sajaa 25.25 55.78333 L GASF AE AE 06 0 113 Asia/Dubai 2011-11-06
+290969 Sagh‘ayn Sagh`ayn Sagh'ain,Sagh`ayn,Sagh‘ayn,Sagh’ain 24.53333 51.11667 H WLL AE 01 0 3 Asia/Dubai 2011-11-06
+290970 WÄdÄ« aÅŸ ÅžafÅŸaf Wadi as Safsaf Wadi as Safsaf,WÄdÄ« aÅŸ ÅžafÅŸaf 25.33999 56.02183 H WAD AE 00 0 201 Asia/Dubai 2011-11-06
+290971 Ţawī Şafşaf Tawi Safsaf Tawi Safsaf,Ţawī Şafşaf 25.32833 56.01056 H WLL AE 02 0 219 Asia/Dubai 2011-11-06
+290972 Jabal ÅžafÅŸaf Jabal Safsaf Jabal Safsaf,Jabal ÅžafÅŸaf 25.33111 56.02306 T HLL AE 02 0 198 Asia/Dubai 2011-11-06
+290973 WÄdÄ« Åžafad Wadi Safad Wadi Safad,WÄdÄ« Åžafad 25.22915 56.35145 H WAD AE 04 0 12 Asia/Dubai 2011-11-06
+290974 Jabal Åžafad Jabal Safad Jabal Safad,Jabal Åžafad 25.23315 56.28695 T MT AE 04 0 640 Asia/Dubai 2011-11-06
+290975 Åžafad Safad Safad,Sufad,Åžafad 25.22165 56.3239 P PPL AE 04 0 71 Asia/Dubai 2011-11-06
+290976 WÄdÄ« ÅžafÄ Wadi Safa Wadi Safa,WÄdÄ« ÅžafÄ 25.06554 55.26203 T TRGD AE 03 0 30 Asia/Dubai 2011-11-06
+290977 Ra’s aş Şadr Ra's as Sadr Ra's as Sadr,Ra’s aş Şadr 24.6753 54.65663 T PT AE 01 0 -9999 Asia/Dubai 2011-11-06
+290978 Ra’s as Sa‘dÄ«yÄt Ra's as Sa`diyat Ra's as Sa`diyat,Ras al Sa`diya,Ras al Sa‘diya,Ra’s as Sa‘dÄ«yÄt 24.58542 54.47465 T PT AE 01 0 -9999 Asia/Dubai 2011-11-06
+290979 Khawr as Sa‘dÄ«yÄt Khawr as Sa`diyat Khawr Essadiyat,Khawr EssÄdiyÄt,Khawr as Sa`diyat,Khawr as Sa‘dÄ«yÄt 24.62296 54.46416 H CHNM AE 01 0 -9999 Asia/Dubai 2011-11-06
+290980 Ţawī Sa‘dīyah Tawi Sa`diyah Tawi Sa`diyah,Ţawī Sa‘dīyah 24.87867 56.16899 H WLL AE 05 0 191 Asia/Dubai 2011-11-06
+290981 Sa‘dīyah Sa`diyah Sa`diyah,Sa‘dīyah 23.69426 54.10408 H WLL AE 01 0 97 Asia/Dubai 2011-11-06
+290982 Sa‘dÄ«yah Sa`diyah Sa`diyah,Sa‘dÄ«yah,Tawi Sa'adiya,TÄwÄ« Sa’adiya 25.1 55.7 V TREE AE 06 0 156 Asia/Dubai 2011-11-06
+290983 Å¢awÄ« as SÄdd Tawi as Sadd Sa`ad,Sa‘ad,Tawi Sa`d,Tawi as Sadd,Å¢awÄ« Sa‘d,Å¢awÄ« as SÄdd 24.20806 55.50417 H WLLS AE AE 01 0 211 Asia/Dubai 2011-11-06
+290984 Raml as SÄdd Raml as Sadd Raml Sa`d,Raml Sa‘d,Raml as Sadd,Raml as SÄdd 24.2 55.48333 T DUNE AE AE 01 0 213 Asia/Dubai 2011-11-06
+290985 Jabal Sa‘d Jabal Sa`d Jabal Sa`d,Jabal Sa‘d 25.11355 56.11717 T MT AE 05 0 427 Asia/Dubai 2011-11-06
+290986 Sa‘d Sa`d Sa`d,Sa‘d 25.26667 56.28333 P PPL AE 06 0 213 Asia/Dubai 2011-11-06
+290987 Ramlat Åžabr Ramlat Sabr Ramlat Sabar,Ramlat Sabr,Ramlat Åžabr 24.03866 55.4161 T DUNE AE 01 0 202 Asia/Dubai 2011-11-06
+290988 Sabkhah Sabkhah Sabakha,Sabkhah 23.3 53.85 P PPL AE AE 01 0 136 Asia/Dubai 2011-11-06
+290989 Sabkhah Sabkhah Sabkha,Sabkhah,Sabukhah 23.12917 53.98181 P PPL AE 01 0 166 Asia/Dubai 2011-11-06
+290990 Sabkah Sabkah Sabka,Sabkah 25.29255 55.39472 H WLL AE 03 0 8 Asia/Dubai 2011-11-06
+290991 Ţawī Sabarad Tawi Sabarad Tawi Sabarad,Ţawī Sabarad 25.29389 55.89944 H WLL AE 06 0 144 Asia/Dubai 2011-11-06
+290992 Sabalah Sabalah Sabalah,Sablah 22.92596 53.45262 T DPR AE 01 0 61 Asia/Dubai 2011-11-06
+290993 SabÄ’is Saba'is Saba'is,SabÄ’is 24.83333 55.5 L TRB AE 03 0 169 Asia/Dubai 2011-11-06
+290994 Qarn Şa‘bah Qarn Sa`bah Qarn Sa`bah,Qarn Şa‘bah 24.46867 55.72733 T HLL AE 01 0 330 Asia/Dubai 2011-11-06
+290995 Sa‘abah Sa`abah Sa`abah,Sa`bah,Sa‘abah,Sa‘bah 24.99417 56.025 P PPLQ AE 05 0 306 Asia/Dubai 2011-11-06
+290996 NaqÄ Sa‘Ädah Naqa Sa`adah Naqa Sa`adah,NaqÄ Sa‘Ädah 23.42818 55.38215 T DUNE AE 01 0 195 Asia/Dubai 2011-11-06
+290997 Ţawī Ruwayyah Tawi Ruwayyah Tawi Mirdif,Tawi Ruwayyah,Ţawī Mirdif,Ţawī Ruwayyah 24.89283 55.66387 H WLL AE 03 0 209 Asia/Dubai 2011-11-06
+290998 Ruwayyah Ruwayyah Ruwayyah 24.8871 55.66016 L LCTY AE 03 0 205 Asia/Dubai 2011-11-06
+290999 Ra’s Ruwaysīyah Ra's Ruwaysiyah Ra's Harmiyah,Ra's Ru'aysiyah,Ra's Ruwaysiyah,Ra’s Harmīyah,Ra’s Ruwaysīyah,Ra’s Ru’aysīyah 24.12591 53.44243 T PT AE 01 0 -9999 Asia/Dubai 2011-11-06
+291000 Ruwaysīyah Ruwaysiyah Ru'aysiyah,Ruwaisiyya,Ruwaysiyah,Ruwaysīyah,Ruweisiya,Ru’aysīyah 24.11927 53.4354 L LCTY AE 01 0 1 Asia/Dubai 2011-11-06
+291001 Sayḩ Ruwayshid Sayh Ruwayshid Sayh Ruwayshid,Sayḩ Ruwayshid 25.3 55.66667 T TRGD AE 06 0 76 Asia/Dubai 2011-11-06
+291002 Khawr ar Ruways Khawr ar Ruways Khawr ar Ru'ays,Khawr ar Ruways,Khawr ar Ru’ays 24.13966 52.67385 H INLT AE 01 0 1 Asia/Dubai 2011-11-06
+291003 Ruwaymayah Ruwaymayah Ruwaymayah 24.80098 55.64042 L LCTY AE 03 0 230 Asia/Dubai 2011-11-06
+291004 Jabal Ruwayḑah Jabal Ruwaydah Jabal Ruwaydah,Jabal Ruwayḑah 25.50556 56.08844 T MT AE 04 0 493 Asia/Dubai 2011-11-06
+291005 Ruwayḑah Ruwaydah Riweidah,Riweiá¸ah,Ruwaidha,Ruwaydah,Ruwayḑah 23.1039 53.97789 L OAS AE 01 0 98 Asia/Dubai 2011-11-06
+291006 RuwÄlÄ Ruwala Ruwala,Ruwalla,RuwÄlÄ 23.2956 54.20134 H SPNG AE 01 0 158 Asia/Dubai 2011-11-06
+291007 Ruqayyib Ruqayyib Ruqayyib 23.93586 52.88188 H WLL AE 01 0 59 Asia/Dubai 2011-11-06
+291008 Ruqayyah Ruqayyah Ruqayyah 23.28333 54.65 H WLL AE 01 0 126 Asia/Dubai 2011-11-06
+291009 Ruqayyah Ruqayyah Ruqayyah 23.03532 53.60933 L OAS AE 01 0 159 Asia/Dubai 2011-11-06
+291010 Shaqqat ar Ruqayţuwah Shaqqat ar Ruqaytuwah Ruqaytuwwah,Ruqayţuwwah,Shaqqat ar Ruqaytuwah,Shaqqat ar Ruqaytuwwah,Shaqqat ar Ruqayţuwah,Shaqqat ar Ruqayţuwwah 23.38663 55.25216 T TRGD AE 01 0 121 Asia/Dubai 2011-11-06
+291011 Sabkhat ar Ruqayţuwah Sabkhat ar Ruqaytuwah Sabkhat Bu Satma,Sabkhat Bū Satma,Sabkhat ar Ruqaytuwah,Sabkhat ar Ruqaytuwwah,Sabkhat ar Ruqayţuwah,Sabkhat ar Ruqayţūwwah 23.44808 55.11346 H SBKH AE 01 0 110 Asia/Dubai 2011-11-06
+291012 ‘Irq Ruqayţuwah `Irq Ruqaytuwah `Irq Ruqaytuwah,`Irq Ruqaytuwwah,‘Irq Ruqayţuwah,‘Irq Ruqayţuwwah 23.38449 55.20788 T DUNE AE 01 0 187 Asia/Dubai 2011-11-06
+291013 Ţawī Ruqayshah Tawi Ruqayshah Tawi Ruqayshah,Ţawī Ruqayshah 24.98485 55.78776 H WLL AE 06 0 163 Asia/Dubai 2011-11-06
+291014 Ruq‘at Ya‘Äribah Ruq`at Ya`aribah Raq`al al Jarba,Raq‘al al Jarba,Ruq`at Ya`aribah,Ruq‘at Ya‘Äribah 23.89652 55.48556 T TRGD AE 01 0 145 Asia/Dubai 2011-11-06
+291015 Ruq‘at Tulūl Ruq`at Tulul Ruq`at Tulul,Ruq‘at Tulūl 22.95827 55.20907 T DPR AE 01 0 126 Asia/Dubai 2011-11-06
+291016 Ruq‘at Sunayyim Ruq`at Sunayyim Ruq`at Sunayyim,Ruq‘at Sunayyim 23.65155 55.29791 T TRGD AE 01 0 114 Asia/Dubai 2011-11-06
+291017 Ruq‘at Ruqayţuwah Ruq`at Ruqaytuwah Ruq`at Ruqatuwwah,Ruq`at Ruqaytuwah,Ruq`at Ruqaytuwwah,Ruq‘at Ruqayţuwah,Ruq‘at Ruqayţuwwah,Ruq‘at Ruqaţuwwah 23.40594 55.28253 T DPR AE 01 0 121 Asia/Dubai 2011-11-06
+291018 Ruq‘at Nuşb Ruq`at Nusb Ruq`at Nusb,Ruq`at Nusub,Ruq‘at Nuşb,Ruq‘at Nuşub 24.05 55.41667 T SAND AE 01 0 173 Asia/Dubai 2011-11-06
+291019 Ruq‘at Muşallī Ruq`at Musalli Ruq`at Musalli,Ruq‘at Muşallī 24.85889 55.57612 T DUNE AE 03 0 195 Asia/Dubai 2011-11-06
+291020 Ruq‘at Musajira Ruq`at Musajira Ruq`at Musajira,Ruq‘at Musajira 24.84075 55.65624 T DUNE AE 03 0 228 Asia/Dubai 2011-11-06
+291021 Muḩayşinah Muhaysinah Muhaysinah,Muḩayşinah,Ruq`ah Muhassanah,Ruq`at Muhassanah,Ruq‘ah Muḩaşşanah,Ruq‘at Muḩaşşanah 25.25528 55.39278 L LCTY AE AE 03 0 15 Asia/Dubai 2011-11-06
+291022 Ruq‘at Maghis Ruq`at Maghis Ruq`at Maghis,Ruq‘at Maghis 23.61802 55.4466 T TRGD AE 01 0 139 Asia/Dubai 2011-11-06
+291023 Ruq‘at Ḩumaydī Ruq`at Humaydi Hameidha,Humaydah,Ruq`at Humaydi,Ruq‘at Ḩumaydī,Ḩumayḑah 24.79964 55.70185 T DUNE AE 03 0 260 Asia/Dubai 2011-11-06
+291024 Ruq‘at Ḩulayw Ruq`at Hulayw Ruq`at Hulayw,Ruq‘at Ḩulayw 23.63585 55.36908 T TRGD AE 01 0 157 Asia/Dubai 2011-11-06
+291025 Rafadah Rafadah Rafadah,Ruq`at Bu Zafidah,Ruq‘at Bū Z̧afīdah 24.86014 55.65022 T DUNE AE 03 0 217 Asia/Dubai 2011-11-06
+291026 Ruq‘at al Mīr Ruq`at al Mir Ruq`at al Mir,Ruq‘at al Mīr 22.98574 55.19227 H SBKH AE 01 0 100 Asia/Dubai 2011-11-06
+291027 Ruq‘at al ḨÄdh Ruq`at al Hadh Ruq`at al Hadh,Ruq‘at al ḨÄdh 22.94468 55.1886 H SBKH AE 01 0 105 Asia/Dubai 2011-11-06
+291028 Ruq‘at al ‘ArÄd Ruq`at al `Arad Raq`at al-`Arad,Raq‘at al-‘ArÄd,Ruq`at al Ard,Ruq`at al `Arad,Ruq‘at al Ard,Ruq‘at al ‘ArÄd 23.86265 55.50198 T TRGD AE 01 0 191 Asia/Dubai 2011-11-06
+291029 WÄdÄ« Rumḩ Wadi Rumh Wadi Rumh,WÄdÄ« Rumḩ 25.04006 56.32907 H WAD AE 06 0 24 Asia/Dubai 2011-11-06
+291030 Ţawī Rumḩ Tawi Rumh Tawi Rumh,Ţawī Rumḩ 25.01667 56.35 H WLL AE 06 0 7 Asia/Dubai 2011-11-06
+291031 Jabal Rumḩ Jabal Rumh Jabal Rumh,Jabal Rumḩ 25.02953 56.2807 T MT AE 04 0 369 Asia/Dubai 2011-11-06
+291032 Rumaylī Rumayli Rumayli,Rumaylī 26.02472 56.11083 V CULT AE 05 0 565 Asia/Dubai 2011-11-06
+291033 Jabal ar Rumaylah Jabal ar Rumaylah Jabal ar Rumaylah 25.43333 56.35 T HLL AE 04 0 34 Asia/Dubai 2011-11-06
+291034 Jabal Umayliḩ Jabal Umaylih Jabal Rumaylah,Jabal Umaylah,Jabal Umaylih,Jabal Umayliḩ 25.0503 55.82244 T HLL AE 06 0 253 Asia/Dubai 2011-11-06
+291035 RÅ«l á¸adnÄ Rul Dadna Rol Dadnah,Rol Ḍadnah,Rul Dadna,Rul Dadnah,Rul Dhadna,RÅ«l á¸adnah,RÅ«l á¸adnÄ 25.55481 56.34546 P PPL AE 04 0 26 Asia/Dubai 2011-11-06
+291036 Ţawī ar Rūl Tawi ar Rul Tawi ar Rul,Ţawī ar Rūl 25.57602 56.35214 H WLLQ AE 04 0 -9999 Asia/Dubai 2011-11-06
+291037 RukbÄt Rukbat Rukbat,RukbÄt 24.74428 54.65006 T SPIT AE 01 0 7 Asia/Dubai 2011-11-06
+291038 Ramlat ar Ruhayl Ramlat ar Ruhayl Ramlat ar Ruhayl 23.55 55.46667 T DUNE AE 00 0 188 Asia/Dubai 2011-11-06
+291039 Jabal Ruḩam Jabal Ruham Jabal Ruham,Jabal Ruḩam 25.13333 56.26667 T HLL AE 04 0 93 Asia/Dubai 2011-11-06
+291040 RughaylÄt Rughaylat Righeilat,RigheilÄt,Rughaylat,RughaylÄt,Rugheilat 25.10552 56.3563 P PPL AE 04 0 23 Asia/Dubai 2011-11-06
+291041 ‘Ayn ar Rufayşah `Ayn ar Rufaysah `Ayn ar Rufaysah,‘Ayn ar Rufayşah 25.35 56.31667 H SPNG AE 06 0 77 Asia/Dubai 2011-11-06
+291042 RufayÅŸah Rufaysah Rufaysah,RufayÅŸah 25.16778 56.17722 V CULT AE 01 0 389 Asia/Dubai 2011-11-06
+291043 Bandar Rudaym Bandar Rudaym Bandar Rudaym 24.06323 53.69867 H COVE AE 01 0 -9999 Asia/Dubai 2011-11-06
+291044 Å¢awÄ« Rubayyah Tawi Rubayyah Tawi Rabaiya,Tawi Rubayyah,TÄwÄ« Rabaiya,Å¢awÄ« Rubayyah 25.73333 56.05 H WLL AE AE 05 0 361 Asia/Dubai 2011-11-06
+291045 Rubay‘ah Rubay`ah Rubay`ah,Rubay‘ah 24.25 55.08333 T DPR AE 01 0 123 Asia/Dubai 2011-11-06
+291046 WÄdÄ« RiyÄmah Wadi Riyamah Wadi Riyama,Wadi Riyamah,WÄdÄ« RiyÄmah 25.55023 56.04815 H WAD AE 04 0 237 Asia/Dubai 2011-11-06
+291047 RiyÄmah Riyamah Riyama,Riyamah,RiyÄmah 25.54564 56.05836 P PPL AE 04 0 179 Asia/Dubai 2011-11-06
+291048 Jabal RiyÄdir Jabal Riyadir Jabal Riyadir,Jabal RiyÄdir 25.3 56.33333 T MT AE 06 0 42 Asia/Dubai 2011-11-06
+291049 Å¢awÄ« RiqÄnah Tawi Riqanah Riqana,Tawi Riqanah,Å¢awÄ« RiqÄnah 24.3418 55.69959 H WLL AE 01 0 310 Asia/Dubai 2011-11-06
+291050 ‘Uqlat ar Rimth `Uqlat ar Rimth `Uqlat ar Rimth,‘Uqlat ar Rimth 24.43333 51.11667 H WLL AE 01 0 6 Asia/Dubai 2011-11-06
+291051 RimÄḩ Rimah Al Ramah,Rimah,RimÄḩ 24.79667 55.61194 V TREE AE AE 03 0 224 Asia/Dubai 2011-11-06
+291052 Rimá Rima Rima,Rimá 25.16784 56.11795 P PPL AE 05 0 519 Asia/Dubai 2011-11-06
+291053 RiḩyÄt Rihyat Rihyat,RiḩyÄt 24.88151 55.44885 T SAND AE 03 0 152 Asia/Dubai 2011-11-06
+291054 Ţawī Rifđ Tawi Rifa` Tawi Rifa`,Ţawī Rifđ 24.96961 55.78658 H WLL AE 06 0 173 Asia/Dubai 2011-11-06
+291055 GhalÄ«lat RÄziqÄ« Ghalilat Raziqi Ghalilat Raziqi,GhalÄ«lat RÄziqÄ« 25.6 56.28333 H WADM AE 04 0 95 Asia/Dubai 2011-11-06
+291056 WÄdÄ« Rayj Wadi Rayj Wadi Rayj,WÄdÄ« Rayj 25.0183 55.2567 T TRGD AE 03 0 37 Asia/Dubai 2011-11-06
+291057 WÄdÄ« RaybÄ«yah Wadi Raybiyah Wadi Raibiya,Wadi Raybiyah,WÄdÄ« Raibiya,WÄdÄ« RaybÄ«yah 25.73472 56.02722 H WAD AE AE 05 0 9 Asia/Dubai 2011-11-06
+291058 Rawḑah Rawdah Rawdah,Rawḑah 24.09028 55.56194 T DPR AE 01 0 215 Asia/Dubai 2011-11-06
+291059 Ra’s SiyÄd Ra's Siyad Ra's Seyad,Ra's Siyad,Ra’s SeyÄd,Ra’s SiyÄd 24.55 51.65 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+291060 Ra’s Qal‘ah Ra's Qal`ah Ra's Qal`ah,Ra’s Qal‘ah 24.19222 55.58333 T DUNE AE 01 0 235 Asia/Dubai 2011-11-06
+291061 Ar RÄshidÄ«yah Ar Rashidiyah Ar Rashidiyah,Ar RÄshidÄ«yah,Rashdia,Rashidiyah,RashÄ«dÄ«yah 25.22365 55.38894 P PPLX AE 03 0 20 Asia/Dubai 2011-11-06
+291062 Å¢awÄ« RÄshid Bin Sa‘īd Tawi Rashid Bin Sa`id Tawi Rashid Bin Sa`id,Å¢awÄ« RÄshid Bin Sa‘īd 25.65528 55.95861 H WLL AE 05 0 22 Asia/Dubai 2011-11-06
+291063 Å¢awÄ« RÄshid Bin Ḩamad Tawi Rashid Bin Hamad Tawi Rashid Bin Hamad,Å¢awÄ« RÄshid Bin Ḩamad 25.24 55.91278 H WLL AE 06 0 136 Asia/Dubai 2011-11-06
+291064 RÄshid al GharbÄ« Rashid al Gharbi Rashid al Gharbi,RÄshid al GharbÄ«,Tawi Rashid Gharbiyah,Tawi Rashid al Gharbiyah,Å¢awÄ« RÄshid GharbÄ«yah,Å¢awÄ« RÄshid al GharbÄ«yah 25.35833 55.70528 H WLL AE AE 06 0 74 Asia/Dubai 2011-11-06
+291065 Å¢awÄ« RÄshidah Tawi Rashidah Tawi Rashidah,Å¢awÄ« RÄshidah 25.16667 55.96667 H WLL AE 05 0 234 Asia/Dubai 2011-11-06
+291066 Å¢awÄ« RÄshid Tawi Rashid Tawi Rashid,Å¢awÄ« RÄshid 25.33333 55.78333 H WLL AE 06 0 105 Asia/Dubai 2011-11-06
+291067 Nadd RÄshid Nadd Rashid Nadd Rashid,Nadd RÄshid 25.21944 55.40556 T DUNE AE 03 0 24 Asia/Dubai 2011-11-06
+291068 MÄ«nÄ’ RÄshid Mina' Rashid Mina' Rashid,MÄ«nÄ’ RÄshid,Port Rashid,Rachid Port 25.27056 55.29083 L PRT AE 03 0 -9999 Asia/Dubai 2011-11-06
+291069 Ḩaql RÄshid Haql Rashid Haql Rashid,Rashid Oilfield,Ḩaql RÄshid 25.23333 55.2 L OILF AE AE 03 0 -9999 Asia/Dubai 2011-11-06
+291070 Barqat RashÄ«d Barqat Rashid Bada` Rashid,Bada‘ Rashid,Barqat Rashid,Barqat RashÄ«d,Barqat RÄshid 24.00562 54.01885 T HLL AE 01 0 18 Asia/Dubai 2011-11-06
+291071 Raseen Raseen Raseen 23.68333 54.78333 H WLL AE 01 0 130 Asia/Dubai 2011-11-06
+291072 Rasan Rasan Rasan 24.15 55.21667 T DUNE AE 01 0 151 Asia/Dubai 2011-11-06
+291073 Khawr Ra’s al Khaymah Khawr Ra's al Khaymah Khawr Khaymah,Khawr Ra's al Khaymah,Khawr Ra’s al Khaymah 25.78333 55.95 H LGN AE 05 0 -9999 Asia/Dubai 2011-11-06
+291074 Ra’s al Khaymah Ra's al Khaymah Julfa,Khaimah,Ra's al Khaymah,Ras al Khaima,Ras al Khaimah,Ra’s al Khaymah,RÄs al Khaima,ras alkhymt,رأس الخيمة 25.78953 55.9432 P PPLA AE 05 115949 27 Asia/Dubai 2011-11-06
+291075 Ra’s al Khaymah Ra's al Khaymah Jasimi Shaikhdom of Ras al-Khaimah,Ra's al Khaymah,Ran al Khaima,Ras al Khaima,Ras el Khaimah,Ras el Khaïmah,Raʼs al Khaymah,Ra’s al Khaymah,Sheikhdom of Ras al Khaimah,State of Ras Al Khaima,ras alkhymt,رأس الخيمة 25.66667 56 A ADM1 AE 05 187535 12 Asia/Dubai 2011-11-05
+291076 WÄdÄ« Ra’s Wadi Ra's Wadi Ra's,WÄdÄ« Ra’s 25.10156 56.35801 H WAD AE 04 0 23 Asia/Dubai 2011-11-06
+291077 Jabal Ra’s Jabal Ra's Jabal Ra's,Jabal Ra’s 25.32634 56.3712 T MT AE 00 0 331 Asia/Dubai 2011-11-06
+291078 Sayḩ ar Raqq Sayh ar Raqq Sayh ar Raq,Sayh ar Raqq,Sayḩ ar Raq,Sayḩ ar Raqq 24.06667 55.83333 T TRGD AE AE 01 0 316 Asia/Dubai 2011-11-06
+291079 Jabal Rams Jabal Rams Jabal Rams 25.86917 56.06917 T MT AE 05 0 774 Asia/Dubai 2011-11-06
+291080 RamrÄmÄ«yÄt Ramramiyat Birkat al Ju,Ramramiyah,Ramramiyat,Ramrammiyat,RamrammiyÄt,RamramÄ«yah,RamrÄmÄ«yÄt 23.98231 53.7953 T HLL AE 01 0 68 69 Asia/Dubai 2011-11-06
+291081 Ḩabl RamrÄm Habl Ramram Habl Ramram,Ḩabl RamrÄm 24.9 55.3 T SAND AE 03 0 62 Asia/Dubai 2011-11-06
+291082 Ḩabl RamrÄm Habl Ramram Habl Ramram,Ḩabl RamrÄm 24.91667 55.3 T DUNE AE 03 0 74 Asia/Dubai 2011-11-06
+291083 Za‘bīl Za`bil Raml Sabil,Raml Za`bil,Raml Za‘bīl,Za`bil,Za‘bīl 25.20408 55.2875 P PPLX AE 03 0 6 Asia/Dubai 2011-11-06
+291084 Ramlat ZarÄrah Ramlat Zararah Ramlat Zarara,Ramlat Zararah,Ramlat ZarÄrah 22.90077 54.49992 L AREA AE 01 0 131 Asia/Dubai 2011-11-06
+291085 Ramlah Ramlah Ramla,Ramlah,RamlÄ 25.35979 56.04452 P PPL AE 04 0 264 Asia/Dubai 2011-11-06
+291086 JazÄ«rat RamḩÄn Jazirat Ramhan Jazirat Ramhan,JazÄ«rat RamḩÄn,Ramhan,RamḩÄn,jzyrt rmhan,جزيرة رمØان 24.53778 54.52419 T ISL AE 01 0 10 Asia/Dubai 2011-11-06
+291087 Å¢awÄ« RamÄrÄ«m Tawi Ramarim Tawi Ramarim,Tawi Rimarim,Tawi Rumayram,TÄwÄ« Rimarim,Å¢awÄ« RamÄrÄ«m,Å¢awÄ« Rumayram 25.36083 55.535 H WLL AE 02 0 12 Asia/Dubai 2011-11-06
+291088 Ramaq Ramaq Ramaq 24.93333 55.13333 T SAND AE 03 0 42 Asia/Dubai 2011-11-06
+291089 QÅ«r ar RÄkibÄ« Qur ar Rakibi Qur ar Rakibi,QÅ«r ar RÄkibÄ« 25.5841 56.32873 T MT AE 04 0 357 Asia/Dubai 2011-11-06
+291090 NaqÄ RÄkah Naqa Rakah Naqa Rakah,NaqÄ RÄkah 23.95296 55.43484 T DUNE AE 01 0 232 Asia/Dubai 2011-11-06
+291091 GhÄf Rakaḑ Ghaf Rakad Ghaf Rakad,GhÄf Rakaḑ 24.51667 55.41667 T HLL AE 01 0 179 Asia/Dubai 2011-11-06
+291092 Sayḩ ar Rajībah Sayh ar Rajibah Sayh ar Rajibah,Sayḩ ar Rajībah 24.8 55.26667 T TRGD AE 03 0 71 Asia/Dubai 2011-11-06
+291093 Ḩadabat ar Rajībah Hadabat ar Rajibah Hadabat ar Rajibah,Ḩadabat ar Rajībah 24.8042 55.2656 T HLL AE 03 0 67 Asia/Dubai 2011-11-06
+291094 Raighnaan Raighnaan Raighnaan 23.16667 54.83333 H WLL AE 01 0 114 Asia/Dubai 2011-11-06
+291095 Raighan Raighan Raighan 23.26667 54.73333 H WLL AE 01 0 129 Asia/Dubai 2011-11-06
+291096 Raigha Raigha Raigha 24.44577 55.15561 T SAND AE 01 0 128 Asia/Dubai 2011-11-06
+291097 Raḩmah Rahmah Rahmah,Raḩmah 25.68 55.86361 H WLL AE 07 0 61 Asia/Dubai 2011-11-06
+291098 Rahfīyah Rahfiyah Rahfiya,Rahfiyah,Rahfīyah 22.79933 54.90797 T DPR AE 01 0 173 Asia/Dubai 2011-11-06
+291099 Jabal ar Raḩraḩ Jabal ar Rahrah Jabal Rahah,Jabal RÄḩah,Jabal ar Rahrah,Jabal ar Raḩraḩ 25.94833 56.14194 T MT AE AE 05 0 1586 Asia/Dubai 2011-11-06
+291100 WÄdÄ« Raḩbah Wadi Rahbah Wadi Rahabah,Wadi Rahbah,WÄdÄ« Raḩabah,WÄdÄ« Raḩbah 25.92472 56.07167 H WAD AE AE 05 0 12 Asia/Dubai 2011-11-06
+291101 Jabal Raḩabah Jabal Rahabah Jabal Rahabah,Jabal Raḩabah,Jabal ar Ra`aylah,Jabal ar Ra‘aylah 25.92583 56.11667 T MT AE AE 05 0 1539 Asia/Dubai 2011-11-06
+291102 Raḩabah Rahabah Rahabah,Raḩabah 25.98333 56.08333 L TRB AE 05 0 37 Asia/Dubai 2011-11-06
+291103 Raḩá Raha Raha,Raḩá 24.87639 56.2175 V CULT AE 05 0 140 Asia/Dubai 2011-11-06
+291105 NaqÄ Raghwah Naqa Raghwah Naqa Raghawa,Naqa Raghwah,NaqÄ Raghawa,NaqÄ Raghwah 24.44834 55.23357 T DUNE AE 01 0 141 Asia/Dubai 2011-11-06
+291106 Å¢awÄ« Rafī‘ah Tawi Rafi`ah Tawi Rafi`ah,Tawi Rafiya,Tawi Rayifah,TÄwÄ« Rafiya,TÄwÄ« Rayifah,Å¢awÄ« Rafī‘ah 25.31972 55.73583 H WLL AE 06 0 79 Asia/Dubai 2011-11-06
+291107 Rafaq Rafaq Rafaq 24.87471 56.24559 P PPL AE 05 0 321 Asia/Dubai 2011-11-06
+291108 Å¢awÄ« RafÄh Tawi Rafah Tawi Rafah,Å¢awÄ« RafÄh 25.28333 55.88333 H WLL AE 06 0 110 Asia/Dubai 2011-11-06
+291109 Å¢awÄ« RafÄdah Tawi Rafadah Tawi Rafaada,Tawi Rafadah,Å¢awÄ« Rafaada,Å¢awÄ« RafÄdah 24.89462 55.74432 H WLL AE 06 0 185 Asia/Dubai 2011-11-06
+291110 Rafđ Rafa` Rafa`,Rafđ 25.34701 56.35014 P PPL AE 06 0 40 Asia/Dubai 2011-11-06
+291111 Radūm Radum Radum,Radūm 23.09185 53.61473 L OAS AE 01 0 172 Asia/Dubai 2011-11-06
+291112 RadÄt Ramz Radat Ramz Radat Ramz,Radath Ramz,RadÄt Ramz 25.5 56.1 H WLL AE AE 05 0 218 Asia/Dubai 2011-11-06
+291113 Jabal ar Rabbah Jabal ar Rabbah Jabal ar Rabbah 25.39071 56.06641 T HLL AE 05 0 322 Asia/Dubai 2011-11-06
+291114 Sayḩ Rab‘ Sayh Rab` Sayh Rab`,Sayḩ Rab‘ 24.61506 54.86516 T TRGD AE 01 0 48 Asia/Dubai 2011-11-06
+291115 Quwayd Quwayd Quwayd 25.13333 56.05 L TRB AE 05 0 488 Asia/Dubai 2011-11-06
+291116 Quţūf Qutuf Qatuf,Qaá¹Å«f,Qutuf,Quţūf 23.10971 53.72738 P PPL AE 01 0 87 Asia/Dubai 2011-11-06
+291117 Quţūf Qutuf Qutuf,Quţūf 23.10794 53.69333 T DPR AE 01 0 80 Asia/Dubai 2011-11-06
+291118 Jabal Qutayyib Jabal Qutayyib Jabal Qutayyib 25.94139 56.09333 T HLL AE 05 0 881 Asia/Dubai 2011-11-06
+291119 Jabal al Qusīy Jabal al Qusiy Jabal al Qusiy,Jabal al Qusīy 25.06667 56.31667 T HLL AE 06 0 90 Asia/Dubai 2011-11-06
+291120 QushÄsh Qushash Qushash,QushÄsh 23.95539 53.62028 T SAND AE 01 0 14 Asia/Dubai 2011-11-06
+291121 Sabkhat Qusaywirah Sabkhat Qusaywirah Sabkhat Qusaywirah 22.77956 55.04968 H SBKH AE 01 0 76 Asia/Dubai 2011-11-06
+291122 Qusaywirah Qusaywirah Geseiwra,Jiseiwrah,Qusaywirah 22.81918 54.79949 L LCTY AE 01 0 117 Asia/Dubai 2011-11-06
+291124 QuÅŸaydÄt Qusaydat Qusaidat,Qusaydat,QuÅŸaydÄt 25.77461 55.97002 P PPLX AE 05 0 21 Asia/Dubai 2011-11-06
+291125 Qurmidah Qurmidah Garmada,GarmadÄ,Jarmada,JarmadÄ,Qarmadah,Qurmidah 23.11957 53.82855 P PPL AE 01 0 154 Asia/Dubai 2011-11-06
+291126 Qurmidah Qurmidah Qarmadah,Qurmidah 23.11234 53.82152 L OAS AE 01 0 86 Asia/Dubai 2011-11-06
+291127 Jazīrat Qurmah Jazirat Qurmah Jazirat Qurmah,Jazīrat Qurmah 25.76667 55.95 T ISL AE 05 0 20 Asia/Dubai 2011-11-06
+291128 Khawr Qurm Khawr Qurm Khawr Qurm 25.72056 55.84667 H LGN AE 05 0 -9999 Asia/Dubai 2011-11-06
+291129 Qurm Qurm Qurm 25.91139 56.06417 P PPL AE 05 0 29 Asia/Dubai 2011-11-06
+291130 WÄdÄ« Qurayyah Wadi Qurayyah Wadi Qaraiyat,Wadi Qurayyah,WÄdÄ« Qurayyah 25.24214 56.34825 H WAD AE 04 0 16 Asia/Dubai 2011-11-06
+291131 Jabal Qurayyah Jabal Qurayyah Jabal Qurayyah 25.25531 56.3374 T HLL AE 04 0 40 Asia/Dubai 2011-11-06
+291132 Quraytisah Quraytisah Quraytisah 23.57867 54.87448 H WLL AE 01 0 147 Asia/Dubai 2011-11-06
+291133 Ţawī Qurayn Tawi Qurayn Tawi Qurayn,Ţawī Qurayn 23.66667 54.7 H WLL AE 01 0 143 Asia/Dubai 2011-11-06
+291134 Sayḩ Qurayḩah Sayh Qurayhah Sayh Qurayhah,Sayḩ Qurayḩah 25.41667 55.7 T TRGD AE 07 0 77 Asia/Dubai 2011-11-06
+291135 Quraydah Quraydah Quraydah 23.13464 53.86398 L OAS AE 01 0 167 Asia/Dubai 2011-11-06
+291136 QÅ«r Qur Al Qawr,Al Qor,Quor,Qur,QÅ«r 24.91214 56.09566 P PPL AE 05 0 340 Asia/Dubai 2011-11-06
+291137 Qunayy Qunayy Qunayy 23.16667 54.38333 H WLL AE 01 0 151 Asia/Dubai 2011-11-06
+291138 Bid‘ al QumzÄn Bid` al Qumzan Bid` al Qumzan,Bid‘ al QumzÄn 23.78619 53.42782 H WLL AE 01 0 102 Asia/Dubai 2011-11-06
+291139 Qulaydah Qulaydah Qulaydah 25.1968 55.96372 T RDGE AE 06 0 213 Asia/Dubai 2011-11-06
+291140 Qufayyid Qufayyid Qiff Rajajil,Qiff RajÄjÄ«l,Qufayyid 23.7573 52.87017 T SAND AE 01 0 94 Asia/Dubai 2011-11-06
+291141 Sih al Qubua Sih al Qubua Sayh al Qubua,Sayḩ al Qubua,Sih al Qubua 24.31519 54.88739 T DPR AE 01 0 75 Asia/Dubai 2011-11-06
+291142 Qubbat BÅ« Lisail Qubbat Bu Lisail Qubbat Bu Lisail,Qubbat BÅ« Lisail 24.36204 55.64738 L LCTY AE 01 0 278 Asia/Dubai 2011-11-06
+291143 WÄdÄ« Qubbah Wadi Qubbah Wadi Qubbah,WÄdÄ« Qubbah 25.3444 56.13202 H WAD AE 00 0 760 Asia/Dubai 2011-11-06
+291144 Sayḩ QubaysÄt Sayh Qubaysat Sayh Qubaysat,Sayḩ QubaysÄt 24.31489 55.05401 T TRGD AE 01 0 95 Asia/Dubai 2011-11-06
+291145 GhaḑÄ’ QÅ«bah Ghada' Qubah Ghada' Qubah,GhaḑÄ’ QÅ«bah,Sayh as Salab,Sayḩ as Salab 24.26986 55.30432 T TRGD AE 01 0 141 Asia/Dubai 2011-11-06
+291146 Qu‘aysah Qu`aysah Ge'aisa,Ge’aisa,Je`eisah,Je‘eiṣah,Qu`aysah,Qu‘aysah 22.9941 54.22184 P PPL AE 01 0 151 Asia/Dubai 2011-11-06
+291147 Quar Ah Qahlish Quar Ah Qahlish Quar Ah Qahlish 25.985 56.08639 P PPL AE 05 0 10 Asia/Dubai 2011-11-06
+291148 Jabal Qitab Jabal Qitab Jabal Kitas,Jabal Qitab 25.02017 56.2411 T MT AE 00 0 1029 1004 Asia/Dubai 2011-11-06
+291149 Khawr QirqishÄn Khawr Qirqishan Khawr Qirqishan,Khawr QirqishÄn 24.37884 54.36899 H BAY AE 01 0 -9999 Asia/Dubai 2011-11-06
+291150 WÄdÄ« Qimah Wadi Qimah Wadi Qamh,Wadi Qima,Wadi Qimah,Wadi Qimh,WÄdÄ« Qamḩ,WÄdÄ« Qimah,WÄdÄ« Qimh,WÄdÄ« QÄ«má 24.79862 56.13736 H WAD AE 03 0 306 Asia/Dubai 2011-11-06
+291151 Jabal Qimah Jabal Qimah Jabal Qima,Jabal Qimah,Jabal Qīmá 24.79495 56.15749 T HLL AE 03 0 609 Asia/Dubai 2011-11-06
+291152 Qimah Qimah Qamh,Qamḩ,Qima,Qimah,Qimh,Qīmá 24.78668 56.14143 P PPL AE 03 0 322 Asia/Dubai 2011-11-06
+291153 Ra’s al QilÄ‘ Ra's al Qila` Qala`,Qala‘,Ra's al Qila`,Ras Djaliya,Ras Ijla,Ras Jaliya,Ras Jaliyah,Ras al Jala'a,Ras al Jala’a,Ras al-Qela',Ra’s al QilÄ‘,RÄs al-QelÄ’ 24.15507 52.97896 T PT AE 01 0 -9999 Asia/Dubai 2011-11-06
+291154 Jabal Qidfa‘ Jabal Qidfa` Jabal Qidfa`,Jabal Qidfa‘ 25.33201 56.32246 T MT AE 06 0 473 Asia/Dubai 2011-11-06
+291155 Qidfa‘ Qidfa` Qidfa,Qidfa`,Qidfa‘,Qidfi`,Qidfi‘ 25.30426 56.37034 P PPL AE 06 0 45 Asia/Dubai 2011-11-06
+291156 Qayyat al Bawl Qayyat al Bawl Qayyat al Bawl 24.27465 54.62206 T DUNE AE 01 0 15 Asia/Dubai 2011-11-06
+291157 NaqÄ Qaydah Naqa Qaydah Naqa Qaydah,NaqÄ Qaydah 23.36667 55.4 T DUNE AE 00 0 174 Asia/Dubai 2011-11-06
+291158 Qawm ‘AnÄ«yÄt Qawm `Aniyat Qaum `Aniyat,Qaum ‘AnÄ«yÄt,Qawm `Aniyat,Qawm ‘AnÄ«yÄt 24.11544 54.34195 T HLL AE 01 0 21 Asia/Dubai 2011-11-06
+291159 QaţţÄrah Qattarah Al-Qatarah,Qatara,Qatarah,Qattara,Qattarah,QatÄrah,QaţţÄrah,Qaá¹á¹Ära 24.25993 55.75566 P PPL AE 01 0 292 Asia/Dubai 2011-11-06
+291160 Ţawī Qaţam Tawi Qatam Tawi Qatam,Ţawī Qaţam 24.0525 54.74417 H WLL AE 01 0 74 Asia/Dubai 2011-11-06
+291161 Qaţam Qatam Qatam,Qaţam 24.0532 54.73458 T DUNE AE 01 0 74 Asia/Dubai 2011-11-06
+291162 Qataiwa Qataiwa Qataiwa 23.41667 55.28333 H WLL AE 01 0 155 Asia/Dubai 2011-11-06
+291163 Qassīs Ḩayy Qassis Hayy Qassis Haiy,Qassis Hayy,Qassīs Haiy,Qassīs Ḩayy 24.1 55.63333 T DPR AE AE 01 0 250 Asia/Dubai 2011-11-06
+291164 Ramlat al Qassīs Ramlat al Qassis Ramlat al Qassis,Ramlat al Qassīs 24.08333 55.58333 T DUNE AE 01 0 238 Asia/Dubai 2011-11-06
+291165 QaÅŸÅŸÄbÄ« Qassabi Gassabi,GassÄbi,Jassabi,JaÅŸÅŸÄbÄ«,Qassabi,QaÅŸÅŸÄbÄ«,Qusabi,QuÅŸÄbÄ«,Umm al Majarib,Umm al MajÄrib 24.21093 54.1017 T ISL AE 01 0 11 Asia/Dubai 2011-11-06
+291166 QaÅŸr ÅžÄliḩ Qasr Salih Qasr Salih,QaÅŸr ÅžÄliḩ 23.92871 52.78831 T SAND AE 01 0 43 Asia/Dubai 2011-11-06
+291167 WÄdÄ« Qasmah Wadi Qasmah Wadi Qasma,Wadi Qasmah,WÄdÄ« Qasma,WÄdÄ« Qasmah 24.48968 55.53049 H WAD AE 01 0 251 Asia/Dubai 2011-11-06
+291168 Kharīmat Qaşīmah Kharimat Qasimah Kharimat Qasimah,Kharmat Qasimah,Kharmat Qaşīmah,Kharīmat Qaşīmah,Qasimah,Qaşimah 24.07524 54.89174 T TRGD AE 01 0 90 Asia/Dubai 2011-11-06
+291169 QaÅŸÄ«mah Qasimah Qasimah,QaÅŸÄ«mah 24.05154 54.90686 H WLL AE 01 0 83 Asia/Dubai 2011-11-06
+291170 Qarn Qashash Qarn Qashash Qarn Qashash 24.42261 55.59755 T HLL AE 01 0 275 Asia/Dubai 2011-11-06
+291171 Qarqarī Qarqari Qarqari,Qarqarī 24.31889 55.61222 T DPR AE 01 0 221 Asia/Dubai 2011-11-06
+291172 Qarnayn Qarnayn Al Qarnain,Al Qarnayn,Jazirat al Qarnayn,Jazīrat al Qarnayn,Jezirat Qarnain,Karnain Island,Qarnayn,Qarnein 24.93528 52.84972 T ISL AE AE 01 0 -9999 Asia/Dubai 2011-11-06
+291173 Qarḩat Suwayd Qarhat Suwayd Qarhat Suwaid,Qarhat Suwayd,Qarḩat Suwayd 24.5 55.68333 V TREE AE AE 01 0 286 Asia/Dubai 2011-11-06
+291174 WÄdÄ« Qarḩah Wadi Qarhah Wadi Qarhah,WÄdÄ« Qarḩah 25.36471 55.8084 T DPR AE 06 0 80 Asia/Dubai 2011-11-06
+291175 Sayḩ QarÄţīs Sayh Qaratis Sayh Qaratis,Sayḩ QarÄţīs 24.86667 55.55 T DPR AE 03 0 148 Asia/Dubai 2011-11-06
+291176 Ţawī al Qaran Tawi al Qaran Tawi al Qaran,Ţawī al Qaran 25.53317 55.74746 H WLL AE 07 0 49 Asia/Dubai 2011-11-06
+291177 QarÄmidah Qaramidah Qaramidah,QarÄmidah 23.14517 53.71552 L OAS AE 01 0 160 Asia/Dubai 2011-11-06
+291178 Å¢awÄ« al QÄrah Tawi al Qarah Alcara,Tawi al Qarah,Å¢awÄ« al QÄrah 25.69146 56.00238 H WLL AE 05 0 15 Asia/Dubai 2011-11-06
+291179 Qar‘ah Qar`ah Qar'a,Qar`ah,Qara'a,Qara’a,Qar‘ah,Qar’a 24.9 55.03333 T SAND AE 03 0 16 Asia/Dubai 2011-11-06
+291180 Å¢awÄ« Qarad Tawi Qarad Tawi Garhad,Tawi Qarad,Å¢awÄ« Qarad,Å¢ÄwÄ« Garhad 25.62735 55.75506 H WLL AE 07 0 23 Asia/Dubai 2011-11-06
+291181 Khawr Qanţūr Khawr Qantur Khawr Qantur,Khawr Qanţūr 24.15843 54.06167 H CHNM AE 01 0 -9999 Asia/Dubai 2011-11-06
+291182 Qamshī Qamshi Qamshi,Qamshī,Qemshi 24.74458 54.77306 T HLL AE 01 0 12 Asia/Dubai 2011-11-06
+291183 QamrÄ’ Qamra' Qamra',QamrÄ’ 23.03861 52.60583 H WLL AE 01 0 103 Asia/Dubai 2011-11-06
+291184 QamrÄ’ Qamra' Qamra',QamrÄ’ 23.01254 52.48934 L LCTY AE 01 0 85 Asia/Dubai 2011-11-06
+291185 Qamarah Qamarah Qamarah 23.71667 53.4 T HLL AE 01 0 81 Asia/Dubai 2011-11-06
+291186 Jabal al Qumr ash ShamÄlÄ« Jabal al Qumr ash Shamali Jabal al Qamar,Jabal al Qumr ash Shamali,Jabal al Qumr ash ShamÄlÄ« 25.46168 56.04501 T MT AE 05 0 561 Asia/Dubai 2011-11-06
+291187 Jabal al Qumr al Janūbī Jabal al Qumr al Janubi Jabal al Qamar,Jabal al Qumr al Janubi,Jabal al Qumr al Janūbī 25.43354 56.044 T MT AE 05 0 455 Asia/Dubai 2011-11-06
+291188 WÄdÄ« al QildÄ« Wadi al Qildi Wadi al Qaliddi,Wadi al Qildi,WÄdÄ« al QaliddÄ«,WÄdÄ« al QildÄ« 25.59763 55.98951 H WAD AE 04 0 36 Asia/Dubai 2011-11-06
+291189 WÄdÄ« al QaliddÄ« Wadi al Qaliddi Wadi al Qaliddi,WÄdÄ« al QaliddÄ« 25.56667 56.05 H WAD AE 04 0 346 Asia/Dubai 2011-11-06
+291190 ‘Aqabat al QaliddÄ« `Aqabat al Qaliddi Qalidda Pass,Qaliddi Pass,QÄliddi Pass,`Aqabat al Qaliddi,‘Aqabat al QaliddÄ« 25.53387 56.12393 T PASS AE 04 0 512 Asia/Dubai 2011-11-06
+291191 Qaiyaisha Qaiyaisha Qaiyaisha 25.88333 56.11667 L TRB AE 05 0 853 Asia/Dubai 2011-11-06
+291192 Ḩabl QÄ’imah Habl Qa'imah Habl Qa'im,Habl Qa'imah,Habl Qa’im,Ḩabl QÄ’imah 24.35345 54.73194 T SAND AE 01 0 46 Asia/Dubai 2011-11-06
+291193 QÄ’imah Qa'imah Gaimo,Qa'imah,QÄ’imah 24.32635 54.7658 H WLLS AE 01 0 53 Asia/Dubai 2011-11-06
+291194 Raml al Qaḩţ Raml al Qaht Raml al Qaht,Raml al Qaḩţ 24.73333 55.28333 T SAND AE 03 0 115 Asia/Dubai 2011-11-06
+291195 Ţawī Qafan Tawi Qafan Tawi Qafan,Ţawī Qafan 25.29778 55.88472 H WLL AE 06 0 118 Asia/Dubai 2011-11-06
+291196 WÄdÄ« Qada‘ah Wadi Qada`ah Wadi Ghayl,Wadi Qada`a,Wadi Qada`ah,Wadi Qadda`a,WÄdÄ« Qada‘a,WÄdÄ« Qada‘ah,WÄdÄ« Qadda‘a 25.79083 56.07842 H WAD AE 05 0 203 Asia/Dubai 2011-11-06
+291197 Jabal Qada‘ah Jabal Qada`ah Jabal Qada`a,Jabal Qada`ah,Jabal Qada‘a,Jabal Qada‘ah 25.77944 56.13973 T MT AE 05 0 1374 Asia/Dubai 2011-11-06
+291198 Qada‘ah Qada`ah Qada`a,Qada`ah,Qada‘a,Qada‘ah 25.76667 56.08333 V CULT AE 05 0 379 Asia/Dubai 2011-11-06
+291199 Qabas Qabas Qabas 26.03435 56.12302 P PPL AE 05 0 419 Asia/Dubai 2011-11-06
+291200 Qubaythah Qubaythah Qabaitha,Qubaythah 24.41472 55.69599 L LCTY AE 01 0 318 Asia/Dubai 2011-11-06
+291201 Petty Patches Petty Patches Petty Patches 24.48392 52.4424 H SHOL AE 01 0 -9999 Asia/Dubai 2011-11-06
+291204 NuwayrÄn Nuwayran Nuwayran,NuwayrÄn 24.0781 54.66495 T DUNE AE 01 0 56 Asia/Dubai 2011-11-06
+291205 Ţawī Nuşaylī Tawi Nusayli Tawi Nusayli,Ţawī Nuşaylī 24.34467 55.22058 H WLLS AE 01 0 133 Asia/Dubai 2011-11-06
+291206 Sabkhat Nuşaylī Sabkhat Nusayli Sabkhat Nusayli,Sabkhat Nuşaylī 24.32398 55.1741 H SBKH AE 01 0 124 Asia/Dubai 2011-11-06
+291207 Qarn NuÅŸaylah Qarn Nusaylah Al-Neseilah,Qarn Nusaylah,Qarn NuÅŸaylah 24.46222 54.63361 T DUNE AE AE 01 0 14 Asia/Dubai 2011-11-06
+291208 NuÅŸayb Nusayb Nusayb,NuÅŸayb 24.45 55.11667 T TRGD AE 01 0 123 Asia/Dubai 2011-11-06
+291209 Nuqayrah Nuqayrah Nuqayrah 23.30021 54.09107 P PPL AE 01 0 172 Asia/Dubai 2011-11-06
+291210 Nuqaydhah Nuqaydhah Nuqaydhah 23.02418 53.56632 T DPR AE 01 0 77 Asia/Dubai 2011-11-06
+291211 Ţawī Numayrīyah Tawi Numayriyah Nimairiya,Numairiya,Tawi Nimairiyyah,Tawi Numayriyah,Ţawī Numayrīyah 23.75469 54.42187 H WLL AE 01 0 104 Asia/Dubai 2011-11-06
+291212 Numayl Numayl Nemail,Numayl 23.13487 53.88304 L OAS AE 01 0 106 Asia/Dubai 2011-11-06
+291213 Å¢awÄ« an Nukharah Tawi an Nukharah Tawi Nakh,Tawi an Nakharah,Tawi an Nukharah,Å¢awÄ« an Nakharah,Å¢awÄ« an Nukharah,ṬÄwÄ« Nakh 24.93857 55.39779 H WLL AE 03 0 83 Asia/Dubai 2011-11-06
+291214 Sayḩ an Nukharah Sayh an Nukharah Sayh an Nakharah,Sayh an Nukharah,Sayḩ an Nakharah,Sayḩ an Nukharah 24.93333 55.35 T TRGD AE AE 03 0 71 Asia/Dubai 2011-11-06
+291215 Nuhayy Nuhayy Nahai,Nuhayy 25.27074 56.36242 P PPL AE 06 0 22 Asia/Dubai 2011-11-06
+291216 Ţawī Nubayy Tawi Nubayy Tawi Nubayy,Ţawī Nubayy 25.48333 55.71667 H WLL AE 07 0 45 Asia/Dubai 2011-11-06
+291217 Ţawī Nubaybigh Tawi Nubaybigh Nebeibighat,Tawi Nubaybigh,Tawi Nubaybighah,Ţawī Nubaybigh,Ţawī Nubaybighah 25.26667 55.81667 H WLL AE AE 06 0 125 Asia/Dubai 2011-11-06
+291218 WÄdÄ« NiyÄm Wadi Niyam Wadi Niyam,WÄdÄ« NiyÄm 25.08412 55.92606 H WAD AE 05 0 185 Asia/Dubai 2011-11-06
+291219 QurÅ«n NiÅŸÄb Qurun Nisab Qurun Nisab,QurÅ«n NiÅŸÄb 23.80045 54.33433 T DUNE AE 01 0 100 Asia/Dubai 2011-11-06
+291220 NisÄb Nisab Nisab,NisÄb 23.79429 54.35987 H WLL AE 01 0 90 Asia/Dubai 2011-11-06
+291221 Nibrī Nibri Nibri,Nibrī 25.35176 55.84985 S FT AE 07 0 75 Asia/Dubai 2011-11-06
+291222 Jabal Nibah Jabal Nibah Jabal Nibah 24.76861 56.15111 T MT AE 00 0 522 Asia/Dubai 2011-11-06
+291223 WÄdÄ« Nazwá Wadi Nazwa Wadi Nazwa,WÄdÄ« Nazwá 25.01163 55.65579 T TRGD AE 06 0 176 Asia/Dubai 2011-11-06
+291224 Å¢awÄ« Nazwá Tawi Nazwa Nazwa,NazwÄ,Tawi Nazwa,Tawi Nezwa,Tawi Nizwa,Å¢awÄ« Nazwá,Å¢ÄwÄ« Nezwa 25.0325 55.68361 H WLL AE AE 06 0 168 Asia/Dubai 2011-11-06
+291225 Qarn Nazwá Qarn Nazwa Qarn Nazwa,Qarn Nazwá,Qarn Nizwa 24.98371 55.66235 T HLL AE 00 0 173 Asia/Dubai 2011-11-06
+291226 WÄdÄ« NayÄs Wadi Nayas Wadi Nayas,Wadi Nayassa,WÄdÄ« Nayassa,WÄdÄ« NayÄs 25.02082 55.9848 H WAD AE 05 0 247 Asia/Dubai 2011-11-06
+291227 NaqÄ an NawÄ Naqa an Nawa Naqa Nawi,Naqa an Nawa,NaqÄ NÄwÄ«,NaqÄ an NawÄ 25.14487 55.42354 T DUNE AE 03 0 55 Asia/Dubai 2011-11-06
+291228 Sayḩ Naşūrīyah Ghafanī Sayh Nasuriyah Ghafani Sayh Nasuriyah Ghafani,Sayh Nisuriyah,Sayḩ Naşūrīyah Ghafanī,Sayḩ Nişūrīyah 24.39117 55.2855 T TRGD AE 01 0 155 Asia/Dubai 2011-11-06
+291229 Ţawī Naşūrīyah Tawi Nasuriyah Tawi Nasuriyah,Tawi Nisuriyah,Ţawī Naşūrīyah,Ţawī Nişūrīyah 24.32521 55.35583 H WLL AE 01 0 146 Asia/Dubai 2011-11-06
+291230 Sayḩ Naşūrīyah Sayh Nasuriyah Sayh Nasuriyah,Sayh Nisuriyah,Sayḩ Naşūrīyah,Sayḩ Nişūrīyah 24.36214 55.35931 T TRGD AE 01 0 179 Asia/Dubai 2011-11-06
+291231 Naşūrīyah Nasuriyah Nasuriyah,Naşūrīyah,Ryah Nisuh 24.4 55.31667 H WLL AE AE 01 0 100 Asia/Dubai 2011-11-06
+291232 Naşūrīyah Nasuriyah Nasuriyah,Naşūrīyah,Nisuriyah,Nişūrīyah 24.36667 55.41667 T DUNE AE AE 01 0 184 Asia/Dubai 2011-11-06
+291233 NaÅŸlah Naslah Naslah,NaÅŸlah 23.82234 52.6032 T SAND AE 01 0 62 Asia/Dubai 2011-11-06
+291234 NaÅŸÄ«b Nasib Nasib,NaÅŸÄ«b 24.56667 55.16667 T DUNE AE 01 0 92 Asia/Dubai 2011-11-06
+291235 Nashimah Nashimah Nashimah 23.09103 53.80754 T DPR AE 01 0 81 Asia/Dubai 2011-11-06
+291236 Sayḩ an Nashash Sayh an Nashash Sayh an Nashash,Sayḩ an Nashash,Sih al Nashash,Sih an Nashash,Sīḩ an NashÄsh 24.08865 55.71184 T TRGD AE 01 0 245 Asia/Dubai 2011-11-06
+291237 Milhala Milhala Milhala,Tawi Nasas,Å¢awÄ« Nasas,Å¢awÄ« NaÅŸÄÅŸ 25.02694 55.97 H WLL AE 05 0 265 Asia/Dubai 2011-11-06
+291238 Ramlat NasÄs Ramlat Nasas Ramlat Nasas,Ramlat NasÄs 24.51593 55.168 T DUNE AE 01 0 106 Asia/Dubai 2011-11-06
+291239 Nasas Nasas Nasas 24.5 55.18333 T TRGD AE 01 0 125 Asia/Dubai 2011-11-06
+291240 Ţawī Naqrah Tawi Naqrah Tawi Nagarah,Tawi Naqara,Tawi Naqrah,Ţawī Naqara,Ţawī Naqrah 24.3762 55.53108 H WLLS AE 01 0 194 Asia/Dubai 2011-11-06
+291241 Qarn Naqrah Qarn Naqrah Qarn Naqrah 24.37348 55.52974 T DUNE AE 01 0 235 Asia/Dubai 2011-11-06
+291242 Naqrah Naqrah Naqrah 24.37644 55.56032 P PPL AE 01 0 247 Asia/Dubai 2011-11-06
+291243 Naqrah Naqrah Naqrah 24.38333 55.45 T DUNE AE 01 0 204 Asia/Dubai 2011-11-06
+291244 Naqbīyīn Naqbiyin Naqbiyin,Naqbīyīn 25.66667 56 L TRB AE 00 0 12 Asia/Dubai 2011-11-06
+291245 Naqbiyīn Naqbiyin Naqbiyin,Naqbiyīn 25.33333 56.33333 L TRB AE 00 0 426 Asia/Dubai 2011-11-06
+291246 WÄdÄ« Naqat Wadi Naqat Wadi Naqat,WÄdÄ« Naqat 25.86667 56.1 H WAD AE 05 0 205 Asia/Dubai 2011-11-06
+291247 Jaww an NÄqah Jaww an Naqah Jaww an Naqah,Jaww an NÄqah 22.96387 54.14931 T DPR AE 01 0 95 Asia/Dubai 2011-11-06
+291248 Naqab Sha‘rÄn Naqab Sha`ran Naqab Sha`ran,Naqab Sha‘rÄn 24.17121 54.66632 T SAND AE 01 0 44 Asia/Dubai 2011-11-06
+291249 WÄdÄ« Naqab Wadi Naqab Wadi Naqab,WÄdÄ« Naqab 25.70384 56.0662 H WAD AE 05 0 85 Asia/Dubai 2011-11-06
+291250 Namlīyah Namliyah Namliyah,Namlīyah 23.05915 53.958 T DPR AE 01 0 170 Asia/Dubai 2011-11-06
+291251 Namlīyah Namliyah Namliyah,Namlīyah 23.03453 54.02193 T DPR AE 01 0 87 Asia/Dubai 2011-11-06
+291252 Namlah Namlah Namlah 23.06497 53.97529 H WLL AE 01 0 76 Asia/Dubai 2011-11-06
+291253 Namlah Namlah Namalah,Namlah 23.01393 53.47494 T DPR AE 01 0 172 Asia/Dubai 2011-11-06
+291254 Nakhl Subayyis Nakhl Subayyis Nakhl Sibaiyis,Nakhl Sibaylis,Nakhl Subaiyis,Nakhl Subayyis 24.3575 55.20611 V TREE AE AE 01 0 107 Asia/Dubai 2011-11-06
+291255 Nakhl Bin JirwÄn Nakhl Bin Jirwan Nakhl Bin Jirwan,Nakhl Bin JirwÄn,Nakhl bin Jerwan 24.18333 55.11667 H WLLS AE AE 01 0 123 Asia/Dubai 2011-11-06
+291256 ‘Uqlat an Nakhlah `Uqlat an Nakhlah An Nakhlah,Nakhla,`Uglat Nakhlan,`Uqlat al-Nakhlah,`Uqlat an Nakhlah,‘Uglat Nakhlan,‘Uqlat al-Nakhlah,‘Uqlat an Nakhlah 24.31667 51.2 H WLL AE 01 0 7 Asia/Dubai 2011-11-06
+291257 Ramlat an Nakhlah Ramlat an Nakhlah Ramlat an Nakhlah 24.35861 51.20632 T DUNE AE 01 0 10 Asia/Dubai 2011-11-06
+291258 Nakhalai Nakhalai Nakhalai 25.09528 55.57653 L LCTY AE 03 0 89 Asia/Dubai 2011-11-06
+291259 Jabal Najla‘ Jabal Najla` Jabal Najla`,Jabal Najla‘ 25.43593 55.99124 T HLL AE 05 0 208 Asia/Dubai 2011-11-06
+291260 Jabal Najdayn Jabal Najdayn Jabal Najdayn,Jabal Naydayn 25.17988 56.17201 T MT AE 00 0 880 Asia/Dubai 2011-11-06
+291261 Najdayn Najdayn Najdayn 25.16667 56.2 V CULT AE 04 0 639 Asia/Dubai 2011-11-06
+291262 NajdÄt Najdat Najadat,NajadÄt,Najdat,NajdÄt 24.13333 55.91667 L TRB AE AE 01 0 378 Asia/Dubai 2011-11-06
+291263 Na‘ītah Na`itah Jazirat Na`itah,Jazīrat Na‘ītah,Na`itah,Naita,Na‘ītah,Ne'ita,Ne’īta,Ni`eitah,Ni‘eitah 24.29085 51.79455 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+291264 NaqÄ NÄ’if Naqa Na'if Naqa Na'if,NaqÄ NÄ’if 23.08742 55.22844 T DUNE AE 01 0 171 Asia/Dubai 2011-11-06
+291265 Nahwá Nahwa Nahawa,Nahwa,Nahwá 25.26823 56.28002 P PPL AE 06 0 213 Asia/Dubai 2011-11-06
+291266 Ţawī Nahshīlah Tawi Nahshilah Tawi Nahshilah,Ţawī Nahshīlah 24.40832 55.10681 H WLL AE 01 0 103 Asia/Dubai 2011-11-06
+291267 Nahshīlah Nahshilah Nahshilah,Nahshīlah 24.4032 55.05936 T SAND AE 01 0 100 Asia/Dubai 2011-11-06
+291268 Nahdayn Nahdayn Nahdain,Nahdayn,Nahdein 23.68333 52.3 S OILW AE AE 01 0 41 Asia/Dubai 2011-11-06
+291269 Nahdayn Nahdayn Nahadain,Nahdayn 23.68725 52.30246 T HLL AE 01 0 49 Asia/Dubai 2011-11-06
+291270 Nafīr Nafir Nafir,Nafīr,Nefair 23.10393 53.78919 P PPL AE 01 0 86 Asia/Dubai 2011-11-06
+291271 Nafīr Nafir Nafir,Nafīr 23.10444 53.78667 T DPR AE 01 0 86 Asia/Dubai 2011-11-06
+291272 NaqÄ Nadh Naqa Nadh Naqa Nadh,NaqÄ Nadh 23.79851 55.49041 T DUNE AE 01 0 194 Asia/Dubai 2011-11-06
+291273 Nadd Umm Ḩaşá Nadd Umm Hasa Nadd Umm Hasa,Nadd Umm Ḩaşá 25.13954 55.38266 L LCTY AE 03 0 20 Asia/Dubai 2011-11-06
+291274 Nadd MÄni‘ Nadd Mani` Nadd Mani`,Nadd MÄni‘,Ned Bin Tamana,Nidd Mani`,Nidd MÄni‘ 25.55306 55.5475 T PEN AE 07 0 18 Asia/Dubai 2011-11-06
+291275 Nadd BayḑÄ’ Nadd Bayda' Nad Beidha,Nadd Bayda',Nadd BayḑÄ’ 25.35352 55.43762 L LCTY AE 06 0 15 Asia/Dubai 2011-11-06
+291276 Ramlat Nadd Ramlat Nadd Ramlat Nadd 23.97641 55.12876 T DUNE AE 01 0 143 Asia/Dubai 2011-11-06
+291277 Naban Naban Naban 24.23824 54.90422 H WLL AE 01 0 77 Asia/Dubai 2011-11-06
+291278 Na‘adhal Na`adhal Na`adhal,Na‘adhal 22.98454 53.54606 T DPR AE 01 0 46 Asia/Dubai 2011-11-06
+291279 Muzayri‘ Muzayri` Mezaira'a,Mezaira’a,Mizeir`ah,Mizeir‘ah,Mozayri`,Mozayri‘,Muzayri`,Muzayri‘ 23.14355 53.7881 P PPL AE 01 10000 181 Asia/Dubai 2011-11-06
+291280 Mughaylat MuzÄri‘ Mughaylat Muzari` Maghailat Muzaria,Mughaylat Muzari`,Mughaylat MuzÄri‘ 24.03333 54.95 H WLL AE 01 0 90 Asia/Dubai 2011-11-06
+291281 GhÄfat al Muyayridah Ghafat al Muyayridah Ghafat al Muyayridah,GhÄfat al Muyayridah 25.6 56.3 H WLL AE 04 0 45 Asia/Dubai 2011-11-06
+291282 Sayḩ Muyaydirah Sayh Muyaydirah Sayh Muyaydirah,Sayḩ Muyaydirah 24.68333 55.4 T TRGD AE 03 0 155 Asia/Dubai 2011-11-06
+291283 Muyaydirah Muyaydirah Muyaydirah 24.7 55.38333 T SAND AE 03 0 118 Asia/Dubai 2011-11-06
+291284 NaqÄ Muwayzah Naqa Muwayzah Naqa Muwayzah,NaqÄ Muwayzah 24.6 55.31667 T SAND AE 01 0 135 Asia/Dubai 2011-11-06
+291285 Ḩişn al Muwayqi‘ī Hisn al Muwayqi`i Hisn al Muwayqi`i,Ḩişn al Muwayqi‘ī 24.21667 55.71667 S FT AE 01 0 266 Asia/Dubai 2011-11-06
+291286 Muwayliḩ Muwaylih Muailah,Muwaylih,Muwayliḩ 24.61506 54.7728 H WLL AE 01 0 24 Asia/Dubai 2011-11-06
+291287 WÄdÄ« al Muwayji‘ah Wadi al Muwayji`ah Wadi al Muwayji`ah,WÄdÄ« al Muwayji‘ah 24.95 55.4 T DPR AE 03 0 85 Asia/Dubai 2011-11-06
+291288 Muwayh Arnab Muwayh Arnab Muwayh Arnab 24.27467 55.05049 T SAND AE 01 0 123 Asia/Dubai 2011-11-06
+291289 Muwayh al Ju’Äbir Muwayh al Ju'abir Muwayh al Ju'abir,Muwayh al Ju’Äbir 23.82211 55.46188 T DUNE AE 01 0 181 Asia/Dubai 2011-11-06
+291290 Muwayh al Huḑayb Muwayh al Hudayb Muwayh al Hudayb,Muwayh al Huḑayb 24.06076 55.35169 T SAND AE 01 0 191 Asia/Dubai 2011-11-06
+291291 Bi’r Muwayfiqah Bi'r Muwayfiqah Bi'r Muwayfiqah,Bi’r Muwayfiqah,Muwafiqa,Muwafiqah,MuwÄfiqa,MuwÄfÄ«qah 24.13194 55.68139 H WLL AE 01 0 247 Asia/Dubai 2011-11-06
+291292 Jabal Muthrad Jabal Muthrad Jabal Muthrad 25.15731 56.28963 T MT AE 04 0 387 Asia/Dubai 2011-11-06
+291293 Ţawī Mutayn Tawi Mutayn Tawi Mutayn,Ţawī Mutayn 23.2725 53.60472 H WLL AE 01 0 141 Asia/Dubai 2011-11-06
+291294 MuÅ£aylÄn Mutaylan Mitailan,Mutailan,Mutaylan,MuÅ£aylÄn 23.84996 53.82125 L AREA AE 01 0 69 Asia/Dubai 2011-11-06
+291295 Mughayyil Muţawwá Mughayyil Mutawwa Mughayyil Mutawwa,Mughayyil Muţawwá 24.06546 54.89046 H WLL AE 01 0 107 Asia/Dubai 2011-11-06
+291296 Bid‘ al MuÅ£Äwa‘ah Bid` al Mutawa`ah Bid' al-Mataw'a,Bid` al Mutawa`ah,Bid` al Mutawwa`,Bid` al-Mataw`ah,Bid‘ al MuÅ£awwa‘,Bid‘ al MuÅ£Äwa‘ah,Bid‘ al-Maá¹Äw‘ah,Bid’ al-Mataw’a 23.75972 52.51917 H WLL AE 01 0 68 Asia/Dubai 2011-11-06
+291297 WÄdÄ« Mu‘tariḑah Wadi Mu`taridah Wadi Mu`taridah,WÄdÄ« Mu‘tariḑah 25.5165 56.00264 H WAD AE 00 0 97 Asia/Dubai 2011-11-06
+291298 Mu‘tariḑah Mu`taridah Mu`taridah,Mu`taridat,Mu‘tariḑah,Mu‘tariḑat 23.93178 52.41949 T RKS AE 01 0 58 Asia/Dubai 2011-11-06
+291299 Mu‘tariḑah Mu`taridah Mu`taridah,Mu‘tariḑah 25.50841 56.11046 P PPL AE 04 0 350 Asia/Dubai 2011-11-06
+291300 Mu‘tariḑah Mu`taridah Mu`taridah,Mu‘tariḑah 24.03558 53.34833 T HLLS AE 01 0 18 Asia/Dubai 2011-11-06
+291301 Mu‘tariḑah Mu`taridah Mu`taridah,Mu‘tariḑah 23.92444 52.43222 T DUNE AE 01 0 38 Asia/Dubai 2011-11-06
+291302 Jabal Mu‘tariḑ Jabal Mu`tarid Jabal Ma'atridh,Jabal Ma’atridh,Jabal Mu`tarid,Jabal Mu‘tariḑ 25.45641 55.99319 T HLL AE 05 0 233 Asia/Dubai 2011-11-06
+291303 Bid‘ Mussama Bid` Mussama Bid` Mussama,Bid‘ Mussama 23.55 53.61667 H WLL AE 01 0 128 Asia/Dubai 2011-11-06
+291304 Musaqab Musaqab Musaqab,Musqab 25.16778 56.14167 V GRVP AE AE 05 0 363 Asia/Dubai 2011-11-06
+291305 Mushrif Mushrif Mushrif 25.21667 55.45 H WLL AE 03 0 34 Asia/Dubai 2011-11-06
+291306 Ţawī Mushayrif Tawi Mushayrif Mashairif,Mushairif,Tawi Mushayrif,Ţawī Mushayrif 24.08689 54.81192 H WLL AE 01 0 76 Asia/Dubai 2011-11-06
+291307 Sabkhat Mushayrif Sabkhat Mushayrif Sabkhat Mushayrif 24.15149 54.66116 H SBKH AE 01 0 40 Asia/Dubai 2011-11-06
+291308 Mushayrif Mushayrif Mushayrif 23.92507 54.31447 T TRGD AE 01 0 81 Asia/Dubai 2011-11-06
+291309 Mushayrif Mushayrif Mushairif,Mushayrif 24.11525 54.81618 L LCTY AE 01 0 84 Asia/Dubai 2011-11-06
+291310 Mushayrif Mushayrif Mushayrif 24.11489 54.66871 T DUNE AE 01 0 57 Asia/Dubai 2011-11-06
+291311 Ra’s Mushayrib Ra's Mushayrib Ra's Mashayrib,Ra's Mushayrib,Ras Mashairif,Ras Masheirib,Ras Masherib,Ras Mushairib,Ras Musheirib,Ra’s Mashayrib,Ra’s Mushayrib,RÄs Mushairib 24.29292 51.74242 T PT AE 01 0 -9999 Asia/Dubai 2011-11-06
+291312 Mushayrib Mushayrib Mushayrib 24.46667 54.41667 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+291313 MushÄshÄ« Mushashi Mashashi,Mushashi,MushÄshÄ« 23.11124 52.5636 S OILW AE 01 0 114 Asia/Dubai 2011-11-06
+291314 MushÄsh Mushash Imshash,Mushash,MushÄsh 24.55769 51.35768 H WLL AE 01 0 -9999 Asia/Dubai 2011-11-06
+291315 MushÄjir Mushajir Mushajir,MushÄjir 23.08605 53.99163 L OAS AE 01 0 178 Asia/Dubai 2011-11-06
+291316 MushÄjir Mushajir Mushajir,MushÄjir 23.07049 53.93374 T DPR AE 01 0 73 Asia/Dubai 2011-11-06
+291317 Bid‘ Muşfir Bid` Musfir Bid` Musfir,Bid‘ Muşfir,Bir Misfar 24.0619 55.29648 H WLL AE 01 0 175 Asia/Dubai 2011-11-06
+291318 Ruqq Musfayr Ruqq Musfayr Ruqq Musfayr 24.27875 51.88656 H RF AE 01 0 -9999 Asia/Dubai 2011-11-06
+291319 Musayyibah Musayyibah Musayyibah 23.82699 55.2768 T TRGD AE 01 0 122 Asia/Dubai 2011-11-06
+291320 Ţawī Musannad Tawi Musannad Tawi Musannad,Tawi Mussarad,Ţawī Musannad,Ţawī Mussarad 25.25 55.7 H WLL AE AE 06 0 111 Asia/Dubai 2011-11-06
+291321 Sayḩ Musannad Sayh Musannad Sayh Musannad,Sayḩ Musannad 25.25104 55.67154 T TRGD AE 06 0 71 Asia/Dubai 2011-11-06
+291322 WÄdÄ« MusallÄ Wadi Musalla Wadi Musalla,WÄdÄ« MusallÄ 25.51575 56.00944 H WAD AE 04 0 142 Asia/Dubai 2011-11-06
+291323 Ḩadd Musafsif Hadd Musafsif Hadd Musafsif,Ḩadd Musafsif 24.10083 52.06417 H SHOL AE 01 0 -9999 Asia/Dubai 2011-11-06
+291324 Khawr Musá Khawr Musa Khawr Musa,Khawr Musá 22.725 53.51671 T DPR AE 01 0 62 Asia/Dubai 2011-11-06
+291325 Sayḩ Muruq Sayh Muruq Sayh Muruq,Sayḩ Muruq 25.56617 56.0731 T DPR AE 04 0 211 Asia/Dubai 2011-11-06
+291326 WÄdÄ« Murtaqam Wadi Murtaqam Wadi Murtaqam,Wadi Murtaqau,WÄdÄ« Murtaqam,WÄdÄ« Murtaqau 25.36727 56.25448 H WAD AE 04 0 277 Asia/Dubai 2011-11-06
+291327 WÄdÄ« Murrah Wadi Murrah Wadi Murrah,WÄdÄ« Murrah 25.19803 56.22673 H WAD AE 04 0 321 Asia/Dubai 2011-11-06
+291328 WÄdÄ« Murrah Wadi Murrah Wadi Murrah,WÄdÄ« Murrah 24.9 55.43333 T TRGD AE 03 0 105 Asia/Dubai 2011-11-06
+291329 Å¢awÄ« Murrah Tawi Murrah Al-Murrah,Qa`r Murra,Qa‘r Murra,Tawi Murra,Tawi Murrah,Å¢awÄ« Murrah,Å¢ÄwÄ« Murra 25.13443 55.74992 H WLL AE 06 0 117 Asia/Dubai 2011-11-06
+291330 Ţawī Murrah Tawi Murrah Tawi Morro,Tawi Motto,Tawi Murra,Tawi Murrah,Ţawī Murrah 24.90846 55.44146 H WLL AE 03 0 113 Asia/Dubai 2011-11-06
+291331 Raml Murrah Raml Murrah Raml Murrah 24.86266 55.38085 T SAND AE 03 0 80 Asia/Dubai 2011-11-06
+291332 Qarn Murrah Qarn Murrah Qarat Murra,Qarat Murrah,Qarn Murrah,QÄrat Murra,QÄrat Murrah 25.13349 55.7703 T DUNE AE 06 0 150 Asia/Dubai 2011-11-06
+291333 Murrah Murrah Murrah 25.03333 55.6 V TREE AE 03 0 162 Asia/Dubai 2011-11-06
+291334 Murrah Murrah Murrah 25.19903 56.22165 P PPL AE 04 0 223 Asia/Dubai 2011-11-06
+291335 Muriya HammÄmah Muriya Hammamah Muriya Hammamah,Muriya HammÄmah 24.93333 54.26667 T RKS AE 01 0 -9999 Asia/Dubai 2011-11-06
+291336 Ḩaql MurbÄn Haql Murban Haql Murban,Mirban,Murban Field,Ḩaql MurbÄn 23.83333 53.75 L OILF AE AE 01 0 76 Asia/Dubai 2011-11-06
+291337 MurbÄn Murban Mirban,MirbÄn,Murban,MurbÄn 23.95342 53.69134 T HLL AE 01 0 3 Asia/Dubai 2011-11-06
+291338 Sabkhat Murbaḩ Sabkhat Murbah Sabkhat Murbah,Sabkhat Murbaḩ 25.25 56.36667 H SBKH AE 04 0 -9999 Asia/Dubai 2011-11-06
+291339 Murbaḩ Murbah Marbah,Mirba,Mirbih,Mirbiḥ,Murbah,Murbaḩ 25.27623 56.36256 P PPL AE 06 0 23 Asia/Dubai 2011-11-06
+291340 Murbaḑ Murbad Marbad,Murbad,Murbaḑ 25.3254 56.13311 P PPL AE 04 0 487 Asia/Dubai 2011-11-06
+291341 Murayyil Murayyil Murayyil 25.11667 55.51667 V TREE AE 06 0 82 Asia/Dubai 2011-11-06
+291342 Muraytah Muraytah Muraytah 25.40032 56.05844 P PPL AE 05 0 240 Asia/Dubai 2011-11-06
+291343 WÄdÄ« Murayshid Wadi Murayshid Wadi Murayshid,WÄdÄ« Murayshid 25.1 56.36667 H WAD AE 04 0 -9999 Asia/Dubai 2011-11-06
+291344 Jabal Murayshid Jabal Murayshid Jabal Murayshid 25.11667 56.33333 T HLL AE 04 0 35 Asia/Dubai 2011-11-06
+291345 Barqat Muraymīth Barqat Muraymith Barqat Muraymith,Barqat Muraymīth 23.88902 54.47119 T RKS AE 01 0 88 Asia/Dubai 2011-11-06
+291346 Muraykh Muraykh Maraikh,Muraykh 24 55.41667 H WLL AE AE 01 0 188 Asia/Dubai 2011-11-06
+291347 Ţawī Muray Tawi Muray Tawi Muray,Ţawī Muray 23.86667 54.61667 H WLL AE 01 0 86 Asia/Dubai 2011-11-06
+291348 Å¢awÄ« MuraqqibÄt Tawi Muraqqibat Muraghabat,Muraqabat,Muraqqibat,Tawi Muraqqibat,Å¢awÄ« MuraqqibÄt 25.32611 55.89944 H WLL AE AE 07 0 170 Asia/Dubai 2011-11-06
+291349 Ţawī Muraqqab Tawi Muraqqab Tawi Muraqqab,Ţawī Muraqqab 24.82029 55.58435 H WLL AE 03 0 182 Asia/Dubai 2011-11-06
+291350 MurÄqabÄt Muraqabat Muraqabat,MurÄqabÄt 25.16361 55.34111 H WLL AE 03 0 13 Asia/Dubai 2011-11-06
+291351 Murabba‘ah Murabba`ah Murabba`ah,Murabba‘ah 25.88333 56.03333 S TOWR AE 05 0 1 Asia/Dubai 2011-11-06
+291352 Ra’s Muqayshiţ Ra's Muqayshit Mughhaishat,Ra's Muqayshit,Ra's al Ibrah,Ra’s Muqayshiţ,Ra’s al Ibrah 24.16778 53.6236 T PT AE 01 0 -9999 Asia/Dubai 2011-11-06
+291353 Muqayshiţ Muqayshit Megaishit,Megeshit,Megeshiţ,Muqayshit,Muqayshiţ 24.18908 53.75226 T ISLX AE 01 0 10 Asia/Dubai 2011-11-06
+291354 Muqaţţarah Muqattarah Miqattarah,Miqaá¹á¹arah,Mugatara,Mugattara,Mugaţţara,Muqatirah,Muqattarah,Muqaţţarah,MuqÄtirah 24.2694 54.51333 T HLL AE 01 0 10 Asia/Dubai 2011-11-06
+291355 Muqala Muqala Muqala 23.53333 54.43333 H WLL AE 01 0 131 Asia/Dubai 2011-11-06
+291356 Muntahá Muntaha Mntaha,Muntaha,Muntahá 23.84263 55.41381 T DPR AE 01 0 187 Asia/Dubai 2011-11-06
+291357 Munfatrah Munfatrah Mufatra,Munfatrah 23.96667 53.03333 T HLL AE AE 01 0 39 Asia/Dubai 2011-11-06
+291358 Mundafinah Mundafinah Mondafanah,Mondafinah,Mundafinah,Mundafnah 24.11667 55.8 P PPL AE AE 01 0 320 Asia/Dubai 2011-11-06
+291359 Khawr ManÄ’if Khawr Mana'if Khawr Mana'if,Khawr ManÄ’if,Khawr Munayyif,Khor Manayef,Khor ManÄyef 24.14456 52.91494 H COVE AE 01 0 -9999 Asia/Dubai 2011-11-06
+291360 Munayyif Munayyif Munayyif 24.07278 52.94833 L LCTY AE 01 0 22 Asia/Dubai 2011-11-06
+291361 Munayyif Munayyif Munaiyif,Munayyif 24.09324 52.93446 T HLL AE 01 0 51 Asia/Dubai 2011-11-06
+291362 WÄdÄ« Munay‘ī Wadi Munay`i Wadi Manai,Wadi Munay`,Wadi Munay`i,WÄdÄ« Munay‘,WÄdÄ« Munay‘ī 24.88227 56.20944 H WAD AE 05 0 142 Asia/Dubai 2011-11-06
+291363 Munay‘ī Munay`i Manai,Manai'i,Manai’i,Munay`i,Munay‘ī 24.95135 56.14997 P PPL AE 05 0 370 Asia/Dubai 2011-11-06
+291364 Jabal Mulfīrah Jabal Mulfirah Jabal Mulfirah,Jabal Mulfīrah 25.15716 56.31601 T HLL AE 04 0 229 Asia/Dubai 2011-11-06
+291365 Mulaysah Mulaysah Mulaysah 23.91634 53.03505 H WLL AE 01 0 63 Asia/Dubai 2011-11-06
+291366 Mulaysah Mulaysah Mulaysah 23.9 53.05 H WLL AE 01 0 51 Asia/Dubai 2011-11-06
+291367 Mulayhim Mulayhim Malayham,Mulayhim 22.90126 53.43345 T DPR AE 01 0 54 Asia/Dubai 2011-11-06
+291368 WÄdÄ« Mulayḩah Wadi Mulayhah Wadi Mulayhah,WÄdÄ« Mulayḩah 25.73333 56.01667 H WAD AE 05 0 28 Asia/Dubai 2011-11-06
+291369 WÄdÄ« Mulayḩah Wadi Mulayhah Wadi Mulayhah,WÄdÄ« Mulayḩah 25.23504 55.90669 H WAD AE 06 0 121 Asia/Dubai 2011-11-06
+291370 Ţawī Mulayḩah Tawi Mulayhah Tawi Mulaiha,Tawi Mulayhah,Ţawī Mulaiha,Ţawī Mulayḩah 25.02722 55.795 H WLL AE AE 06 0 161 Asia/Dubai 2011-11-06
+291371 Jabal Mulayḩah Jabal Mulayhah Jabal Milaiha,Jabal Mileihah,Jabal Mileiḥah,Jabal Mulayhah,Jabal Mulayḩah,Jibal Mulayhah,JibÄl Mulayḩah,Mulaiha 25.14818 55.83716 T HLL AE 06 0 362 Asia/Dubai 2011-11-06
+291372 Mulayḩah Mulayhah Mileihah,Mileiḥah,Miliaha,Mulayhah,Mulayḩah 25.16667 55.8 H WLLS AE AE 06 0 158 Asia/Dubai 2011-11-06
+291373 Qarn Mulayḩ Qarn Mulayh Qarn Mileih,Qarn Mulayh,Qarn Mulayḩ 25.02286 55.72966 T HLL AE 06 0 274 236 Asia/Dubai 2011-11-06
+291374 Mukhtaraqah Mukhtaraqah Mahtarraqah,Muhtarqah,Mukhtaraja,Mukhtaraqah 25.54092 56.13066 P PPL AE 04 0 272 Asia/Dubai 2011-11-06
+291375 Mukhayūs Mukhayus Mukhayus,Mukhayūs 25.73222 55.95389 H WLL AE 05 0 47 Asia/Dubai 2011-11-06
+291376 MÅ«jib Mujib Mujib,MÅ«jib 23.11667 53.68333 P PPL AE 01 0 84 Asia/Dubai 2011-11-06
+291377 Kharmat al Muhayn Kharmat al Muhayn Kharimat al Mahain,Kharmat al Mahaim,Kharmat al Muhayn 23.01796 55.10773 T DPR AE 01 0 109 Asia/Dubai 2011-11-06
+291378 WÄdÄ« MuhaylÄ« Wadi Muhayli Wadi Muhayli,WÄdÄ« MuhaylÄ« 25.7044 56.06564 H WAD AE 05 0 85 Asia/Dubai 2011-11-06
+291379 Ţawī Muḩayjir Tawi Muhayjir Tawi Muhayjir,Ţawī Muḩayjir 24.5511 55.76381 H WLL AE 01 0 319 Asia/Dubai 2011-11-06
+291380 Jabal Muḩayjir Jabal Muhayjir Jabal Muhayjir,Jabal Muḩayjir,Qarn Muhaiyir 24.53819 55.73512 T HLL AE 01 0 293 Asia/Dubai 2011-11-06
+291381 Muhammalīyah Muhammaliyah Al Mahammaliyah,Jazirat Muhammaliyah,Jazīrat Muḩammalīyah,Mahamaliya,Mehammaliyya,Mehammaliyyah,Muhammaliya,Muhammaliyah,Muhammalīyah 24.11616 51.89603 T ISL AE 01 0 -9999 Asia/Dubai 2011-11-06
+291382 Ţawī Muḩammad Tawi Muhammad Tawi Muhammad,Ţawī Muḩammad 24.94636 55.75046 H WLL AE 06 0 183 Asia/Dubai 2011-11-06
+291383 Bid‘ Muḩammad Bid` Muhammad Bid` Muhammad,Bid‘ Muḩammad 24.25 55.1 H WLL AE 01 0 125 Asia/Dubai 2011-11-06
+291384 Qullat MuḩÄfiz̧ Qullat Muhafiz Qal`eh Mahafidh,Qallah Mahafidh,Qal‘eh MahÄfidh,Qullat Mahafiz,Qullat MaḩÄfiz̧,Qullat Muhafiz,Qullat MuḩÄfiz̧ 25.15848 55.93008 T PLN AE 06 0 164 Asia/Dubai 2011-11-06
+291385 Mughīlah Mughilah Mughila,Mughilah,Mughīlah 23.78842 55.18178 T DPR AE 01 0 113 Asia/Dubai 2011-11-06
+291386 Mughayyin Mughayyin Mughaiyin,Mughayyin 23.89196 52.78213 T SAND AE 01 0 69 Asia/Dubai 2011-11-06
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dataimport/test/data/timeZones.txt Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,410 @@
+Africa/Abidjan 0.0 0.0 0.0
+Africa/Accra 0.0 0.0 0.0
+Africa/Addis_Ababa 3.0 3.0 3.0
+Africa/Algiers 1.0 1.0 1.0
+Africa/Asmara 3.0 3.0 3.0
+Africa/Bamako 0.0 0.0 0.0
+Africa/Bangui 1.0 1.0 1.0
+Africa/Banjul 0.0 0.0 0.0
+Africa/Bissau 0.0 0.0 0.0
+Africa/Blantyre 2.0 2.0 2.0
+Africa/Brazzaville 1.0 1.0 1.0
+Africa/Bujumbura 2.0 2.0 2.0
+Africa/Cairo 2.0 2.0 2.0
+Africa/Casablanca 0.0 1.0 0.0
+Africa/Ceuta 1.0 2.0 1.0
+Africa/Conakry 0.0 0.0 0.0
+Africa/Dakar 0.0 0.0 0.0
+Africa/Dar_es_Salaam 3.0 3.0 3.0
+Africa/Djibouti 3.0 3.0 3.0
+Africa/Douala 1.0 1.0 1.0
+Africa/El_Aaiun 0.0 0.0 0.0
+Africa/Freetown 0.0 0.0 0.0
+Africa/Gaborone 2.0 2.0 2.0
+Africa/Harare 2.0 2.0 2.0
+Africa/Johannesburg 2.0 2.0 2.0
+Africa/Kampala 3.0 3.0 3.0
+Africa/Khartoum 3.0 3.0 3.0
+Africa/Kigali 2.0 2.0 2.0
+Africa/Kinshasa 1.0 1.0 1.0
+Africa/Lagos 1.0 1.0 1.0
+Africa/Libreville 1.0 1.0 1.0
+Africa/Lome 0.0 0.0 0.0
+Africa/Luanda 1.0 1.0 1.0
+Africa/Lubumbashi 2.0 2.0 2.0
+Africa/Lusaka 2.0 2.0 2.0
+Africa/Malabo 1.0 1.0 1.0
+Africa/Maputo 2.0 2.0 2.0
+Africa/Maseru 2.0 2.0 2.0
+Africa/Mbabane 2.0 2.0 2.0
+Africa/Mogadishu 3.0 3.0 3.0
+Africa/Monrovia 0.0 0.0 0.0
+Africa/Nairobi 3.0 3.0 3.0
+Africa/Ndjamena 1.0 1.0 1.0
+Africa/Niamey 1.0 1.0 1.0
+Africa/Nouakchott 0.0 0.0 0.0
+Africa/Ouagadougou 0.0 0.0 0.0
+Africa/Porto-Novo 1.0 1.0 1.0
+Africa/Sao_Tome 0.0 0.0 0.0
+Africa/Tripoli 2.0 2.0 2.0
+Africa/Tunis 1.0 1.0 1.0
+Africa/Windhoek 2.0 1.0 1.0
+America/Adak -10.0 -9.0 -10.0
+America/Anchorage -9.0 -8.0 -9.0
+America/Anguilla -4.0 -4.0 -4.0
+America/Antigua -4.0 -4.0 -4.0
+America/Araguaina -3.0 -3.0 -3.0
+America/Argentina/Buenos_Aires -3.0 -3.0 -3.0
+America/Argentina/Catamarca -3.0 -3.0 -3.0
+America/Argentina/Cordoba -3.0 -3.0 -3.0
+America/Argentina/Jujuy -3.0 -3.0 -3.0
+America/Argentina/La_Rioja -3.0 -3.0 -3.0
+America/Argentina/Mendoza -3.0 -3.0 -3.0
+America/Argentina/Rio_Gallegos -3.0 -3.0 -3.0
+America/Argentina/Salta -3.0 -3.0 -3.0
+America/Argentina/San_Juan -3.0 -3.0 -3.0
+America/Argentina/San_Luis -3.0 -3.0 -4.0
+America/Argentina/Tucuman -3.0 -3.0 -3.0
+America/Argentina/Ushuaia -3.0 -3.0 -3.0
+America/Aruba -4.0 -4.0 -4.0
+America/Asuncion -3.0 -4.0 -4.0
+America/Atikokan -5.0 -5.0 -5.0
+America/Bahia -3.0 -3.0 -3.0
+America/Bahia_Banderas -6.0 -5.0 -6.0
+America/Barbados -4.0 -4.0 -4.0
+America/Belem -3.0 -3.0 -3.0
+America/Belize -6.0 -6.0 -6.0
+America/Blanc-Sablon -4.0 -4.0 -4.0
+America/Boa_Vista -4.0 -4.0 -4.0
+America/Bogota -5.0 -5.0 -5.0
+America/Boise -7.0 -6.0 -7.0
+America/Cambridge_Bay -7.0 -6.0 -7.0
+America/Campo_Grande -3.0 -4.0 -4.0
+America/Cancun -6.0 -5.0 -6.0
+America/Caracas -4.5 -4.5 -4.5
+America/Cayenne -3.0 -3.0 -3.0
+America/Cayman -5.0 -5.0 -5.0
+America/Chicago -6.0 -5.0 -6.0
+America/Chihuahua -7.0 -6.0 -7.0
+America/Costa_Rica -6.0 -6.0 -6.0
+America/Cuiaba -3.0 -4.0 -4.0
+America/Curacao -4.0 -4.0 -4.0
+America/Danmarkshavn 0.0 0.0 0.0
+America/Dawson -8.0 -7.0 -8.0
+America/Dawson_Creek -7.0 -7.0 -7.0
+America/Denver -7.0 -6.0 -7.0
+America/Detroit -5.0 -4.0 -5.0
+America/Dominica -4.0 -4.0 -4.0
+America/Edmonton -7.0 -6.0 -7.0
+America/Eirunepe -4.0 -4.0 -4.0
+America/El_Salvador -6.0 -6.0 -6.0
+America/Fortaleza -3.0 -3.0 -3.0
+America/Glace_Bay -4.0 -3.0 -4.0
+America/Godthab -3.0 -2.0 -3.0
+America/Goose_Bay -4.0 -3.0 -4.0
+America/Grand_Turk -5.0 -4.0 -5.0
+America/Grenada -4.0 -4.0 -4.0
+America/Guadeloupe -4.0 -4.0 -4.0
+America/Guatemala -6.0 -6.0 -6.0
+America/Guayaquil -5.0 -5.0 -5.0
+America/Guyana -4.0 -4.0 -4.0
+America/Halifax -4.0 -3.0 -4.0
+America/Havana -5.0 -4.0 -5.0
+America/Hermosillo -7.0 -7.0 -7.0
+America/Indiana/Indianapolis -5.0 -4.0 -5.0
+America/Indiana/Knox -6.0 -5.0 -6.0
+America/Indiana/Marengo -5.0 -4.0 -5.0
+America/Indiana/Petersburg -5.0 -4.0 -5.0
+America/Indiana/Tell_City -6.0 -5.0 -6.0
+America/Indiana/Vevay -5.0 -4.0 -5.0
+America/Indiana/Vincennes -5.0 -4.0 -5.0
+America/Indiana/Winamac -5.0 -4.0 -5.0
+America/Inuvik -7.0 -6.0 -7.0
+America/Iqaluit -5.0 -4.0 -5.0
+America/Jamaica -5.0 -5.0 -5.0
+America/Juneau -9.0 -8.0 -9.0
+America/Kentucky/Louisville -5.0 -4.0 -5.0
+America/Kentucky/Monticello -5.0 -4.0 -5.0
+America/La_Paz -4.0 -4.0 -4.0
+America/Lima -5.0 -5.0 -5.0
+America/Los_Angeles -8.0 -7.0 -8.0
+America/Maceio -3.0 -3.0 -3.0
+America/Managua -6.0 -6.0 -6.0
+America/Manaus -4.0 -4.0 -4.0
+America/Marigot -4.0 -4.0 -4.0
+America/Martinique -4.0 -4.0 -4.0
+America/Matamoros -6.0 -5.0 -6.0
+America/Mazatlan -7.0 -6.0 -7.0
+America/Menominee -6.0 -5.0 -6.0
+America/Merida -6.0 -5.0 -6.0
+America/Metlakatla -8.0 -8.0 -8.0
+America/Mexico_City -6.0 -5.0 -6.0
+America/Miquelon -3.0 -2.0 -3.0
+America/Moncton -4.0 -3.0 -4.0
+America/Monterrey -6.0 -5.0 -6.0
+America/Montevideo -2.0 -3.0 -3.0
+America/Montreal -5.0 -4.0 -5.0
+America/Montserrat -4.0 -4.0 -4.0
+America/Nassau -5.0 -4.0 -5.0
+America/New_York -5.0 -4.0 -5.0
+America/Nipigon -5.0 -4.0 -5.0
+America/Nome -9.0 -8.0 -9.0
+America/Noronha -2.0 -2.0 -2.0
+America/North_Dakota/Beulah -6.0 -5.0 -6.0
+America/North_Dakota/Center -6.0 -5.0 -6.0
+America/North_Dakota/New_Salem -6.0 -5.0 -6.0
+America/Ojinaga -7.0 -6.0 -7.0
+America/Panama -5.0 -5.0 -5.0
+America/Pangnirtung -5.0 -4.0 -5.0
+America/Paramaribo -3.0 -3.0 -3.0
+America/Phoenix -7.0 -7.0 -7.0
+America/Port-au-Prince -5.0 -5.0 -5.0
+America/Port_of_Spain -4.0 -4.0 -4.0
+America/Porto_Velho -4.0 -4.0 -4.0
+America/Puerto_Rico -4.0 -4.0 -4.0
+America/Rainy_River -6.0 -5.0 -6.0
+America/Rankin_Inlet -6.0 -5.0 -6.0
+America/Recife -3.0 -3.0 -3.0
+America/Regina -6.0 -6.0 -6.0
+America/Resolute -6.0 -5.0 -6.0
+America/Rio_Branco -4.0 -4.0 -4.0
+America/Santa_Isabel -8.0 -7.0 -8.0
+America/Santarem -3.0 -3.0 -3.0
+America/Santiago -3.0 -4.0 -4.0
+America/Santo_Domingo -4.0 -4.0 -4.0
+America/Sao_Paulo -2.0 -3.0 -3.0
+America/Scoresbysund -1.0 0.0 -1.0
+America/Shiprock -7.0 -6.0 -7.0
+America/Sitka -9.0 -8.0 -9.0
+America/St_Barthelemy -4.0 -4.0 -4.0
+America/St_Johns -3.5 -2.5 -3.5
+America/St_Kitts -4.0 -4.0 -4.0
+America/St_Lucia -4.0 -4.0 -4.0
+America/St_Thomas -4.0 -4.0 -4.0
+America/St_Vincent -4.0 -4.0 -4.0
+America/Swift_Current -6.0 -6.0 -6.0
+America/Tegucigalpa -6.0 -6.0 -6.0
+America/Thule -4.0 -3.0 -4.0
+America/Thunder_Bay -5.0 -4.0 -5.0
+America/Tijuana -8.0 -7.0 -8.0
+America/Toronto -5.0 -4.0 -5.0
+America/Tortola -4.0 -4.0 -4.0
+America/Vancouver -8.0 -7.0 -8.0
+America/Whitehorse -8.0 -7.0 -8.0
+America/Winnipeg -6.0 -5.0 -6.0
+America/Yakutat -9.0 -8.0 -9.0
+America/Yellowknife -7.0 -6.0 -7.0
+Antarctica/Casey 8.0 8.0 8.0
+Antarctica/Davis 7.0 7.0 7.0
+Antarctica/DumontDUrville 10.0 10.0 10.0
+Antarctica/Macquarie 11.0 11.0 11.0
+Antarctica/Mawson 5.0 5.0 5.0
+Antarctica/McMurdo 13.0 12.0 12.0
+Antarctica/Palmer -3.0 -4.0 -4.0
+Antarctica/Rothera -3.0 -3.0 -3.0
+Antarctica/South_Pole 13.0 12.0 12.0
+Antarctica/Syowa 3.0 3.0 3.0
+Antarctica/Vostok 6.0 6.0 6.0
+Arctic/Longyearbyen 1.0 2.0 1.0
+Asia/Aden 3.0 3.0 3.0
+Asia/Almaty 6.0 6.0 6.0
+Asia/Amman 2.0 3.0 2.0
+Asia/Anadyr 11.0 12.0 12.0
+Asia/Aqtau 5.0 5.0 5.0
+Asia/Aqtobe 5.0 5.0 5.0
+Asia/Ashgabat 5.0 5.0 5.0
+Asia/Baghdad 3.0 3.0 3.0
+Asia/Bahrain 3.0 3.0 3.0
+Asia/Baku 4.0 5.0 4.0
+Asia/Bangkok 7.0 7.0 7.0
+Asia/Beirut 2.0 3.0 2.0
+Asia/Bishkek 6.0 6.0 6.0
+Asia/Brunei 8.0 8.0 8.0
+Asia/Choibalsan 8.0 8.0 8.0
+Asia/Chongqing 8.0 8.0 8.0
+Asia/Colombo 5.5 5.5 5.5
+Asia/Damascus 2.0 3.0 2.0
+Asia/Dhaka 6.0 6.0 6.0
+Asia/Dili 9.0 9.0 9.0
+Asia/Dubai 4.0 4.0 4.0
+Asia/Dushanbe 5.0 5.0 5.0
+Asia/Gaza 2.0 3.0 2.0
+Asia/Harbin 8.0 8.0 8.0
+Asia/Ho_Chi_Minh 7.0 7.0 7.0
+Asia/Hong_Kong 8.0 8.0 8.0
+Asia/Hovd 7.0 7.0 7.0
+Asia/Irkutsk 8.0 9.0 9.0
+Asia/Jakarta 7.0 7.0 7.0
+Asia/Jayapura 9.0 9.0 9.0
+Asia/Jerusalem 2.0 3.0 2.0
+Asia/Kabul 4.5 4.5 4.5
+Asia/Kamchatka 11.0 12.0 12.0
+Asia/Karachi 5.0 5.0 5.0
+Asia/Kashgar 8.0 8.0 8.0
+Asia/Kathmandu 5.75 5.75 5.75
+Asia/Kolkata 5.5 5.5 5.5
+Asia/Krasnoyarsk 7.0 8.0 8.0
+Asia/Kuala_Lumpur 8.0 8.0 8.0
+Asia/Kuching 8.0 8.0 8.0
+Asia/Kuwait 3.0 3.0 3.0
+Asia/Macau 8.0 8.0 8.0
+Asia/Magadan 11.0 12.0 12.0
+Asia/Makassar 8.0 8.0 8.0
+Asia/Manila 8.0 8.0 8.0
+Asia/Muscat 4.0 4.0 4.0
+Asia/Nicosia 2.0 3.0 2.0
+Asia/Novokuznetsk 6.0 7.0 7.0
+Asia/Novosibirsk 6.0 7.0 7.0
+Asia/Omsk 6.0 7.0 7.0
+Asia/Oral 5.0 5.0 5.0
+Asia/Phnom_Penh 7.0 7.0 7.0
+Asia/Pontianak 7.0 7.0 7.0
+Asia/Pyongyang 9.0 9.0 9.0
+Asia/Qatar 3.0 3.0 3.0
+Asia/Qyzylorda 6.0 6.0 6.0
+Asia/Rangoon 6.5 6.5 6.5
+Asia/Riyadh 3.0 3.0 3.0
+Asia/Sakhalin 10.0 11.0 11.0
+Asia/Samarkand 5.0 5.0 5.0
+Asia/Seoul 9.0 9.0 9.0
+Asia/Shanghai 8.0 8.0 8.0
+Asia/Singapore 8.0 8.0 8.0
+Asia/Taipei 8.0 8.0 8.0
+Asia/Tashkent 5.0 5.0 5.0
+Asia/Tbilisi 4.0 4.0 4.0
+Asia/Tehran 3.5 4.5 3.5
+Asia/Thimphu 6.0 6.0 6.0
+Asia/Tokyo 9.0 9.0 9.0
+Asia/Ulaanbaatar 8.0 8.0 8.0
+Asia/Urumqi 8.0 8.0 8.0
+Asia/Vientiane 7.0 7.0 7.0
+Asia/Vladivostok 10.0 11.0 11.0
+Asia/Yakutsk 9.0 10.0 10.0
+Asia/Yekaterinburg 5.0 6.0 6.0
+Asia/Yerevan 4.0 5.0 4.0
+Atlantic/Azores -1.0 0.0 -1.0
+Atlantic/Bermuda -4.0 -3.0 -4.0
+Atlantic/Canary 0.0 1.0 0.0
+Atlantic/Cape_Verde -1.0 -1.0 -1.0
+Atlantic/Faroe 0.0 1.0 0.0
+Atlantic/Madeira 0.0 1.0 0.0
+Atlantic/Reykjavik 0.0 0.0 0.0
+Atlantic/South_Georgia -2.0 -2.0 -2.0
+Atlantic/St_Helena 0.0 0.0 0.0
+Atlantic/Stanley -3.0 -3.0 -4.0
+Australia/Adelaide 10.5 9.5 9.5
+Australia/Brisbane 10.0 10.0 10.0
+Australia/Broken_Hill 10.5 9.5 9.5
+Australia/Currie 11.0 10.0 10.0
+Australia/Darwin 9.5 9.5 9.5
+Australia/Eucla 8.75 8.75 8.75
+Australia/Hobart 11.0 10.0 10.0
+Australia/Lindeman 10.0 10.0 10.0
+Australia/Lord_Howe 11.0 10.5 10.5
+Australia/Melbourne 11.0 10.0 10.0
+Australia/Perth 8.0 8.0 8.0
+Australia/Sydney 11.0 10.0 10.0
+Europe/Amsterdam 1.0 2.0 1.0
+Europe/Andorra 1.0 2.0 1.0
+Europe/Athens 2.0 3.0 2.0
+Europe/Belgrade 1.0 2.0 1.0
+Europe/Berlin 1.0 2.0 1.0
+Europe/Bratislava 1.0 2.0 1.0
+Europe/Brussels 1.0 2.0 1.0
+Europe/Bucharest 2.0 3.0 2.0
+Europe/Budapest 1.0 2.0 1.0
+Europe/Chisinau 2.0 3.0 2.0
+Europe/Copenhagen 1.0 2.0 1.0
+Europe/Dublin 0.0 1.0 0.0
+Europe/Gibraltar 1.0 2.0 1.0
+Europe/Guernsey 0.0 1.0 0.0
+Europe/Helsinki 2.0 3.0 2.0
+Europe/Isle_of_Man 0.0 1.0 0.0
+Europe/Istanbul 2.0 3.0 2.0
+Europe/Jersey 0.0 1.0 0.0
+Europe/Kaliningrad 2.0 3.0 3.0
+Europe/Kiev 2.0 3.0 3.0
+Europe/Lisbon 0.0 1.0 0.0
+Europe/Ljubljana 1.0 2.0 1.0
+Europe/London 0.0 1.0 0.0
+Europe/Luxembourg 1.0 2.0 1.0
+Europe/Madrid 1.0 2.0 1.0
+Europe/Malta 1.0 2.0 1.0
+Europe/Mariehamn 2.0 3.0 2.0
+Europe/Minsk 2.0 3.0 3.0
+Europe/Monaco 1.0 2.0 1.0
+Europe/Moscow 3.0 4.0 4.0
+Europe/Oslo 1.0 2.0 1.0
+Europe/Paris 1.0 2.0 1.0
+Europe/Podgorica 1.0 2.0 1.0
+Europe/Prague 1.0 2.0 1.0
+Europe/Riga 2.0 3.0 2.0
+Europe/Rome 1.0 2.0 1.0
+Europe/Samara 3.0 4.0 4.0
+Europe/San_Marino 1.0 2.0 1.0
+Europe/Sarajevo 1.0 2.0 1.0
+Europe/Simferopol 2.0 3.0 3.0
+Europe/Skopje 1.0 2.0 1.0
+Europe/Sofia 2.0 3.0 2.0
+Europe/Stockholm 1.0 2.0 1.0
+Europe/Tallinn 2.0 3.0 2.0
+Europe/Tirane 1.0 2.0 1.0
+Europe/Uzhgorod 2.0 3.0 3.0
+Europe/Vaduz 1.0 2.0 1.0
+Europe/Vatican 1.0 2.0 1.0
+Europe/Vienna 1.0 2.0 1.0
+Europe/Vilnius 2.0 3.0 2.0
+Europe/Volgograd 3.0 4.0 4.0
+Europe/Warsaw 1.0 2.0 1.0
+Europe/Zagreb 1.0 2.0 1.0
+Europe/Zaporozhye 2.0 3.0 3.0
+Europe/Zurich 1.0 2.0 1.0
+Indian/Antananarivo 3.0 3.0 3.0
+Indian/Chagos 6.0 6.0 6.0
+Indian/Christmas 7.0 7.0 7.0
+Indian/Cocos 6.5 6.5 6.5
+Indian/Comoro 3.0 3.0 3.0
+Indian/Kerguelen 5.0 5.0 5.0
+Indian/Mahe 4.0 4.0 4.0
+Indian/Maldives 5.0 5.0 5.0
+Indian/Mauritius 4.0 4.0 4.0
+Indian/Mayotte 3.0 3.0 3.0
+Indian/Reunion 4.0 4.0 4.0
+Pacific/Apia -10.0 -11.0 -11.0
+Pacific/Auckland 13.0 12.0 12.0
+Pacific/Chatham 13.75 12.75 12.75
+Pacific/Chuuk 10.0 10.0 10.0
+Pacific/Easter -5.0 -6.0 -6.0
+Pacific/Efate 11.0 11.0 11.0
+Pacific/Enderbury 13.0 13.0 13.0
+Pacific/Fakaofo -10.0 -10.0 -10.0
+Pacific/Fiji 13.0 12.0 12.0
+Pacific/Funafuti 12.0 12.0 12.0
+Pacific/Galapagos -6.0 -6.0 -6.0
+Pacific/Gambier -9.0 -9.0 -9.0
+Pacific/Guadalcanal 11.0 11.0 11.0
+Pacific/Guam 10.0 10.0 10.0
+Pacific/Honolulu -10.0 -10.0 -10.0
+Pacific/Johnston -10.0 -10.0 -10.0
+Pacific/Kiritimati 14.0 14.0 14.0
+Pacific/Kosrae 11.0 11.0 11.0
+Pacific/Kwajalein 12.0 12.0 12.0
+Pacific/Majuro 12.0 12.0 12.0
+Pacific/Marquesas -9.5 -9.5 -9.5
+Pacific/Midway -11.0 -11.0 -11.0
+Pacific/Nauru 12.0 12.0 12.0
+Pacific/Niue -11.0 -11.0 -11.0
+Pacific/Norfolk 11.5 11.5 11.5
+Pacific/Noumea 11.0 11.0 11.0
+Pacific/Pago_Pago -11.0 -11.0 -11.0
+Pacific/Palau 9.0 9.0 9.0
+Pacific/Pitcairn -8.0 -8.0 -8.0
+Pacific/Pohnpei 11.0 11.0 11.0
+Pacific/Port_Moresby 10.0 10.0 10.0
+Pacific/Rarotonga -10.0 -10.0 -10.0
+Pacific/Saipan 10.0 10.0 10.0
+Pacific/Tahiti -10.0 -10.0 -10.0
+Pacific/Tarawa 12.0 12.0 12.0
+Pacific/Tongatapu 13.0 13.0 13.0
+Pacific/Wake 12.0 12.0 12.0
+Pacific/Wallis 12.0 12.0 12.0
--- a/dataimport/test/test_csv.py Wed Dec 09 18:42:13 2015 +0100
+++ b/dataimport/test/test_csv.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,7 +17,7 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""unittest for cubicweb.dataimport.csv"""
-from StringIO import StringIO
+from io import BytesIO
from logilab.common.testlib import TestCase, unittest_main
@@ -27,7 +27,7 @@
class UcsvreaderTC(TestCase):
def test_empty_lines_skipped(self):
- stream = StringIO('''a,b,c,d,
+ stream = BytesIO(b'''a,b,c,d,
1,2,3,4,
,,,,
,,,,
@@ -45,7 +45,7 @@
list(csv.ucsvreader(stream, skip_empty=False)))
def test_skip_first(self):
- stream = StringIO('a,b,c,d,\n1,2,3,4,\n')
+ stream = BytesIO(b'a,b,c,d,\n1,2,3,4,\n')
reader = csv.ucsvreader(stream, skipfirst=True, ignore_errors=True)
self.assertEqual(list(reader),
[[u'1', u'2', u'3', u'4', u'']])
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/dataimport/test/test_massive_store.py Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,263 @@
+# -*- coding: utf-8 -*-
+# copyright 2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr -- mailto:contact@logilab.fr
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+"""Massive store test case"""
+
+import itertools
+
+from cubicweb.dataimport import ucsvreader
+from cubicweb.devtools import testlib, PostgresApptestConfiguration
+from cubicweb.devtools import startpgcluster, stoppgcluster
+from cubicweb.dataimport.massive_store import MassiveObjectStore
+
+
+def setUpModule():
+ startpgcluster(__file__)
+
+
+def tearDownModule(*args):
+ stoppgcluster(__file__)
+
+
+class MassImportSimpleTC(testlib.CubicWebTC):
+ configcls = PostgresApptestConfiguration
+ appid = 'data-massimport'
+
+ def cast(self, _type, value):
+ try:
+ return _type(value)
+ except ValueError:
+ return None
+
+ def push_geonames_data(self, dumpname, store):
+ # Push timezones
+ cnx = store._cnx
+ for code, gmt, dst, raw_offset in ucsvreader(open(self.datapath('timeZones.txt'), 'rb'),
+ delimiter='\t'):
+ cnx.create_entity('TimeZone', code=code, gmt=float(gmt),
+ dst=float(dst), raw_offset=float(raw_offset))
+ timezone_code = dict(cnx.execute('Any C, X WHERE X is TimeZone, X code C'))
+ # Push data
+ for ind, infos in enumerate(ucsvreader(open(dumpname, 'rb'),
+ delimiter='\t',
+ ignore_errors=True)):
+ latitude = self.cast(float, infos[4])
+ longitude = self.cast(float, infos[5])
+ population = self.cast(int, infos[14])
+ elevation = self.cast(int, infos[15])
+ gtopo = self.cast(int, infos[16])
+ feature_class = infos[6]
+ if len(infos[6]) != 1:
+ feature_class = None
+ entity = {'name': infos[1],
+ 'asciiname': infos[2],
+ 'alternatenames': infos[3],
+ 'latitude': latitude, 'longitude': longitude,
+ 'feature_class': feature_class,
+ 'alternate_country_code':infos[9],
+ 'admin_code_3': infos[12],
+ 'admin_code_4': infos[13],
+ 'population': population, 'elevation': elevation,
+ 'gtopo30': gtopo, 'timezone': timezone_code.get(infos[17]),
+ 'cwuri': u'http://sws.geonames.org/%s/' % int(infos[0]),
+ 'geonameid': int(infos[0]),
+ }
+ store.prepare_insert_entity('Location', **entity)
+
+ def test_autoflush_metadata(self):
+ with self.admin_access.repo_cnx() as cnx:
+ crs = cnx.system_sql('SELECT * FROM entities WHERE type=%(t)s',
+ {'t': 'Location'})
+ self.assertEqual(len(crs.fetchall()), 0)
+ store = MassiveObjectStore(cnx)
+ store.prepare_insert_entity('Location', name=u'toto')
+ store.flush()
+ store.commit()
+ store.finish()
+ cnx.commit()
+ with self.admin_access.repo_cnx() as cnx:
+ crs = cnx.system_sql('SELECT * FROM entities WHERE type=%(t)s',
+ {'t': 'Location'})
+ self.assertEqual(len(crs.fetchall()), 1)
+
+ def test_massimport_etype_metadata(self):
+ with self.admin_access.repo_cnx() as cnx:
+ store = MassiveObjectStore(cnx)
+ timezone_eid = store.prepare_insert_entity('TimeZone')
+ store.prepare_insert_entity('Location', timezone=timezone_eid)
+ store.flush()
+ store.commit()
+ eid, etname = cnx.execute('Any X, TN WHERE X timezone TZ, X is T, '
+ 'T name TN')[0]
+ self.assertEqual(cnx.entity_from_eid(eid).cw_etype, etname)
+
+ def test_drop_index(self):
+ with self.admin_access.repo_cnx() as cnx:
+ store = MassiveObjectStore(cnx)
+ cnx.commit()
+ with self.admin_access.repo_cnx() as cnx:
+ crs = cnx.system_sql('SELECT indexname FROM pg_indexes')
+ indexes = [r[0] for r in crs.fetchall()]
+ self.assertNotIn('entities_pkey', indexes)
+ self.assertNotIn('unique_entities_extid_idx', indexes)
+ self.assertNotIn('owned_by_relation_pkey', indexes)
+ self.assertNotIn('owned_by_relation_to_idx', indexes)
+
+ def test_drop_index_recreation(self):
+ with self.admin_access.repo_cnx() as cnx:
+ store = MassiveObjectStore(cnx)
+ store.finish()
+ cnx.commit()
+ with self.admin_access.repo_cnx() as cnx:
+ crs = cnx.system_sql('SELECT indexname FROM pg_indexes')
+ indexes = [r[0] for r in crs.fetchall()]
+ self.assertIn('entities_pkey', indexes)
+ self.assertIn('unique_entities_extid_idx', indexes)
+ self.assertIn('owned_by_relation_p_key', indexes)
+ self.assertIn('owned_by_relation_to_idx', indexes)
+
+ def test_eids_seq_range(self):
+ class MyMassiveObjectStore(MassiveObjectStore):
+ eids_seq_range = 1000
+ eids_seq_start = 50000
+
+ with self.admin_access.repo_cnx() as cnx:
+ store = MyMassiveObjectStore(cnx)
+ store.prepare_insert_entity('Location', name=u'toto')
+ store.flush()
+ cnx.commit()
+ with self.admin_access.repo_cnx() as cnx:
+ crs = cnx.system_sql("SELECT * FROM entities_id_seq")
+ self.assertGreater(crs.fetchone()[0], 50000)
+
+ def test_eid_entity(self):
+ class MyMassiveObjectStore(MassiveObjectStore):
+ eids_seq_range = 1000
+ eids_seq_start = 50000
+
+ with self.admin_access.repo_cnx() as cnx:
+ store = MyMassiveObjectStore(cnx)
+ eid = store.prepare_insert_entity('Location', name=u'toto')
+ store.flush()
+ self.assertGreater(eid, 50000)
+
+ def test_eid_entity_2(self):
+ class MyMassiveObjectStore(MassiveObjectStore):
+ eids_seq_range = 1000
+ eids_seq_start = 50000
+
+ with self.admin_access.repo_cnx() as cnx:
+ store = MyMassiveObjectStore(cnx)
+ eid = store.prepare_insert_entity('Location', name=u'toto', eid=10000)
+ store.flush()
+ self.assertEqual(eid, 10000)
+
+ def test_on_commit_callback(self):
+ counter = itertools.count()
+ with self.admin_access.repo_cnx() as cnx:
+ store = MassiveObjectStore(cnx, on_commit_callback=lambda:next(counter))
+ store.prepare_insert_entity('Location', name=u'toto')
+ store.flush()
+ store.commit()
+ self.assertGreaterEqual(next(counter), 1)
+
+ def test_on_rollback_callback(self):
+ counter = itertools.count()
+ with self.admin_access.repo_cnx() as cnx:
+ store = MassiveObjectStore(cnx, on_rollback_callback=lambda *_: next(counter))
+ store.prepare_insert_entity('Location', nm='toto')
+ store.flush()
+ store.commit()
+ self.assertGreaterEqual(next(counter), 1)
+
+ def test_slave_mode_indexes(self):
+ with self.admin_access.repo_cnx() as cnx:
+ slave_store = MassiveObjectStore(cnx, slave_mode=True)
+ with self.admin_access.repo_cnx() as cnx:
+ crs = cnx.system_sql('SELECT indexname FROM pg_indexes')
+ indexes = [r[0] for r in crs.fetchall()]
+ self.assertIn('entities_pkey', indexes)
+ self.assertIn('unique_entities_extid_idx', indexes)
+ self.assertIn('owned_by_relation_p_key', indexes)
+ self.assertIn('owned_by_relation_to_idx', indexes)
+
+ def test_slave_mode_exception(self):
+ with self.admin_access.repo_cnx() as cnx:
+ master_store = MassiveObjectStore(cnx, slave_mode=False)
+ slave_store = MassiveObjectStore(cnx, slave_mode=True)
+ self.assertRaises(RuntimeError, slave_store.flush_meta_data)
+ self.assertRaises(RuntimeError, slave_store.finish)
+
+ def test_simple_insert(self):
+ with self.admin_access.repo_cnx() as cnx:
+ store = MassiveObjectStore(cnx)
+ self.push_geonames_data(self.datapath('geonames.csv'), store)
+ store.flush()
+ store.commit()
+ store.finish()
+ with self.admin_access.repo_cnx() as cnx:
+ rset = cnx.execute('Any X WHERE X is Location')
+ self.assertEqual(len(rset), 4000)
+ rset = cnx.execute('Any X WHERE X is Location, X timezone T')
+ self.assertEqual(len(rset), 4000)
+
+ def test_index_building(self):
+ with self.admin_access.repo_cnx() as cnx:
+ store = MassiveObjectStore(cnx)
+ self.push_geonames_data(self.datapath('geonames.csv'), store)
+ store.flush()
+
+ # Check index
+ crs = cnx.system_sql('SELECT indexname FROM pg_indexes')
+ indexes = [r[0] for r in crs.fetchall()]
+ self.assertNotIn('entities_pkey', indexes)
+ self.assertNotIn('unique_entities_extid_idx', indexes)
+ self.assertNotIn('owned_by_relation_p_key', indexes)
+ self.assertNotIn('owned_by_relation_to_idx', indexes)
+
+ # Cleanup -> index
+ store.finish()
+
+ # Check index again
+ crs = cnx.system_sql('SELECT indexname FROM pg_indexes')
+ indexes = [r[0] for r in crs.fetchall()]
+ self.assertIn('entities_pkey', indexes)
+ self.assertIn('unique_entities_extid_idx', indexes)
+ self.assertIn('owned_by_relation_p_key', indexes)
+ self.assertIn('owned_by_relation_to_idx', indexes)
+
+ def test_multiple_insert(self):
+ with self.admin_access.repo_cnx() as cnx:
+ store = MassiveObjectStore(cnx)
+ store.init_etype_table('TestLocation')
+ store.finish()
+ store = MassiveObjectStore(cnx)
+ store.init_etype_table('TestLocation')
+ store.finish()
+
+ def test_multiple_insert_relation(self):
+ with self.admin_access.repo_cnx() as cnx:
+ store = MassiveObjectStore(cnx)
+ store.init_relation_table('used_language')
+ store.finish()
+ store = MassiveObjectStore(cnx)
+ store.init_relation_table('used_language')
+ store.finish()
+
+
+if __name__ == '__main__':
+ from logilab.common.testlib import unittest_main
+ unittest_main()
--- a/dataimport/test/test_pgstore.py Wed Dec 09 18:42:13 2015 +0100
+++ b/dataimport/test/test_pgstore.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,9 +20,11 @@
import datetime as DT
+from six import PY2
from logilab.common.testlib import TestCase, unittest_main
from cubicweb.dataimport import pgstore
+from cubicweb.devtools import testlib
class CreateCopyFromBufferTC(TestCase):
@@ -31,24 +33,24 @@
def test_convert_none(self):
cnvt = pgstore._copyfrom_buffer_convert_None
- self.assertEqual('NULL', cnvt(None))
+ self.assertEqual(u'NULL', cnvt(None))
def test_convert_number(self):
cnvt = pgstore._copyfrom_buffer_convert_number
- self.assertEqual('42', cnvt(42))
- self.assertEqual('42', cnvt(42L))
- self.assertEqual('42.42', cnvt(42.42))
+ self.assertEqual(u'42', cnvt(42))
+ if PY2:
+ self.assertEqual(u'42', cnvt(long(42)))
+ self.assertEqual(u'42.42', cnvt(42.42))
def test_convert_string(self):
cnvt = pgstore._copyfrom_buffer_convert_string
# simple
- self.assertEqual('babar', cnvt('babar'))
+ self.assertEqual(u'babar', cnvt('babar'))
# unicode
- self.assertEqual('\xc3\xa9l\xc3\xa9phant', cnvt(u'éléphant'))
- self.assertEqual('\xe9l\xe9phant', cnvt(u'éléphant', encoding='latin1'))
+ self.assertEqual(u'éléphant', cnvt(u'éléphant'))
# escaping
- self.assertEqual('babar\\tceleste\\n', cnvt('babar\tceleste\n'))
- self.assertEqual(r'C:\\new\tC:\\test', cnvt('C:\\new\tC:\\test'))
+ self.assertEqual(u'babar\\tceleste\\n', cnvt(u'babar\tceleste\n'))
+ self.assertEqual(u'C:\\\\new\\tC:\\\\test', cnvt(u'C:\\new\tC:\\test'))
def test_convert_date(self):
cnvt = pgstore._copyfrom_buffer_convert_date
@@ -64,18 +66,19 @@
# test buffer
def test_create_copyfrom_buffer_tuple(self):
- data = ((42, 42L, 42.42, u'éléphant', DT.date(666, 1, 13), DT.time(6, 6, 6),
+ l = long if PY2 else int
+ data = ((42, l(42), 42.42, u'éléphant', DT.date(666, 1, 13), DT.time(6, 6, 6),
DT.datetime(666, 6, 13, 6, 6, 6)),
- (6, 6L, 6.6, u'babar', DT.date(2014, 1, 14), DT.time(4, 2, 1),
+ (6, l(6), 6.6, u'babar', DT.date(2014, 1, 14), DT.time(4, 2, 1),
DT.datetime(2014, 1, 1, 0, 0, 0)))
results = pgstore._create_copyfrom_buffer(data)
# all columns
- expected = '''42\t42\t42.42\téléphant\t0666-01-13\t06:06:06.000000\t0666-06-13 06:06:06.000000
+ expected = u'''42\t42\t42.42\téléphant\t0666-01-13\t06:06:06.000000\t0666-06-13 06:06:06.000000
6\t6\t6.6\tbabar\t2014-01-14\t04:02:01.000000\t2014-01-01 00:00:00.000000'''
self.assertMultiLineEqual(expected, results.getvalue())
# selected columns
results = pgstore._create_copyfrom_buffer(data, columns=(1, 3, 6))
- expected = '''42\téléphant\t0666-06-13 06:06:06.000000
+ expected = u'''42\téléphant\t0666-06-13 06:06:06.000000
6\tbabar\t2014-01-01 00:00:00.000000'''
self.assertMultiLineEqual(expected, results.getvalue())
@@ -85,8 +88,19 @@
dict(integer=6, double=6.6, text=u'babar',
date=DT.datetime(2014, 1, 1, 0, 0, 0)))
results = pgstore._create_copyfrom_buffer(data, ('integer', 'text'))
- expected = '''42\téléphant\n6\tbabar'''
- self.assertMultiLineEqual(expected, results.getvalue())
+ expected = u'''42\téléphant\n6\tbabar'''
+ self.assertEqual(expected, results.getvalue())
+
+
+class SQLGenObjectStoreTC(testlib.CubicWebTC):
+
+ def test_prepare_insert_entity(self):
+ with self.admin_access.repo_cnx() as cnx:
+ store = pgstore.SQLGenObjectStore(cnx)
+ eid = store.prepare_insert_entity('CWUser', login=u'toto',
+ upassword=u'pwd')
+ self.assertIsNotNone(eid)
+
if __name__ == '__main__':
unittest_main()
--- a/dataimport/test/unittest_importer.py Wed Dec 09 18:42:13 2015 +0100
+++ b/dataimport/test/unittest_importer.py Thu Dec 10 12:34:15 2015 +0100
@@ -152,14 +152,14 @@
class UseExtidAsCwuriTC(TestCase):
def test(self):
- personne = ExtEntity('Personne', 1, {'nom': set([u'de la lune']),
- 'prenom': set([u'Jean'])})
+ personne = ExtEntity('Personne', b'1', {'nom': set([u'de la lune']),
+ 'prenom': set([u'Jean'])})
mapping = {}
set_cwuri = use_extid_as_cwuri(mapping)
list(set_cwuri((personne,)))
self.assertIn('cwuri', personne.values)
- self.assertEqual(personne.values['cwuri'], set(['1']))
- mapping[1] = 'whatever'
+ self.assertEqual(personne.values['cwuri'], set([u'1']))
+ mapping[b'1'] = 'whatever'
personne.values.pop('cwuri')
list(set_cwuri((personne,)))
self.assertNotIn('cwuri', personne.values)
@@ -167,7 +167,7 @@
def extentities_from_csv(fpath):
"""Yield ExtEntity read from `fpath` CSV file."""
- with open(fpath) as f:
+ with open(fpath, 'rb') as f:
for uri, name, knows in ucsvreader(f, skipfirst=True, skip_empty=False):
yield ExtEntity('Personne', uri,
{'nom': set([name]), 'connait': set([knows])})
--- a/debian/control Wed Dec 09 18:42:13 2015 +0100
+++ b/debian/control Thu Dec 10 12:34:15 2015 +0100
@@ -10,13 +10,14 @@
Build-Depends:
debhelper (>= 7),
python (>= 2.6),
+ python-six (>= 1.4.0),
python-sphinx,
python-logilab-common,
python-unittest2 | python (>= 2.7),
python-logilab-mtconverter,
python-markdown,
python-rql,
- python-yams (>= 0.40.0),
+ python-yams (>= 0.41.1),
python-lxml,
Standards-Version: 3.9.1
Homepage: http://www.cubicweb.org
@@ -155,10 +156,11 @@
${python:Depends},
graphviz,
gettext,
+ python-six (>= 1.4.0),
python-logilab-mtconverter (>= 0.8.0),
python-logilab-common (>= 0.63.1),
python-markdown,
- python-yams (>= 0.40.0),
+ python-yams (>= 0.41.1)
python-rql (>= 0.31.2),
python-lxml
Recommends:
--- a/devtools/__init__.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/__init__.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""Test tools for cubicweb"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
@@ -24,7 +25,6 @@
import errno
import logging
import shutil
-import pickle
import glob
import subprocess
import warnings
@@ -35,6 +35,9 @@
from os.path import (abspath, realpath, join, exists, split, isabs, isdir)
from functools import partial
+from six import text_type
+from six.moves import cPickle as pickle
+
from logilab.common.date import strptime
from logilab.common.decorators import cached, clear_cache
@@ -92,7 +95,7 @@
DEFAULT_PSQL_SOURCES = DEFAULT_SOURCES.copy()
DEFAULT_PSQL_SOURCES['system'] = DEFAULT_SOURCES['system'].copy()
DEFAULT_PSQL_SOURCES['system']['db-driver'] = 'postgres'
-DEFAULT_PSQL_SOURCES['system']['db-user'] = unicode(getpass.getuser())
+DEFAULT_PSQL_SOURCES['system']['db-user'] = text_type(getpass.getuser())
DEFAULT_PSQL_SOURCES['system']['db-password'] = None
def turn_repo_off(repo):
@@ -109,7 +112,7 @@
try:
repo.close(sessionid)
except BadConnectionId: #this is strange ? thread issue ?
- print 'XXX unknown session', sessionid
+ print('XXX unknown session', sessionid)
for cnxset in repo.cnxsets:
cnxset.close(True)
repo.system_source.shutdown()
@@ -162,7 +165,7 @@
return None, None
return self.anonymous_credential
- def set_anonymous_allowed(self, allowed, anonuser='anon'):
+ def set_anonymous_allowed(self, allowed, anonuser=u'anon'):
if allowed:
self.anonymous_credential = (anonuser, anonuser)
else:
@@ -193,7 +196,7 @@
def sources_file(self):
"""define in subclasses self.sourcefile if necessary"""
if self.sourcefile:
- print 'Reading sources from', self.sourcefile
+ print('Reading sources from', self.sourcefile)
sourcefile = self.sourcefile
if not isabs(sourcefile):
sourcefile = join(self.apphome, sourcefile)
@@ -367,7 +370,8 @@
# XXX set a clearer error message ???
backup_coordinates, config_path = self.db_cache[self.db_cache_key(db_id)]
# reload the config used to create the database.
- config = pickle.loads(open(config_path, 'rb').read())
+ with open(config_path, 'rb') as f:
+ config = pickle.load(f)
# shutdown repo before changing database content
if self._repo is not None:
self._repo.turn_repo_off()
@@ -399,9 +403,8 @@
def _new_repo(self, config):
"""Factory method to create a new Repository Instance"""
- from cubicweb.repoapi import _get_inmemory_repo
config._cubes = None
- repo = _get_inmemory_repo(config)
+ repo = config.repository()
config.repository = lambda x=None: repo
# extending Repository class
repo._has_started = False
@@ -415,7 +418,7 @@
from cubicweb.repoapi import connect
repo = self.get_repo()
sources = self.config.read_sources_file()
- login = unicode(sources['admin']['login'])
+ login = text_type(sources['admin']['login'])
password = sources['admin']['password'] or 'xxx'
cnx = connect(repo, login, password=password)
return cnx
@@ -464,7 +467,7 @@
dbname, data = data.split('-', 1)
db_id, filetype = data.split('.', 1)
entries.setdefault((dbname, db_id), {})[filetype] = filepath
- for (dbname, db_id), entry in entries.iteritems():
+ for (dbname, db_id), entry in entries.items():
# apply necessary transformation from the driver
value = self.process_cache_entry(directory, dbname, db_id, entry)
assert 'config' in entry
@@ -494,7 +497,7 @@
if test_db_id is DEFAULT_EMPTY_DB_ID:
self.init_test_database()
else:
- print 'Building %s for database %s' % (test_db_id, self.dbname)
+ print('Building %s for database %s' % (test_db_id, self.dbname))
self.build_db_cache(DEFAULT_EMPTY_DB_ID)
self.restore_database(DEFAULT_EMPTY_DB_ID)
repo = self.get_repo(startup=True)
@@ -543,7 +546,7 @@
try:
subprocess.check_call(['initdb', '-D', datadir, '-E', 'utf-8', '--locale=C'])
- except OSError, err:
+ except OSError as err:
if err.errno == errno.ENOENT:
raise OSError('"initdb" could not be found. '
'You should add the postgresql bin folder to your PATH '
@@ -562,7 +565,11 @@
subprocess.check_call(['pg_ctl', 'start', '-w', '-D', datadir,
'-o', options],
env=env)
- except OSError, err:
+ except OSError as err:
+ try:
+ os.rmdir(sockdir)
+ except OSError:
+ pass
if err.errno == errno.ENOENT:
raise OSError('"pg_ctl" could not be found. '
'You should add the postgresql bin folder to your PATH '
@@ -575,6 +582,10 @@
datadir = join(os.path.dirname(pyfile), 'data',
'pgdb-%s' % os.path.splitext(os.path.basename(pyfile))[0])
subprocess.call(['pg_ctl', 'stop', '-D', datadir, '-m', 'fast'])
+ try:
+ os.rmdir(DEFAULT_PSQL_SOURCES['system']['db-host'])
+ except OSError:
+ pass
class PostgresTestDataBaseHandler(TestDataBaseHandler):
@@ -678,7 +689,7 @@
@property
def _config_id(self):
- return sha1(self.config.apphome).hexdigest()[:10]
+ return sha1(self.config.apphome.encode('utf-8')).hexdigest()[:10]
def _backup_name(self, db_id): # merge me with parent
backup_name = '_'.join(('cache', self._config_id, self.dbname, db_id))
@@ -834,21 +845,21 @@
found_date = False
for row, rowdesc in zip(rset, rset.description):
for cellindex, (value, vtype) in enumerate(zip(row, rowdesc)):
- if vtype in ('Date', 'Datetime') and type(value) is unicode:
+ if vtype in ('Date', 'Datetime') and isinstance(value, text_type):
found_date = True
value = value.rsplit('.', 1)[0]
try:
row[cellindex] = strptime(value, '%Y-%m-%d %H:%M:%S')
except Exception:
row[cellindex] = strptime(value, '%Y-%m-%d')
- if vtype == 'Time' and type(value) is unicode:
+ if vtype == 'Time' and isinstance(value, text_type):
found_date = True
try:
row[cellindex] = strptime(value, '%H:%M:%S')
except Exception:
# DateTime used as Time?
row[cellindex] = strptime(value, '%Y-%m-%d %H:%M:%S')
- if vtype == 'Interval' and type(value) is int:
+ if vtype == 'Interval' and isinstance(value, int):
found_date = True
row[cellindex] = timedelta(0, value, 0) # XXX value is in number of seconds?
if not found_date:
@@ -882,7 +893,7 @@
We only keep one repo in cache to prevent too much objects to stay alive
(database handler holds a reference to a repository). As at the moment a new
handler is created for each TestCase class and all test methods are executed
- sequentialy whithin this class, there should not have more cache miss that
+ sequentially whithin this class, there should not have more cache miss that
if we had a wider cache as once a Handler stop being used it won't be used
again.
"""
@@ -947,5 +958,3 @@
handler = get_test_db_handler(config)
handler.build_db_cache()
return handler.get_repo_and_cnx()
-
-
--- a/devtools/devctl.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/devctl.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,6 +18,7 @@
"""additional cubicweb-ctl commands and command handlers for cubicweb and
cubicweb's cubes development
"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
@@ -83,7 +84,7 @@
def cleanup_sys_modules(config):
# cleanup sys.modules, required when we're updating multiple cubes
- for name, mod in sys.modules.items():
+ for name, mod in list(sys.modules.items()):
if mod is None:
# duh ? logilab.common.os for instance
del sys.modules[name]
@@ -250,7 +251,7 @@
# bw compat, necessary until all translation of relation are
# done properly...
add_msg(w, '%s_object' % rtype)
- for rdef in rschema.rdefs.itervalues():
+ for rdef in rschema.rdefs.values():
if not rdef.description or rdef.description in done:
continue
if (librschema is None or
@@ -267,7 +268,7 @@
for reg, objdict in vreg.items():
if reg in ('boxes', 'contentnavigation'):
continue
- for objects in objdict.itervalues():
+ for objects in objdict.values():
for obj in objects:
objid = '%s_%s' % (reg, obj.__regid__)
if objid in done:
@@ -314,21 +315,21 @@
from cubicweb.i18n import extract_from_tal, execute2
tempdir = tempfile.mkdtemp(prefix='cw-')
cwi18ndir = WebConfiguration.i18n_lib_dir()
- print '-> extract messages:',
- print 'schema',
+ print('-> extract messages:', end=' ')
+ print('schema', end=' ')
schemapot = osp.join(tempdir, 'schema.pot')
potfiles = [schemapot]
potfiles.append(schemapot)
# explicit close necessary else the file may not be yet flushed when
# we'll using it below
- schemapotstream = file(schemapot, 'w')
+ schemapotstream = open(schemapot, 'w')
generate_schema_pot(schemapotstream.write, cubedir=None)
schemapotstream.close()
- print 'TAL',
+ print('TAL', end=' ')
tali18nfile = osp.join(tempdir, 'tali18n.py')
extract_from_tal(find(osp.join(BASEDIR, 'web'), ('.py', '.pt')),
tali18nfile)
- print '-> generate .pot files.'
+ print('-> generate .pot files.')
pyfiles = get_module_files(BASEDIR)
pyfiles += globfind(osp.join(BASEDIR, 'misc', 'migration'), '*.py')
schemafiles = globfind(osp.join(BASEDIR, 'schemas'), '*.py')
@@ -349,12 +350,12 @@
if osp.exists(potfile):
potfiles.append(potfile)
else:
- print '-> WARNING: %s file was not generated' % potfile
- print '-> merging %i .pot files' % len(potfiles)
+ print('-> WARNING: %s file was not generated' % potfile)
+ print('-> merging %i .pot files' % len(potfiles))
cubicwebpot = osp.join(tempdir, 'cubicweb.pot')
cmd = ['msgcat', '-o', cubicwebpot] + potfiles
execute2(cmd)
- print '-> merging main pot file with existing translations.'
+ print('-> merging main pot file with existing translations.')
chdir(cwi18ndir)
toedit = []
for lang in CubicWebNoAppConfiguration.cw_languages():
@@ -368,10 +369,10 @@
# cleanup
rm(tempdir)
# instructions pour la suite
- print '-> regenerated CubicWeb\'s .po catalogs.'
- print '\nYou can now edit the following files:'
- print '* ' + '\n* '.join(toedit)
- print 'when you are done, run "cubicweb-ctl i18ncube yourcube".'
+ print('-> regenerated CubicWeb\'s .po catalogs.')
+ print('\nYou can now edit the following files:')
+ print('* ' + '\n* '.join(toedit))
+ print('when you are done, run "cubicweb-ctl i18ncube yourcube".')
class UpdateCubeCatalogCommand(Command):
@@ -398,25 +399,25 @@
from subprocess import CalledProcessError
for cubedir in cubes:
if not osp.isdir(cubedir):
- print '-> ignoring %s that is not a directory.' % cubedir
+ print('-> ignoring %s that is not a directory.' % cubedir)
continue
try:
toedit = update_cube_catalogs(cubedir)
except CalledProcessError as exc:
- print '\n*** error while updating catalogs for cube', cubedir
- print 'cmd:\n%s' % exc.cmd
- print 'stdout:\n%s\nstderr:\n%s' % exc.data
+ print('\n*** error while updating catalogs for cube', cubedir)
+ print('cmd:\n%s' % exc.cmd)
+ print('stdout:\n%s\nstderr:\n%s' % exc.data)
except Exception:
import traceback
traceback.print_exc()
- print '*** error while updating catalogs for cube', cubedir
+ print('*** error while updating catalogs for cube', cubedir)
return False
else:
# instructions pour la suite
if toedit:
- print '-> regenerated .po catalogs for cube %s.' % cubedir
- print '\nYou can now edit the following files:'
- print '* ' + '\n* '.join(toedit)
+ print('-> regenerated .po catalogs for cube %s.' % cubedir)
+ print('\nYou can now edit the following files:')
+ print('* ' + '\n* '.join(toedit))
print ('When you are done, run "cubicweb-ctl i18ninstance '
'<yourinstance>" to see changes in your instances.')
return True
@@ -429,7 +430,7 @@
from cubicweb.i18n import extract_from_tal, execute2
cube = osp.basename(osp.normpath(cubedir))
tempdir = tempfile.mkdtemp()
- print underline_title('Updating i18n catalogs for cube %s' % cube)
+ print(underline_title('Updating i18n catalogs for cube %s' % cube))
chdir(cubedir)
if osp.exists(osp.join('i18n', 'entities.pot')):
warn('entities.pot is deprecated, rename file to static-messages.pot (%s)'
@@ -439,20 +440,20 @@
potfiles = [osp.join('i18n', 'static-messages.pot')]
else:
potfiles = []
- print '-> extracting messages:',
- print 'schema',
+ print('-> extracting messages:', end=' ')
+ print('schema', end=' ')
schemapot = osp.join(tempdir, 'schema.pot')
potfiles.append(schemapot)
# explicit close necessary else the file may not be yet flushed when
# we'll using it below
- schemapotstream = file(schemapot, 'w')
+ schemapotstream = open(schemapot, 'w')
generate_schema_pot(schemapotstream.write, cubedir)
schemapotstream.close()
- print 'TAL',
+ print('TAL', end=' ')
tali18nfile = osp.join(tempdir, 'tali18n.py')
ptfiles = find('.', ('.py', '.pt'), blacklist=STD_BLACKLIST+('test',))
extract_from_tal(ptfiles, tali18nfile)
- print 'Javascript'
+ print('Javascript')
jsfiles = [jsfile for jsfile in find('.', '.js')
if osp.basename(jsfile).startswith('cub')]
if jsfiles:
@@ -463,7 +464,7 @@
# no pot file created if there are no string to translate
if osp.exists(tmppotfile):
potfiles.append(tmppotfile)
- print '-> creating cube-specific catalog'
+ print('-> creating cube-specific catalog')
tmppotfile = osp.join(tempdir, 'generated.pot')
cubefiles = find('.', '.py', blacklist=STD_BLACKLIST+('test',))
cubefiles.append(tali18nfile)
@@ -473,20 +474,20 @@
if osp.exists(tmppotfile): # doesn't exists of no translation string found
potfiles.append(tmppotfile)
potfile = osp.join(tempdir, 'cube.pot')
- print '-> merging %i .pot files' % len(potfiles)
+ print('-> merging %i .pot files' % len(potfiles))
cmd = ['msgcat', '-o', potfile]
cmd.extend(potfiles)
execute2(cmd)
if not osp.exists(potfile):
- print 'no message catalog for cube', cube, 'nothing to translate'
+ print('no message catalog for cube', cube, 'nothing to translate')
# cleanup
rm(tempdir)
return ()
- print '-> merging main pot file with existing translations:',
+ print('-> merging main pot file with existing translations:', end=' ')
chdir('i18n')
toedit = []
for lang in CubicWebNoAppConfiguration.cw_languages():
- print lang,
+ print(lang, end=' ')
cubepo = '%s.po' % lang
if not osp.exists(cubepo):
shutil.copy(potfile, cubepo)
@@ -496,7 +497,7 @@
ensure_fs_mode(cubepo)
shutil.move('%snew' % cubepo, cubepo)
toedit.append(osp.abspath(cubepo))
- print
+ print()
# cleanup
rm(tempdir)
return toedit
@@ -620,7 +621,7 @@
" Please specify it using the --directory option")
cubesdir = cubespath[0]
if not osp.isdir(cubesdir):
- print "-> creating cubes directory", cubesdir
+ print("-> creating cubes directory", cubesdir)
try:
mkdir(cubesdir)
except OSError as err:
@@ -649,7 +650,8 @@
if verbose:
longdesc = raw_input(
'Enter a long description (leave empty to reuse the short one): ')
- dependencies = {'cubicweb': '>= %s' % cubicwebversion}
+ dependencies = {'cubicweb': '>= %s' % cubicwebversion,
+ 'six': '>= 1.4.0',}
if verbose:
dependencies.update(self._ask_for_dependencies())
context = {'cubename' : cubename,
@@ -710,7 +712,7 @@
requests = {}
for filepath in args:
try:
- stream = file(filepath)
+ stream = open(filepath)
except OSError as ex:
raise BadCommandUsage("can't open rql log file %s: %s"
% (filepath, ex))
@@ -731,17 +733,17 @@
except Exception as exc:
sys.stderr.write('Line %s: %s (%s)\n' % (lineno, exc, line))
stat = []
- for rql, times in requests.iteritems():
+ for rql, times in requests.items():
stat.append( (sum(time[0] for time in times),
sum(time[1] for time in times),
len(times), rql) )
stat.sort()
stat.reverse()
total_time = sum(clocktime for clocktime, cputime, occ, rql in stat) * 0.01
- print 'Percentage;Cumulative Time (clock);Cumulative Time (CPU);Occurences;Query'
+ print('Percentage;Cumulative Time (clock);Cumulative Time (CPU);Occurences;Query')
for clocktime, cputime, occ, rql in stat:
- print '%.2f;%.2f;%.2f;%s;%s' % (clocktime/total_time, clocktime,
- cputime, occ, rql)
+ print('%.2f;%.2f;%.2f;%s;%s' % (clocktime/total_time, clocktime,
+ cputime, occ, rql))
class GenerateSchema(Command):
--- a/devtools/fake.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/fake.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,6 +22,8 @@
from contextlib import contextmanager
+from six import string_types
+
from logilab.database import get_db_helper
from cubicweb.req import RequestSessionBase
@@ -91,7 +93,7 @@
def set_request_header(self, header, value, raw=False):
"""set an incoming HTTP header (for test purpose only)"""
- if isinstance(value, basestring):
+ if isinstance(value, string_types):
value = [value]
if raw:
# adding encoded header is important, else page content
@@ -110,7 +112,7 @@
def build_url_params(self, **kwargs):
# overriden to get predictable resultts
args = []
- for param, values in sorted(kwargs.iteritems()):
+ for param, values in sorted(kwargs.items()):
if not isinstance(values, (list, tuple)):
values = (values,)
for value in values:
--- a/devtools/fill.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/fill.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,6 +17,7 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""This modules defines func / methods for creating test repositories"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
@@ -25,6 +26,10 @@
from copy import deepcopy
from datetime import datetime, date, time, timedelta
from decimal import Decimal
+import inspect
+
+from six import text_type, add_metaclass
+from six.moves import range
from logilab.common import attrdict
from logilab.mtconverter import xml_escape
@@ -173,7 +178,7 @@
generate_tztime = generate_time # XXX implementation should add a timezone
def generate_bytes(self, entity, attrname, index, format=None):
- fakefile = Binary("%s%s" % (attrname, index))
+ fakefile = Binary(("%s%s" % (attrname, index)).encode('ascii'))
fakefile.filename = u"file_%s" % attrname
return fakefile
@@ -224,7 +229,7 @@
"""
for cst in self.eschema.rdef(attrname).constraints:
if isinstance(cst, StaticVocabularyConstraint):
- return unicode(choice(cst.vocabulary()))
+ return text_type(choice(cst.vocabulary()))
return None
# XXX nothing to do here
@@ -254,13 +259,15 @@
for attrname, attrvalue in classdict.items():
if callable(attrvalue):
if attrname.startswith('generate_') and \
- attrvalue.func_code.co_argcount < 2:
+ len(inspect.getargspec(attrvalue).args) < 2:
raise TypeError('generate_xxx must accept at least 1 argument')
setattr(_ValueGenerator, attrname, attrvalue)
return type.__new__(mcs, name, bases, classdict)
+
+@add_metaclass(autoextend)
class ValueGenerator(_ValueGenerator):
- __metaclass__ = autoextend
+ pass
def _default_choice_func(etype, attrname):
@@ -286,7 +293,7 @@
returns acceptable values for this attribute
"""
queries = []
- for index in xrange(entity_num):
+ for index in range(entity_num):
restrictions = []
args = {}
for attrname, value in make_entity(etype, schema, vreg, index, choice_func).items():
@@ -347,7 +354,7 @@
fmt = vreg.property_value('ui.float-format')
value = fmt % value
else:
- value = unicode(value)
+ value = text_type(value)
return entity
@@ -363,7 +370,7 @@
rql += ', %s is %s' % (selectvar, objtype)
rset = cnx.execute(rql)
except Exception:
- print "could restrict eid_list with given constraints (%r)" % constraints
+ print("could restrict eid_list with given constraints (%r)" % constraints)
return []
return set(eid for eid, in rset.rows)
@@ -508,8 +515,8 @@
break
else:
# FIXME: 20 should be read from config
- subjeidsiter = [choice(tuple(subjeids)) for i in xrange(min(len(subjeids), 20))]
- objeidsiter = [choice(tuple(objeids)) for i in xrange(min(len(objeids), 20))]
+ subjeidsiter = [choice(tuple(subjeids)) for i in range(min(len(subjeids), 20))]
+ objeidsiter = [choice(tuple(objeids)) for i in range(min(len(objeids), 20))]
for subjeid, objeid in zip(subjeidsiter, objeidsiter):
if subjeid != objeid and not (subjeid, objeid) in used:
used.add( (subjeid, objeid) )
--- a/devtools/htmlparser.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/htmlparser.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,7 +20,7 @@
import re
import sys
from xml import sax
-from cStringIO import StringIO
+from io import BytesIO
from lxml import etree
@@ -33,7 +33,7 @@
ERR_COUNT = 0
-_REM_SCRIPT_RGX = re.compile(r"<script[^>]*>.*?</script>", re.U|re.M|re.I|re.S)
+_REM_SCRIPT_RGX = re.compile(br"<script[^>]*>.*?</script>", re.M|re.I|re.S)
def _remove_script_tags(data):
"""Remove the script (usually javascript) tags to help the lxml
XMLParser / HTMLParser do their job. Without that, they choke on
@@ -70,7 +70,7 @@
#
# using that, we'll miss most actual validation error we want to
# catch. For now, use dumb regexp
- return _REM_SCRIPT_RGX.sub('', data)
+ return _REM_SCRIPT_RGX.sub(b'', data)
class Validator(object):
@@ -164,10 +164,10 @@
def _parse(self, data):
inpsrc = sax.InputSource()
- inpsrc.setByteStream(StringIO(data))
+ inpsrc.setByteStream(BytesIO(data))
try:
self._parser.parse(inpsrc)
- except sax.SAXParseException, exc:
+ except sax.SAXParseException as exc:
new_exc = AssertionError(u'invalid document: %s' % exc)
new_exc.position = (exc._linenum, exc._colnum)
raise new_exc
@@ -209,7 +209,7 @@
def matching_nodes(self, tag, **attrs):
for elt in self.etree.iterfind(self._iterstr(tag)):
eltattrs = elt.attrib
- for attr, value in attrs.iteritems():
+ for attr, value in attrs.items():
try:
if eltattrs[attr] != value:
break
--- a/devtools/httptest.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/httptest.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,17 +18,18 @@
"""this module contains base classes and utilities for integration with running
http server
"""
+from __future__ import print_function
+
__docformat__ = "restructuredtext en"
import random
import threading
import socket
-import httplib
-from urlparse import urlparse
-from twisted.internet import reactor, error
+from six.moves import range, http_client
+from six.moves.urllib.parse import urlparse
-from cubicweb.etwist.server import run
+
from cubicweb.devtools.testlib import CubicWebTC
from cubicweb.devtools import ApptestConfiguration
@@ -89,6 +90,8 @@
configcls = CubicWebServerConfig
def start_server(self):
+ from twisted.internet import reactor
+ from cubicweb.etwist.server import run
# use a semaphore to avoid starting test while the http server isn't
# fully initilialized
semaphore = threading.Semaphore(0)
@@ -110,12 +113,13 @@
#pre init utils connection
parseurl = urlparse(self.config['base-url'])
assert parseurl.port == self.config['port'], (self.config['base-url'], self.config['port'])
- self._web_test_cnx = httplib.HTTPConnection(parseurl.hostname,
- parseurl.port)
+ self._web_test_cnx = http_client.HTTPConnection(parseurl.hostname,
+ parseurl.port)
self._ident_cookie = None
def stop_server(self, timeout=15):
"""Stop the webserver, waiting for the thread to return"""
+ from twisted.internet import reactor
if self._web_test_cnx is None:
self.web_logout()
self._web_test_cnx.close()
@@ -139,7 +143,7 @@
passwd = user
response = self.web_get("login?__login=%s&__password=%s" %
(user, passwd))
- assert response.status == httplib.SEE_OTHER, response.status
+ assert response.status == http_client.SEE_OTHER, response.status
self._ident_cookie = response.getheader('Set-Cookie')
assert self._ident_cookie
return True
@@ -151,7 +155,7 @@
self._ident_cookie = None
def web_request(self, path='', method='GET', body=None, headers=None):
- """Return an httplib.HTTPResponse object for the specified path
+ """Return an http_client.HTTPResponse object for the specified path
Use available credential if available.
"""
@@ -174,9 +178,10 @@
self.start_server()
def tearDown(self):
+ from twisted.internet import error
try:
self.stop_server()
except error.ReactorNotRunning as err:
# Server could be launched manually
- print err
+ print(err)
super(CubicWebServerTC, self).tearDown()
--- a/devtools/instrument.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/instrument.py Thu Dec 10 12:34:15 2015 +0100
@@ -14,6 +14,7 @@
# You should have received a copy of the GNU Lesser General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
"""Instrumentation utilities"""
+from __future__ import print_function
import os
@@ -45,10 +46,10 @@
return _COLORS[key]
def warn(msg, *args):
- print 'WARNING: %s' % (msg % args)
+ print('WARNING: %s' % (msg % args))
def info(msg):
- print 'INFO: ' + msg
+ print('INFO: ' + msg)
class PropagationAnalyzer(object):
@@ -185,7 +186,7 @@
def add_colors_legend(self, graph):
"""Add a legend of used colors to the graph."""
- for package, color in sorted(_COLORS.iteritems()):
+ for package, color in sorted(_COLORS.items()):
graph.add_node(package, color=color, fontcolor=color, shape='record')
--- a/devtools/qunit.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/qunit.py Thu Dec 10 12:34:15 2015 +0100
@@ -15,53 +15,28 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+from __future__ import absolute_import
import os, os.path as osp
-from tempfile import mkdtemp, NamedTemporaryFile, TemporaryFile
-import tempfile
-from Queue import Queue, Empty
-from subprocess import Popen, check_call, CalledProcessError
-from shutil import rmtree, copy as copyfile
-from uuid import uuid4
+import errno
+from tempfile import mkdtemp
+from subprocess import Popen, PIPE, STDOUT
+
+from six.moves.queue import Queue, Empty
# imported by default to simplify further import statements
from logilab.common.testlib import unittest_main, with_tempdir, InnerTest, Tags
-from logilab.common.shellutils import getlogin
+import webtest.http
import cubicweb
from cubicweb.view import View
from cubicweb.web.controller import Controller
from cubicweb.web.views.staticcontrollers import StaticFileController, STATIC_CONTROLLERS
-from cubicweb.devtools.httptest import CubicWebServerTC
-
-
-class VerboseCalledProcessError(CalledProcessError):
-
- def __init__(self, returncode, command, stdout, stderr):
- super(VerboseCalledProcessError, self).__init__(returncode, command)
- self.stdout = stdout
- self.stderr = stderr
-
- def __str__(self):
- str = [ super(VerboseCalledProcessError, self).__str__()]
- if self.stdout.strip():
- str.append('******************')
- str.append('* process stdout *')
- str.append('******************')
- str.append(self.stdout)
- if self.stderr.strip():
- str.append('******************')
- str.append('* process stderr *')
- str.append('******************')
- str.append(self.stderr)
- return '\n'.join(str)
-
+from cubicweb.devtools import webtest as cwwebtest
class FirefoxHelper(object):
- profile_name_mask = 'PYTEST_PROFILE_%(uid)s'
-
def __init__(self, url=None):
self._process = None
self._profile_dir = mkdtemp(prefix='cwtest-ffxprof-')
@@ -70,6 +45,17 @@
self.firefox_cmd = [osp.join(osp.dirname(__file__), 'data', 'xvfb-run.sh'),
'-a', '-s', '-noreset -screen 0 800x600x24'] + self.firefox_cmd
+ def test(self):
+ try:
+ proc = Popen(['firefox', '--help'], stdout=PIPE, stderr=STDOUT)
+ stdout, _ = proc.communicate()
+ return proc.returncode == 0, stdout
+ except OSError as exc:
+ if exc.errno == errno.ENOENT:
+ msg = '[%s] %s' % (errno.errorcode[exc.errno], exc.strerror)
+ return False, msg
+ raise
+
def start(self, url):
self.stop()
cmd = self.firefox_cmd + ['-silent', '--profile', self._profile_dir,
@@ -88,60 +74,46 @@
self.stop()
-class QUnitTestCase(CubicWebServerTC):
+class QUnitTestCase(cwwebtest.CubicWebTestTC):
- tags = CubicWebServerTC.tags | Tags(('qunit',))
+ tags = cwwebtest.CubicWebTestTC.tags | Tags(('qunit',))
# testfile, (dep_a, dep_b)
all_js_tests = ()
def setUp(self):
- self.config.global_set_option('access-control-allow-origin', '*')
super(QUnitTestCase, self).setUp()
self.test_queue = Queue()
class MyQUnitResultController(QUnitResultController):
tc = self
test_queue = self.test_queue
self._qunit_controller = MyQUnitResultController
- self.vreg.register(MyQUnitResultController)
- self.vreg.register(QUnitView)
- self.vreg.register(CWSoftwareRootStaticController)
+ self.webapp.app.appli.vreg.register(MyQUnitResultController)
+ self.webapp.app.appli.vreg.register(QUnitView)
+ self.webapp.app.appli.vreg.register(CWDevtoolsStaticController)
+ self.server = webtest.http.StopableWSGIServer.create(self.webapp.app)
+ self.config.global_set_option('base-url', self.server.application_url)
def tearDown(self):
+ self.server.shutdown()
+ self.webapp.app.appli.vreg.unregister(self._qunit_controller)
+ self.webapp.app.appli.vreg.unregister(QUnitView)
+ self.webapp.app.appli.vreg.unregister(CWDevtoolsStaticController)
super(QUnitTestCase, self).tearDown()
- self.vreg.unregister(self._qunit_controller)
- self.vreg.unregister(QUnitView)
- self.vreg.unregister(CWSoftwareRootStaticController)
-
- def abspath(self, path):
- """use self.__module__ to build absolute path if necessary"""
- if not osp.isabs(path):
- dirname = osp.dirname(__import__(self.__module__).__file__)
- return osp.abspath(osp.join(dirname,path))
- return path
def test_javascripts(self):
for args in self.all_js_tests:
- test_file = self.abspath(args[0])
+ self.assertIn(len(args), (1, 2))
+ test_file = args[0]
if len(args) > 1:
- depends = [self.abspath(dep) for dep in args[1]]
+ depends = args[1]
else:
depends = ()
- if len(args) > 2:
- data = [self.abspath(data) for data in args[2]]
- else:
- data = ()
- for js_test in self._test_qunit(test_file, depends, data):
+ for js_test in self._test_qunit(test_file, depends):
yield js_test
@with_tempdir
- def _test_qunit(self, test_file, depends=(), data_files=(), timeout=10):
- assert osp.exists(test_file), test_file
- for dep in depends:
- assert osp.exists(dep), dep
- for data in data_files:
- assert osp.exists(data), data
-
+ def _test_qunit(self, test_file, depends=(), timeout=10):
QUnitView.test_file = test_file
QUnitView.depends = depends
@@ -149,6 +121,9 @@
self.test_queue.get(False)
browser = FirefoxHelper()
+ isavailable, reason = browser.test()
+ if not isavailable:
+ self.fail('firefox not available or not working properly (%s)' % reason)
browser.start(self.config['base-url'] + "?vid=qunit")
test_count = 0
error = False
@@ -188,6 +163,7 @@
def publish(self, rset=None):
event = self._cw.form['event']
getattr(self, 'handle_%s' % event)()
+ return b''
def handle_module_start(self):
self.__class__._current_module_name = self._cw.form.get('name', '')
@@ -234,20 +210,15 @@
def call(self, **kwargs):
w = self.w
req = self._cw
- data = {
- 'jquery': req.data_url('jquery.js'),
- 'web_test': req.build_url('cwsoftwareroot/devtools/data'),
- }
w(u'''<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="application/html; charset=UTF-8"/>
<!-- JS lib used as testing framework -->
- <link rel="stylesheet" type="text/css" media="all" href="%(web_test)s/qunit.css" />
- <script src="%(jquery)s" type="text/javascript"></script>
- <script src="%(web_test)s/cwmock.js" type="text/javascript"></script>
- <script src="%(web_test)s/qunit.js" type="text/javascript"></script>'''
- % data)
+ <link rel="stylesheet" type="text/css" media="all" href="/devtools/qunit.css" />
+ <script src="/data/jquery.js" type="text/javascript"></script>
+ <script src="/devtools/cwmock.js" type="text/javascript"></script>
+ <script src="/devtools/qunit.js" type="text/javascript"></script>''')
w(u'<!-- result report tools -->')
w(u'<script type="text/javascript">')
w(u"var BASE_URL = '%s';" % req.base_url())
@@ -293,14 +264,11 @@
w(u'</script>')
w(u'<!-- Test script dependencies (tested code for example) -->')
- prefix = len(cubicweb.CW_SOFTWARE_ROOT) + 1
for dep in self.depends:
- dep = req.build_url('cwsoftwareroot/') + dep[prefix:]
- w(u' <script src="%s" type="text/javascript"></script>' % dep)
+ w(u' <script src="%s" type="text/javascript"></script>\n' % dep)
w(u' <!-- Test script itself -->')
- test_url = req.build_url('cwsoftwareroot/') + self.test_file[prefix:]
- w(u' <script src="%s" type="text/javascript"></script>' % test_url)
+ w(u' <script src="%s" type="text/javascript"></script>' % self.test_file)
w(u''' </head>
<body>
<div id="qunit-fixture"></div>
@@ -309,16 +277,16 @@
</html>''')
-class CWSoftwareRootStaticController(StaticFileController):
- __regid__ = 'cwsoftwareroot'
+class CWDevtoolsStaticController(StaticFileController):
+ __regid__ = 'devtools'
def publish(self, rset=None):
- staticdir = cubicweb.CW_SOFTWARE_ROOT
+ staticdir = osp.join(osp.dirname(__file__), 'data')
relpath = self.relpath[len(self.__regid__) + 1:]
return self.static_file(osp.join(staticdir, relpath))
-STATIC_CONTROLLERS.append(CWSoftwareRootStaticController)
+STATIC_CONTROLLERS.append(CWDevtoolsStaticController)
if __name__ == '__main__':
--- a/devtools/repotest.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/repotest.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,6 +19,7 @@
This module contains functions to initialize a new repository.
"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
@@ -29,10 +30,9 @@
def tuplify(mylist):
return [tuple(item) for item in mylist]
-def snippet_cmp(a, b):
- a = (a[0], [e.expression for e in a[1]])
- b = (b[0], [e.expression for e in b[1]])
- return cmp(a, b)
+def snippet_key(a):
+ # a[0] may be a dict or a key/value tuple
+ return (sorted(dict(a[0]).items()), [e.expression for e in a[1]])
def test_plan(self, rql, expected, kwargs=None):
with self.session.new_cnx() as cnx:
@@ -57,7 +57,7 @@
'expected %s queries, got %s' % (len(equeries), len(queries)))
for i, (rql, sol) in enumerate(queries):
self.assertEqual(rql, equeries[i][0])
- self.assertEqual(sorted(sol), sorted(equeries[i][1]))
+ self.assertEqual(sorted(sorted(x.items()) for x in sol), sorted(sorted(x.items()) for x in equeries[i][1]))
idx = 2
else:
idx = 1
@@ -66,7 +66,7 @@
self.assertEqual(len(step[-1]), len(expected[-1]),
'got %s child steps, expected %s' % (len(step[-1]), len(expected[-1])))
except AssertionError:
- print 'error on step ',
+ print('error on step ', end=' ')
pprint(step[:-1])
raise
children = step[-1]
@@ -115,7 +115,7 @@
schema_eids[x] = x.eid
for x in schema.relations():
schema_eids[x] = x.eid
- for rdef in x.rdefs.itervalues():
+ for rdef in x.rdefs.values():
schema_eids[(rdef.subject, rdef.rtype, rdef.object)] = rdef.eid
return schema_eids
@@ -127,7 +127,7 @@
for x in schema.relations():
x.eid = schema_eids[x]
schema._eid_index[x.eid] = x
- for rdef in x.rdefs.itervalues():
+ for rdef in x.rdefs.values():
rdef.eid = schema_eids[(rdef.subject, rdef.rtype, rdef.object)]
schema._eid_index[rdef.eid] = rdef
@@ -187,7 +187,7 @@
plan = self.qhelper.plan_factory(union, {}, FakeSession(self.repo))
plan.preprocess(union)
for select in union.children:
- select.solutions.sort()
+ select.solutions.sort(key=lambda x: list(x.items()))
#print '********* ppsolutions', solutions
return union
@@ -197,7 +197,7 @@
def setUp(self):
self.o = self.repo.querier
- self.session = self.repo._sessions.values()[0]
+ self.session = next(iter(self.repo._sessions.values()))
self.ueid = self.session.user.eid
assert self.ueid != -1
self.repo._type_source_cache = {} # clear cache
@@ -238,7 +238,7 @@
if simplify:
rqlhelper.simplify(rqlst)
for select in rqlst.children:
- select.solutions.sort()
+ select.solutions.sort(key=lambda x: list(x.items()))
return self.o.plan_factory(rqlst, kwargs, cnx)
def _prepare(self, cnx, rql, kwargs=None):
@@ -286,13 +286,13 @@
if rqlst.TYPE == 'select':
self.repo.vreg.rqlhelper.annotate(rqlst)
for select in rqlst.children:
- select.solutions.sort()
+ select.solutions.sort(key=lambda x: list(x.items()))
else:
- rqlst.solutions.sort()
+ rqlst.solutions.sort(key=lambda x: list(x.items()))
return self.o.plan_factory(rqlst, kwargs, cnx)
-# monkey patch some methods to get predicatable results #######################
+# monkey patch some methods to get predictable results #######################
from cubicweb import rqlrewrite
_orig_iter_relations = rqlrewrite.iter_relations
@@ -300,16 +300,15 @@
_orig_build_variantes = rqlrewrite.RQLRewriter.build_variantes
def _insert_snippets(self, snippets, varexistsmap=None):
- _orig_insert_snippets(self, sorted(snippets, snippet_cmp), varexistsmap)
+ _orig_insert_snippets(self, sorted(snippets, key=snippet_key), varexistsmap)
def _build_variantes(self, newsolutions):
variantes = _orig_build_variantes(self, newsolutions)
sortedvariantes = []
for variante in variantes:
- orderedkeys = sorted((k[1], k[2], v) for k, v in variante.iteritems())
- variante = DumbOrderedDict(sorted(variante.iteritems(),
- lambda a, b: cmp((a[0][1],a[0][2],a[1]),
- (b[0][1],b[0][2],b[1]))))
+ orderedkeys = sorted((k[1], k[2], v) for k, v in variante.items())
+ variante = DumbOrderedDict(sorted(variante.items(),
+ key=lambda a: (a[0][1], a[0][2], a[1])))
sortedvariantes.append( (orderedkeys, variante) )
return [v for ok, v in sorted(sortedvariantes)]
@@ -318,7 +317,7 @@
def _check_permissions(*args, **kwargs):
res, restricted = _orig_check_permissions(*args, **kwargs)
- res = DumbOrderedDict(sorted(res.iteritems(), lambda a, b: cmp(a[1], b[1])))
+ res = DumbOrderedDict(sorted(res.items(), key=lambda x: [y.items() for y in x[1]]))
return res, restricted
def _dummy_check_permissions(self, rqlst):
--- a/devtools/stresstester.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/stresstester.py Thu Dec 10 12:34:15 2015 +0100
@@ -41,6 +41,7 @@
Copyright (c) 2003-2011 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
+from __future__ import print_function
import os
import sys
@@ -84,7 +85,7 @@
def usage(status=0):
"""print usage string and exit"""
- print __doc__ % basename(sys.argv[0])
+ print(__doc__ % basename(sys.argv[0]))
sys.exit(status)
@@ -133,7 +134,7 @@
'nb-times=', 'nb-threads=',
'profile', 'report-output=',])
except Exception as ex:
- print ex
+ print(ex)
usage(1)
repeat = 100
threads = 1
@@ -155,7 +156,7 @@
elif opt in ('-P', '--profile'):
prof_file = val
elif opt in ('-o', '--report-output'):
- report_output = file(val, 'w')
+ report_output = open(val, 'w')
if len(args) != 2:
usage(1)
queries = [query for query in lines(args[1]) if not query.startswith('#')]
@@ -166,7 +167,7 @@
from cubicweb.cwconfig import instance_configuration
config = instance_configuration(args[0])
# get local access to the repository
- print "Creating repo", prof_file
+ print("Creating repo", prof_file)
repo = Repository(config, prof_file)
cnxid = repo.connect(user, password=password)
# connection to the CubicWeb repository
--- a/devtools/test/data/js_examples/dep_1.js Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-a = 4;
--- a/devtools/test/data/js_examples/deps_2.js Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-b = a +2;
--- a/devtools/test/data/js_examples/test_simple_failure.js Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-$(document).ready(function() {
-
- QUnit.module("air");
-
- QUnit.test("test 1", function (assert) {
- assert.equal(2, 4);
- });
-
- QUnit.test("test 2", function (assert) {
- assert.equal('', '45');
- assert.equal('1024', '32');
- });
-
- QUnit.module("able");
- QUnit.test("test 3", function (assert) {
- assert.deepEqual(1, 1);
- });
-});
--- a/devtools/test/data/js_examples/test_simple_success.js Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-$(document).ready(function() {
-
- QUnit.module("air");
-
- QUnit.test("test 1", function (assert) {
- assert.equal(2, 2);
- });
-
- QUnit.test("test 2", function (assert) {
- assert.equal('45', '45');
- });
-
- QUnit.module("able");
- QUnit.test("test 3", function (assert) {
- assert.deepEqual(1, 1);
- });
-});
--- a/devtools/test/data/js_examples/test_with_dep.js Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-$(document).ready(function() {
-
- QUnit.module("air");
-
- QUnit.test("test 1", function (assert) {
- assert.equal(a, 4);
- });
-
-});
--- a/devtools/test/data/js_examples/test_with_ordered_deps.js Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-$(document).ready(function() {
-
- QUnit.module("air");
-
- QUnit.test("test 1", function (assert) {
- assert.equal(b, 6);
- });
-
-});
--- a/devtools/test/data/js_examples/utils.js Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-function datetuple(d) {
- return [d.getFullYear(), d.getMonth()+1, d.getDate(),
- d.getHours(), d.getMinutes()];
-}
-
-function pprint(obj) {
- print('{');
- for(k in obj) {
- print(' ' + k + ' = ' + obj[k]);
- }
- print('}');
-}
-
-function arrayrepr(array) {
- return '[' + array.join(', ') + ']';
-}
-
-function assertArrayEquals(array1, array2) {
- if (array1.length != array2.length) {
- throw new crosscheck.AssertionFailure(array1.join(', ') + ' != ' + array2.join(', '));
- }
- for (var i=0; i<array1.length; i++) {
- if (array1[i] != array2[i]) {
-
- throw new crosscheck.AssertionFailure(arrayrepr(array1) + ' and ' + arrayrepr(array2)
- + ' differs at index ' + i);
- }
- }
-}
--- a/devtools/test/data/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/test/data/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -30,4 +30,3 @@
cost = Int()
description = String(maxsize=4096, fulltextindexed=True)
identical_to = SubjectRelation('Bug', symmetric=True)
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devtools/test/data/static/js_examples/dep_1.js Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,1 @@
+a = 4;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devtools/test/data/static/js_examples/deps_2.js Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,1 @@
+b = a +2;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devtools/test/data/static/js_examples/test_simple_failure.js Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,18 @@
+$(document).ready(function() {
+
+ QUnit.module("air");
+
+ QUnit.test("test 1", function (assert) {
+ assert.equal(2, 4);
+ });
+
+ QUnit.test("test 2", function (assert) {
+ assert.equal('', '45');
+ assert.equal('1024', '32');
+ });
+
+ QUnit.module("able");
+ QUnit.test("test 3", function (assert) {
+ assert.deepEqual(1, 1);
+ });
+});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devtools/test/data/static/js_examples/test_simple_success.js Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,17 @@
+$(document).ready(function() {
+
+ QUnit.module("air");
+
+ QUnit.test("test 1", function (assert) {
+ assert.equal(2, 2);
+ });
+
+ QUnit.test("test 2", function (assert) {
+ assert.equal('45', '45');
+ });
+
+ QUnit.module("able");
+ QUnit.test("test 3", function (assert) {
+ assert.deepEqual(1, 1);
+ });
+});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devtools/test/data/static/js_examples/test_with_dep.js Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,9 @@
+$(document).ready(function() {
+
+ QUnit.module("air");
+
+ QUnit.test("test 1", function (assert) {
+ assert.equal(a, 4);
+ });
+
+});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devtools/test/data/static/js_examples/test_with_ordered_deps.js Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,9 @@
+$(document).ready(function() {
+
+ QUnit.module("air");
+
+ QUnit.test("test 1", function (assert) {
+ assert.equal(b, 6);
+ });
+
+});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/devtools/test/data/static/js_examples/utils.js Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,29 @@
+function datetuple(d) {
+ return [d.getFullYear(), d.getMonth()+1, d.getDate(),
+ d.getHours(), d.getMinutes()];
+}
+
+function pprint(obj) {
+ print('{');
+ for(k in obj) {
+ print(' ' + k + ' = ' + obj[k]);
+ }
+ print('}');
+}
+
+function arrayrepr(array) {
+ return '[' + array.join(', ') + ']';
+}
+
+function assertArrayEquals(array1, array2) {
+ if (array1.length != array2.length) {
+ throw new crosscheck.AssertionFailure(array1.join(', ') + ' != ' + array2.join(', '));
+ }
+ for (var i=0; i<array1.length; i++) {
+ if (array1[i] != array2[i]) {
+
+ throw new crosscheck.AssertionFailure(arrayrepr(array1) + ' and ' + arrayrepr(array2)
+ + ' differs at index ' + i);
+ }
+ }
+}
--- a/devtools/test/unittest_dbfill.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/test/unittest_dbfill.py Thu Dec 10 12:34:15 2015 +0100
@@ -21,6 +21,9 @@
import os.path as osp
import re
import datetime
+import io
+
+from six.moves import range
from logilab.common.testlib import TestCase, unittest_main
@@ -50,7 +53,7 @@
return None
def _available_Person_firstname(self, etype, attrname):
- return [f.strip() for f in file(osp.join(DATADIR, 'firstnames.txt'))]
+ return [f.strip() for f in io.open(osp.join(DATADIR, 'firstnames.txt'), encoding='latin1')]
def setUp(self):
config = ApptestConfiguration('data', apphome=DATADIR)
@@ -86,7 +89,7 @@
# Test for random index
for index in range(5):
cost_value = self.bug_valgen.generate_attribute_value({}, 'cost', index)
- self.assertIn(cost_value, range(index+1))
+ self.assertIn(cost_value, list(range(index+1)))
def test_date(self):
"""test date generation"""
--- a/devtools/test/unittest_httptest.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/test/unittest_httptest.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,7 +17,7 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""unittest for cubicweb.devtools.httptest module"""
-import httplib
+from six.moves import http_client
from logilab.common.testlib import Tags
from cubicweb.devtools.httptest import CubicWebServerTC
@@ -28,12 +28,12 @@
def test_response(self):
try:
response = self.web_get()
- except httplib.NotConnected as ex:
+ except http_client.NotConnected as ex:
self.fail("Can't connection to test server: %s" % ex)
def test_response_anon(self):
response = self.web_get()
- self.assertEqual(response.status, httplib.OK)
+ self.assertEqual(response.status, http_client.OK)
def test_base_url(self):
if self.config['base-url'] not in self.web_get().read():
@@ -47,20 +47,20 @@
def test_response_denied(self):
response = self.web_get()
- self.assertEqual(response.status, httplib.FORBIDDEN)
+ self.assertEqual(response.status, http_client.FORBIDDEN)
def test_login(self):
response = self.web_get()
- if response.status != httplib.FORBIDDEN:
+ if response.status != http_client.FORBIDDEN:
self.skipTest('Already authenticated, "test_response_denied" must have failed')
# login
self.web_login(self.admlogin, self.admpassword)
response = self.web_get()
- self.assertEqual(response.status, httplib.OK, response.body)
+ self.assertEqual(response.status, http_client.OK, response.body)
# logout
self.web_logout()
response = self.web_get()
- self.assertEqual(response.status, httplib.FORBIDDEN, response.body)
+ self.assertEqual(response.status, http_client.FORBIDDEN, response.body)
--- a/devtools/test/unittest_qunit.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/test/unittest_qunit.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,15 +1,10 @@
-from logilab.common.testlib import unittest_main
-from cubicweb.devtools.qunit import QUnitTestCase
-
-from os import path as osp
-
-JSTESTDIR = osp.abspath(osp.join(osp.dirname(__file__), 'data', 'js_examples'))
+from cubicweb.devtools import qunit
def js(name):
- return osp.join(JSTESTDIR, name)
+ return '/static/js_examples/' + name
-class QUnitTestCaseTC(QUnitTestCase):
+class QUnitTestCaseTC(qunit.QUnitTestCase):
all_js_tests = (
(js('test_simple_success.js'),),
@@ -28,4 +23,5 @@
if __name__ == '__main__':
- unittest_main()
+ from unittest import main
+ main()
--- a/devtools/test/unittest_testlib.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/test/unittest_testlib.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,9 +17,10 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""unittests for cw.devtools.testlib module"""
-from cStringIO import StringIO
+from io import BytesIO, StringIO
+from unittest import TextTestRunner
-from unittest import TextTestRunner
+from six import PY2
from logilab.common.testlib import TestSuite, TestCase, unittest_main
from logilab.common.registry import yes
@@ -33,7 +34,7 @@
class entity:
cw_etype = 'Entity'
eid = 0
- sio = StringIO('hop\n')
+ sio = BytesIO(b'hop\n')
form = CubicWebTC.fake_form('import',
{'file': ('filename.txt', sio),
'encoding': u'utf-8',
@@ -51,7 +52,7 @@
class WebTestTC(TestCase):
def setUp(self):
- output = StringIO()
+ output = BytesIO() if PY2 else StringIO()
self.runner = TextTestRunner(stream=output)
def test_error_raised(self):
--- a/devtools/test/unittest_webtest.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/test/unittest_webtest.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,4 +1,4 @@
-import httplib
+from six.moves import http_client
from logilab.common.testlib import Tags
from cubicweb.devtools.webtest import CubicWebTestTC
@@ -21,19 +21,19 @@
def test_reponse_denied(self):
res = self.webapp.get('/', expect_errors=True)
- self.assertEqual(httplib.FORBIDDEN, res.status_int)
+ self.assertEqual(http_client.FORBIDDEN, res.status_int)
def test_login(self):
res = self.webapp.get('/', expect_errors=True)
- self.assertEqual(httplib.FORBIDDEN, res.status_int)
+ self.assertEqual(http_client.FORBIDDEN, res.status_int)
self.login(self.admlogin, self.admpassword)
res = self.webapp.get('/')
- self.assertEqual(httplib.OK, res.status_int)
+ self.assertEqual(http_client.OK, res.status_int)
self.logout()
res = self.webapp.get('/', expect_errors=True)
- self.assertEqual(httplib.FORBIDDEN, res.status_int)
+ self.assertEqual(http_client.FORBIDDEN, res.status_int)
if __name__ == '__main__':
--- a/devtools/testlib.py Wed Dec 09 18:42:13 2015 +0100
+++ b/devtools/testlib.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,19 +16,22 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""this module contains base classes and utilities for cubicweb tests"""
+from __future__ import print_function
+
__docformat__ = "restructuredtext en"
import sys
import re
-import urlparse
from os.path import dirname, join, abspath
-from urllib import unquote
from math import log
from contextlib import contextmanager
from warnings import warn
-from types import NoneType
from itertools import chain
+from six import text_type, string_types
+from six.moves import range
+from six.moves.urllib.parse import urlparse, parse_qs, unquote as urlunquote
+
import yams.schema
from logilab.common.testlib import TestCase, InnerTest, Tags
@@ -60,7 +63,7 @@
def do_view(self, arg):
import webbrowser
data = self._getval(arg)
- with file('/tmp/toto.html', 'w') as toto:
+ with open('/tmp/toto.html', 'w') as toto:
toto.write(data)
webbrowser.open('file:///tmp/toto.html')
@@ -85,7 +88,7 @@
class JsonValidator(object):
def parse_string(self, data):
- return json.loads(data)
+ return json.loads(data.decode('ascii'))
@contextmanager
def real_error_handling(app):
@@ -283,7 +286,7 @@
"""provide a new RepoAccess object for a given user
The access is automatically closed at the end of the test."""
- login = unicode(login)
+ login = text_type(login)
access = RepoAccess(self.repo, login, self.requestcls)
self._open_access.add(access)
return access
@@ -310,7 +313,7 @@
db_handler.restore_database(self.test_db_id)
self.repo = db_handler.get_repo(startup=True)
# get an admin session (without actual login)
- login = unicode(db_handler.config.default_admin_config['login'])
+ login = text_type(db_handler.config.default_admin_config['login'])
self.admin_access = self.new_access(login)
self._admin_session = self.admin_access._session
@@ -323,8 +326,11 @@
Configuration is cached on the test class.
"""
+ if cls is CubicWebTC:
+ # Prevent direct use of CubicWebTC directly to avoid database
+ # caching issues
+ return None
try:
- assert not cls is CubicWebTC, "Don't use CubicWebTC directly to prevent database caching issue"
return cls.__dict__['_config']
except KeyError:
home = abspath(join(dirname(sys.modules[cls.__module__].__file__), cls.appid))
@@ -345,7 +351,7 @@
been properly bootstrapped.
"""
admincfg = config.default_admin_config
- cls.admlogin = unicode(admincfg['login'])
+ cls.admlogin = text_type(admincfg['login'])
cls.admpassword = admincfg['password']
# uncomment the line below if you want rql queries to be logged
#config.global_set_option('query-log-file',
@@ -366,7 +372,6 @@
config.global_set_option('embed-allowed', re.compile('.*'))
except Exception: # not in server only configuration
pass
- config.set_anonymous_allowed(cls.anonymous_allowed)
@property
def vreg(self):
@@ -404,6 +409,7 @@
self.__class__._repo_init_failed = ex
raise
self.addCleanup(self._close_access)
+ self.config.set_anonymous_allowed(self.anonymous_allowed)
self.setup_database()
MAILBOX[:] = [] # reset mailbox
@@ -453,14 +459,14 @@
if password is None:
password = login
if login is not None:
- login = unicode(login)
+ login = text_type(login)
user = req.create_entity('CWUser', login=login,
upassword=password, **kwargs)
req.execute('SET X in_group G WHERE X eid %%(x)s, G name IN(%s)'
% ','.join(repr(str(g)) for g in groups),
{'x': user.eid})
if email is not None:
- req.create_entity('EmailAddress', address=unicode(email),
+ req.create_entity('EmailAddress', address=text_type(email),
reverse_primary_email=user)
user.cw_clear_relation_cache('in_group', 'subject')
if commit:
@@ -518,10 +524,10 @@
similar to `orig_permissions.update(partial_perms)`.
"""
torestore = []
- for erschema, etypeperms in chain(perm_overrides, perm_kwoverrides.iteritems()):
- if isinstance(erschema, basestring):
+ for erschema, etypeperms in chain(perm_overrides, perm_kwoverrides.items()):
+ if isinstance(erschema, string_types):
erschema = self.schema[erschema]
- for action, actionperms in etypeperms.iteritems():
+ for action, actionperms in etypeperms.items():
origperms = erschema.permissions[action]
erschema.set_action_permissions(action, actionperms)
torestore.append([erschema, action, origperms])
@@ -737,8 +743,8 @@
req = self.request(url=url)
if isinstance(url, unicode):
url = url.encode(req.encoding) # req.setup_params() expects encoded strings
- querystring = urlparse.urlparse(url)[-2]
- params = urlparse.parse_qs(querystring)
+ querystring = urlparse(url)[-2]
+ params = parse_qs(querystring)
req.setup_params(params)
return req
@@ -751,8 +757,8 @@
with self.admin_access.web_request(url=url) as req:
if isinstance(url, unicode):
url = url.encode(req.encoding) # req.setup_params() expects encoded strings
- querystring = urlparse.urlparse(url)[-2]
- params = urlparse.parse_qs(querystring)
+ querystring = urlparse(url)[-2]
+ params = parse_qs(querystring)
req.setup_params(params)
yield req
@@ -791,7 +797,7 @@
path = location
params = {}
else:
- cleanup = lambda p: (p[0], unquote(p[1]))
+ cleanup = lambda p: (p[0], urlunquote(p[1]))
params = dict(cleanup(p.split('=', 1)) for p in params.split('&') if p)
if path.startswith(req.base_url()): # may be relative
path = path[len(req.base_url()):]
@@ -884,7 +890,7 @@
}
# maps vid : validator name (override content_type_validators)
vid_validators = dict((vid, htmlparser.VALMAP[valkey])
- for vid, valkey in VIEW_VALIDATORS.iteritems())
+ for vid, valkey in VIEW_VALIDATORS.items())
def view(self, vid, rset=None, req=None, template='main-template',
@@ -907,8 +913,11 @@
view = viewsreg.select(vid, req, rset=rset, **kwargs)
# set explicit test description
if rset is not None:
+ # coerce to "bytes" on py2 because the description will be sent to
+ # sys.stdout/stderr which takes "bytes" on py2 and "unicode" on py3
+ rql = str(rset.printable_rql())
self.set_description("testing vid=%s defined in %s with (%s)" % (
- vid, view.__module__, rset.printable_rql()))
+ vid, view.__module__, rql))
else:
self.set_description("testing vid=%s defined in %s without rset" % (
vid, view.__module__))
@@ -940,7 +949,9 @@
msg = '[%s in %s] %s' % (klass, view.__regid__, exc)
except Exception:
msg = '[%s in %s] undisplayable exception' % (klass, view.__regid__)
- raise AssertionError, msg, tcbk
+ exc = AssertionError(msg)
+ exc.__traceback__ = tcbk
+ raise exc
return self._check_html(output, view, template)
def get_validator(self, view=None, content_type=None, output=None):
@@ -953,11 +964,11 @@
if content_type is None:
content_type = 'text/html'
if content_type in ('text/html', 'application/xhtml+xml') and output:
- if output.startswith('<!DOCTYPE html>'):
+ if output.startswith(b'<!DOCTYPE html>'):
# only check XML well-formness since HTMLValidator isn't html5
# compatible and won't like various other extensions
default_validator = htmlparser.XMLSyntaxValidator
- elif output.startswith('<?xml'):
+ elif output.startswith(b'<?xml'):
default_validator = htmlparser.DTDValidator
else:
default_validator = htmlparser.HTMLValidator
@@ -973,6 +984,9 @@
def _check_html(self, output, view, template='main-template'):
"""raises an exception if the HTML is invalid"""
output = output.strip()
+ if isinstance(output, text_type):
+ # XXX
+ output = output.encode('utf-8')
validator = self.get_validator(view, output=output)
if validator is None:
return output # return raw output if no validator is defined
@@ -998,7 +1012,7 @@
str_exc = str(exc)
except Exception:
str_exc = 'undisplayable exception'
- msg += str_exc
+ msg += str_exc.encode(sys.getdefaultencoding(), 'replace')
if content is not None:
position = getattr(exc, "position", (0,))[0]
if position:
@@ -1015,7 +1029,9 @@
for idx, line in enumerate(content)
if line_context_filter(idx+1, position))
msg += u'\nfor content:\n%s' % content
- raise AssertionError, msg, tcbk
+ exc = AssertionError(msg)
+ exc.__traceback__ = tcbk
+ raise exc
def assertDocTestFile(self, testfile):
# doctest returns tuple (failure_count, test_count)
@@ -1096,7 +1112,7 @@
# new num for etype = max(current num, sum(num for possible target etypes))
#
# XXX we should first check there is no cycle then propagate changes
- for (rschema, etype), targets in relmap.iteritems():
+ for (rschema, etype), targets in relmap.items():
relfactor = sum(howmanydict[e] for e in targets)
howmanydict[str(etype)] = max(relfactor, howmanydict[etype])
return howmanydict
@@ -1166,7 +1182,7 @@
cnx.execute(rql, args)
except ValidationError as ex:
# failed to satisfy some constraint
- print 'error in automatic db population', ex
+ print('error in automatic db population', ex)
cnx.commit_state = None # reset uncommitable flag
self.post_populate(cnx)
@@ -1179,7 +1195,7 @@
else:
rql = 'Any X WHERE X is %s' % etype
rset = req.execute(rql)
- for row in xrange(len(rset)):
+ for row in range(len(rset)):
if limit and row > limit:
break
# XXX iirk
@@ -1243,7 +1259,10 @@
tags = AutoPopulateTest.tags | Tags('web', 'generated')
def setUp(self):
- assert not self.__class__ is AutomaticWebTest, 'Please subclass AutomaticWebTest to prevent database caching issue'
+ if self.__class__ is AutomaticWebTest:
+ # Prevent direct use of AutomaticWebTest to avoid database caching
+ # issues.
+ return
super(AutomaticWebTest, self).setUp()
# access to self.app for proper initialization of the authentication
@@ -1284,7 +1303,7 @@
# # XXX broken
# from cubicweb.devtools.apptest import TestEnvironment
# env = testclass._env = TestEnvironment('data', configcls=testclass.configcls)
-# for reg in env.vreg.itervalues():
+# for reg in env.vreg.values():
# reg._selected = {}
# try:
# orig_select_best = reg.__class__.__orig_select_best
@@ -1304,10 +1323,10 @@
# def print_untested_objects(testclass, skipregs=('hooks', 'etypes')):
-# for regname, reg in testclass._env.vreg.iteritems():
+# for regname, reg in testclass._env.vreg.items():
# if regname in skipregs:
# continue
-# for appobjects in reg.itervalues():
+# for appobjects in reg.values():
# for appobject in appobjects:
# if not reg._selected.get(appobject):
# print 'not tested', regname, appobject
--- a/doc/book/devrepo/fti.rst Wed Dec 09 18:42:13 2015 +0100
+++ b/doc/book/devrepo/fti.rst Thu Dec 10 12:34:15 2015 +0100
@@ -94,37 +94,10 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``db-rebuild-fti`` will call the
-:meth:`~cubicweb.entities.AnyEntity.cw_fti_index_rql_queries` class
+:meth:`~cubicweb.entities.AnyEntity.cw_fti_index_rql_limit` class
method on your entity type.
-.. automethod:: cubicweb.entities.AnyEntity.cw_fti_index_rql_queries
-
-Now, suppose you've got a _huge_ table to index, you probably don't want to
-get all entities at once. So here's a simple customized example that will
-process block of 10000 entities:
-
-.. sourcecode:: python
-
-
- class MyEntityClass(AnyEntity):
- __regid__ = 'MyEntityClass'
-
- @classmethod
- def cw_fti_index_rql_queries(cls, req):
- # get the default RQL method and insert LIMIT / OFFSET instructions
- base_rql = super(SearchIndex, cls).cw_fti_index_rql_queries(req)[0]
- selected, restrictions = base_rql.split(' WHERE ')
- rql_template = '%s ORDERBY X LIMIT %%(limit)s OFFSET %%(offset)s WHERE %s' % (
- selected, restrictions)
- # count how many entities you'll have to index
- count = req.execute('Any COUNT(X) WHERE X is MyEntityClass')[0][0]
- # iterate by blocks of 10000 entities
- chunksize = 10000
- for offset in xrange(0, count, chunksize):
- print 'SENDING', rql_template % {'limit': chunksize, 'offset': offset}
- yield rql_template % {'limit': chunksize, 'offset': offset}
-
-Since you have access to ``req``, you can more or less fetch whatever you want.
+.. automethod:: cubicweb.entities.AnyEntity.cw_fti_index_rql_limit
Customizing :meth:`~cubicweb.entities.adapters.IFTIndexableAdapter.get_words`
--- a/doc/book/devrepo/testing.rst Wed Dec 09 18:42:13 2015 +0100
+++ b/doc/book/devrepo/testing.rst Thu Dec 10 12:34:15 2015 +0100
@@ -324,9 +324,9 @@
def test_blog_rss(self):
with self.admin_access.web_request() as req:
- rset = req.execute('Any B ORDERBY D DESC WHERE B is BlogEntry, '
- 'B created_by U, U login "logilab", B creation_date D')
- self.view('rss', rset, req=req)
+ rset = req.execute('Any B ORDERBY D DESC WHERE B is BlogEntry, '
+ 'B created_by U, U login "logilab", B creation_date D')
+ self.view('rss', rset, req=req)
Testing with other cubes
--- a/doc/book/devweb/views/table.rst Wed Dec 09 18:42:13 2015 +0100
+++ b/doc/book/devweb/views/table.rst Thu Dec 10 12:34:15 2015 +0100
@@ -96,8 +96,8 @@
'resource': MainEntityColRenderer(),
'workpackage': EntityTableColRenderer(
header='Workpackage',
- renderfunc=worpackage_cell,
- sortfunc=worpackage_sortvalue,),
+ renderfunc=workpackage_cell,
+ sortfunc=workpackage_sortvalue,),
'in_state': EntityTableColRenderer(
renderfunc=lambda w,x: w(x.cw_adapt_to('IWorkflowable').printable_state),
sortfunc=lambda x: x.cw_adapt_to('IWorkflowable').printable_state),
--- a/doc/changes/3.21.rst Wed Dec 09 18:42:13 2015 +0100
+++ b/doc/changes/3.21.rst Thu Dec 10 12:34:15 2015 +0100
@@ -1,5 +1,5 @@
-3.21
-====
+3.21 (10 July 2015)
+===================
New features
------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/changes/3.22.rst Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,71 @@
+3.22
+====
+
+New features
+------------
+
+* a huge amount of changes were done towards python 3.x support (as yet
+ incomplete). This introduces a new dependency on six, to handle
+ python2/python3 compatibility.
+
+* new cubicweb.dataimport.massive_store module, a postgresql-specific store
+ using the COPY statement to accelerate massive data imports. This
+ functionality was previously part of cubicweb-dataio (there are some API
+ differences with that previous version, however).
+
+* cubes custom sql scripts are executed before creating tables. This allows
+ them to create new types or extensions.
+
+User-visible changes
+--------------------
+
+* the ldapfeed source now depends on the `ldap3` module instead of
+ `python-ldap`.
+
+* replies don't get an ``Expires`` header by default. However when they do,
+ they also get a coherent ``Cache-Control``.
+
+* data files are regenerated at each request, they are no longer cached by
+ ``cubicweb.web.PropertySheet``. Requests for data files missing the instance
+ hash are handled with a redirection instead of a direct reply, to allow
+ correct cache-related reply headers.
+
+API changes
+-----------
+
+* ``config.repository()`` creates a new Repository object each time, instead of
+ returning a cached object
+
+* migration scripts, as well as other scripts executed by ``cubicweb-ctl
+ shell``, are loaded with the print_function flag enabled (for backwards
+ compatibility, if that fails they are re-loaded without that flag)
+
+* the ``cw_fti_index_rql_queries`` method on entity classes is replaced by
+ ``cw_fti_index_rql_limit``, a generator which yields ``ResultSet`` objects
+ containing entities to be indexed. By default, entities are returned 1000 at
+ a time.
+
+* ``IDownloadableAdapter`` API is clarified: ``download_url``,
+ ``download_content_type`` and ``download_file_name`` return unicode objects,
+ ``download_data`` returns bytes.
+
+* the ``Repository.extid2eid()`` entry point for external sources is deprecated.
+ Imports should use one of the stores from the ``cubicweb.dataimport`` package
+ instead.
+
+* the ``cubicweb.repoapi.get_repository()`` function's ``uri`` argument should
+ no longer be used.
+
+* the generic datafeed xml parser is deprecated in favor of the "store" API
+ introduced in cubicweb 3.21.
+
+* the session manager lives in the ``sessions`` registry instead of ``components``.
+
+Deprecated code drops
+---------------------
+
+* the ``cubicweb.server.hooksmanager`` module was removed
+
+* the ``Repository.pinfo()`` method was removed
+
+* the ``cubicweb.utils.SizeConstrainedList`` class was removed
--- a/doc/changes/changelog.rst Wed Dec 09 18:42:13 2015 +0100
+++ b/doc/changes/changelog.rst Thu Dec 10 12:34:15 2015 +0100
@@ -2,6 +2,7 @@
Changelog history
===================
+.. include:: 3.22.rst
.. include:: 3.21.rst
.. include:: 3.20.rst
.. include:: 3.19.rst
--- a/doc/changes/index.rst Wed Dec 09 18:42:13 2015 +0100
+++ b/doc/changes/index.rst Thu Dec 10 12:34:15 2015 +0100
@@ -4,6 +4,7 @@
.. toctree::
:maxdepth: 1
+ 3.22
3.21
3.20
3.19
--- a/doc/dev/features_list.rst Wed Dec 09 18:42:13 2015 +0100
+++ b/doc/dev/features_list.rst Thu Dec 10 12:34:15 2015 +0100
@@ -2,21 +2,21 @@
CubicWeb features
=================
-This page tries to resume features found in the bare cubicweb framework,
+This page summarizes features found in the bare cubicweb framework and indicates
how mature and documented they are.
:code maturity (CM):
- 0: experimental, not ready at all for production, may be killed
- - 1: draft / unsatisfying, api may change in a near future, much probably in long
- term
+ - 1: draft / unsatisfying, API may change in a near future, and will
+ certainly change in the long term
- - 2: good enough, api sounds good but will probably evolve a bit with more
+ - 2: good enough, API sounds good but will probably evolve a bit with more
hindsight
- - 3: mature, backward incompatible changes unexpected (may still evolve though,
- of course)
+ - 3: mature, backward incompatible changes unexpected (may still evolve
+ though, of course)
:documentation level (DL):
@@ -25,7 +25,7 @@
- 1: poor documentation
- - 2: some valuable documentation but some parts keep uncovered
+ - 2: some valuable documentation but incomplete coverage
- 3: good / complete documentation
@@ -33,191 +33,306 @@
Instance configuration and maintainance
=======================================
-+====================================================================+====+====+
-| FEATURE | CM | DL |
-+====================================================================+====+====+
-| setup - installation | 2 | 3 |
-| setup - environment variables | 3 | 2 |
-| setup - running modes | 2 | 2 |
-| setup - administration tasks | 2 | 2 |
-| setup - configuration file | 2 | 1 |
-+--------------------------------------------------------------------+----+----+
-| configuration - user / groups handling | 3 | 1 |
-| configuration - site configuration | 3 | 1 |
-| configuration - distributed configuration | 2 | 1 |
-+--------------------------------------------------------------------+----+----+
-| multi-sources - capabilities | NA | 0 |
-| multi-sources - configuration | 2 | 0 |
-| multi-sources - ldap integration | 2 | 1 |
-+--------------------------------------------------------------------+----+----+
-| usage - custom ReST markup | 2 | 0 |
-| usage - personal preferences | 2 | 1 |
-+--------------------------------------------------------------------+----+----+
+.. table::
+ +-------------------------------------------------------------------+----+----+
+ | FEATURE | CM | DL |
+ +===============+===================================================+====+====+
+ | setup | installation | 2 | 3 |
+ | +---------------------------------------------------+----+----+
+ | | environment variables | 3 | 2 |
+ | +---------------------------------------------------+----+----+
+ | | running modes | 2 | 2 |
+ | +---------------------------------------------------+----+----+
+ | | administration tasks | 2 | 2 |
+ | +---------------------------------------------------+----+----+
+ | | configuration file | 2 | 1 |
+ +---------------+---------------------------------------------------+----+----+
+ | configuration | user / groups handling | 3 | 1 |
+ | +---------------------------------------------------+----+----+
+ | | site configuration | 3 | 1 |
+ | +---------------------------------------------------+----+----+
+ | | distributed configuration | 2 | 1 |
+ +---------------+---------------------------------------------------+----+----+
+ | multi-sources | capabilities | NA | 0 |
+ | +---------------------------------------------------+----+----+
+ | | configuration | 2 | 0 |
+ | +---------------------------------------------------+----+----+
+ | | ldap integration | 2 | 1 |
+ +---------------+---------------------------------------------------+----+----+
+ | usage | custom ReST markup | 2 | 0 |
+ | +---------------------------------------------------+----+----+
+ | | personal preferences | 2 | 1 |
+ +---------------+---------------------------------------------------+----+----+
Core development
================
-+====================================================================+====+====+
-| FEATURE | CM | DL |
-+====================================================================+====+====+
-| base - concepts | NA | 3 |
-| base - security model | NA | 2 |
-| base - database initialization | 2 | 1 |
-+--------------------------------------------------------------------+----+----+
-| rql - base | 2 | 2 |
-| rql - write | 2 | 2 |
-| rql - function | 2 | 0 |
-| rql - outer joins | 2 | 1 |
-| rql - aggregates | 2 | 1 |
-| rql - subqueries | 2 | 0 |
-+--------------------------------------------------------------------+----+----+
-| schema - base | 2 | 3 |
-| schema - constraints | 3 | 2 |
-| schema - security | 2 | 2 |
-| schema - inheritance | 1 | 1 |
-| schema - customization | 1 | 1 |
-| schema - introspection | 2 | 1 |
-+--------------------------------------------------------------------+----+----+
-| vregistry - appobject | 2 | 2 |
-| vregistry - registration | 2 | 2 |
-| vregistry - selection | 3 | 2 |
-| vregistry - core selectors | 3 | 3 |
-| vregistry - custom selectors | 2 | 1 |
-| vregistry - debugging selection | 2 | 1 |
-+--------------------------------------------------------------------+----+----+
-| entities - interfaces | 2 | ? |
-| entities - customization (`dc_`, ...) | 2 | ? |
-| entities - app logic | 2 | 2 |
-| entities - orm configuration | 2 | 1 |
-| entities - pluggable mixins | 1 | 0 |
-| entities - workflow | 3 | 2 |
-+--------------------------------------------------------------------+----+----+
-| dbapi - connection | 3 | 1 |
-| dbapi - data management | 1 | 1 |
-| dbapi - result set | 3 | 1 |
-| dbapi - transaction, undo | 2 | 0 |
-+--------------------------------------------------------------------+----+----+
-| cube - layout | 2 | 3 |
-| cube - new cube | 2 | 2 |
-+--------------------------------------------------------------------+----+----+
-| migration - context | 2 | 1 |
-| migration - commands | 2 | 2 |
-+--------------------------------------------------------------------+----+----+
-| testlib - CubicWebTC | 2 | 1 |
-| testlib - automatic tests | 2 | 2 |
-+--------------------------------------------------------------------+----+----+
-| i18n - mark string | 3 | 2 |
-| i18n - customize strings from other cubes / cubicweb | 3 | 1 |
-| i18n - update catalog | 3 | 2 |
-+--------------------------------------------------------------------+----+----+
-| more - reloading tips | NA | 0 |
-| more - site_cubicweb | 2 | ? |
-| more - adding options in configuration file | 3 | 0 |
-| more - adding options in site configuration / preferences | 3 | ? |
-| more - optimizing / profiling | 2 | 1 |
-| more - c-c plugins | 3 | 0 |
-| more - crypto services | 0 | 0 |
-| more - massive import | 2 | 0 |
-| more - mime type based conversion | 2 | 0 |
-| more - CWCache | 1 | 0 |
-+--------------------------------------------------------------------+----+----+
+.. table::
+
+ +--------------------------------------------------------------------+----+----+
+ | FEATURE | CM | DL |
+ +===========+========================================================+====+====+
+ | base | concepts | NA | 3 |
+ | +--------------------------------------------------------+----+----+
+ | | security model | NA | 2 |
+ | +--------------------------------------------------------+----+----+
+ | | database initialization | 2 | 1 |
+ +-----------+--------------------------------------------------------+----+----+
+ | rql | base | 2 | 2 |
+ | +--------------------------------------------------------+----+----+
+ | | write | 2 | 2 |
+ | +--------------------------------------------------------+----+----+
+ | | function | 2 | 0 |
+ | +--------------------------------------------------------+----+----+
+ | | outer joins | 2 | 1 |
+ | +--------------------------------------------------------+----+----+
+ | | aggregates | 2 | 1 |
+ | +--------------------------------------------------------+----+----+
+ | | subqueries | 2 | 0 |
+ +-----------+--------------------------------------------------------+----+----+
+ | schema | base | 2 | 3 |
+ | +--------------------------------------------------------+----+----+
+ | | constraints | 3 | 2 |
+ | +--------------------------------------------------------+----+----+
+ | | security | 2 | 2 |
+ | +--------------------------------------------------------+----+----+
+ | | inheritance | 1 | 1 |
+ | +--------------------------------------------------------+----+----+
+ | | customization | 1 | 1 |
+ | +--------------------------------------------------------+----+----+
+ | | introspection | 2 | 1 |
+ +-----------+--------------------------------------------------------+----+----+
+ | vregistry | appobject | 2 | 2 |
+ | +--------------------------------------------------------+----+----+
+ | | registration | 2 | 2 |
+ | +--------------------------------------------------------+----+----+
+ | | selection | 3 | 2 |
+ | +--------------------------------------------------------+----+----+
+ | | core selectors | 3 | 3 |
+ | +--------------------------------------------------------+----+----+
+ | | custom selectors | 2 | 1 |
+ | +--------------------------------------------------------+----+----+
+ | | debugging selection | 2 | 1 |
+ +-----------+--------------------------------------------------------+----+----+
+ | entities | interfaces | 2 | ? |
+ | +--------------------------------------------------------+----+----+
+ | | customization (`dc_`, ...) | 2 | ? |
+ | +--------------------------------------------------------+----+----+
+ | | app logic | 2 | 2 |
+ | +--------------------------------------------------------+----+----+
+ | | orm configuration | 2 | 1 |
+ | +--------------------------------------------------------+----+----+
+ | | pluggable mixins | 1 | 0 |
+ | +--------------------------------------------------------+----+----+
+ | | workflow | 3 | 2 |
+ +-----------+--------------------------------------------------------+----+----+
+ | dbapi | connection | 3 | 1 |
+ | +--------------------------------------------------------+----+----+
+ | | data management | 1 | 1 |
+ | +--------------------------------------------------------+----+----+
+ | | result set | 3 | 1 |
+ | +--------------------------------------------------------+----+----+
+ | | transaction, undo | 2 | 0 |
+ +-----------+--------------------------------------------------------+----+----+
+ | cube | layout | 2 | 3 |
+ | +--------------------------------------------------------+----+----+
+ | | new cube | 2 | 2 |
+ +-----------+--------------------------------------------------------+----+----+
+ | migration | context | 2 | 1 |
+ | +--------------------------------------------------------+----+----+
+ | | commands | 2 | 2 |
+ +-----------+--------------------------------------------------------+----+----+
+ | testlib | CubicWebTC | 2 | 1 |
+ | +--------------------------------------------------------+----+----+
+ | | automatic tests | 2 | 2 |
+ +-----------+--------------------------------------------------------+----+----+
+ | i18n | mark string | 3 | 2 |
+ | +--------------------------------------------------------+----+----+
+ | | customize strings from other cubes / cubicweb | 3 | 1 |
+ | +--------------------------------------------------------+----+----+
+ | | update catalog | 3 | 2 |
+ +-----------+--------------------------------------------------------+----+----+
+ | more | reloading tips | NA | 0 |
+ | +--------------------------------------------------------+----+----+
+ | | site_cubicweb | 2 | ? |
+ | +--------------------------------------------------------+----+----+
+ | | adding options in configuration file | 3 | 0 |
+ | +--------------------------------------------------------+----+----+
+ | | adding options in site configuration / preferences | 3 | ? |
+ | +--------------------------------------------------------+----+----+
+ | | optimizing / profiling | 2 | 1 |
+ | +--------------------------------------------------------+----+----+
+ | | c-c plugins | 3 | 0 |
+ | +--------------------------------------------------------+----+----+
+ | | crypto services | 0 | 0 |
+ | +--------------------------------------------------------+----+----+
+ | | massive import | 2 | 0 |
+ | +--------------------------------------------------------+----+----+
+ | | mime type based conversion | 2 | 0 |
+ | +--------------------------------------------------------+----+----+
+ | | CWCache | 1 | 0 |
+ +-----------+--------------------------------------------------------+----+----+
Web UI development
==================
-+====================================================================+====+====+
-| FEATURE | CM | DL |
-+====================================================================+====+====+
-| base - web request | 2 | 2 |
-| base - exceptions | 2 | 0 |
-| base - session, authentication | 1 | 0 |
-| base - http caching | 2 | 1 |
-| base - external resources | 2 | 2 |
-| base - static files | 2 | ? |
-| base - data sharing | 2 | 2 |
-| base - graphical chart customization | 1 | 1 |
-+--------------------------------------------------------------------+----+----+
-| publishing - cycle | 2 | 2 |
-| publishing - error handling | 2 | 1 |
-| publishing - transactions | NA | ? |
-+--------------------------------------------------------------------+----+----+
-| controller - base | 2 | 2 |
-| controller - view | 2 | 1 |
-| controller - edit | 2 | 1 |
-| controller - json | 2 | 1 |
-+--------------------------------------------------------------------+----+----+
-| views - base | 2 | 2 |
-| views - templates | 2 | 2 |
-| views - boxes | 2 | 1 |
-| views - components | 2 | 1 |
-| views - primary | 2 | 1 |
-| views - tabs | 2 | 1 |
-| views - xml | 2 | 0 |
-| views - text | 2 | 1 |
-| views - table | 2 | 1 |
-| views - plot | 2 | 0 |
-| views - navigation | 2 | 0 |
-| views - calendar, timeline | 2 | 0 |
-| views - index | 2 | 2 |
-| views - breadcrumbs | 2 | 1 |
-| views - actions | 2 | 1 |
-| views - debugging | 2 | 1 |
-+--------------------------------------------------------------------+----+----+
-| form - base | 2 | 1 |
-| form - fields | 2 | 1 |
-| form - widgets | 2 | 1 |
-| form - captcha | 2 | 0 |
-| form - renderers | 2 | 0 |
-| form - validation error handling | 2 | 0 |
-| form - autoform | 2 | 2 |
-| form - reledit | 2 | 0 |
-+--------------------------------------------------------------------+----+----+
-| facets - base | 2 | ? |
-| facets - configuration | 2 | 1 |
-| facets - custom facets | 2 | 0 |
-+--------------------------------------------------------------------+----+----+
-| css - base | 1 | 1 |
-| css - customization | 1 | 1 |
-+--------------------------------------------------------------------+----+----+
-| js - base | 1 | 1 |
-| js - jquery | 1 | 1 |
-| js - base functions | 1 | 0 |
-| js - ajax | 1 | 0 |
-| js - widgets | 1 | 1 |
-+--------------------------------------------------------------------+----+----+
-| other - page template | 0 | 0 |
-| other - inline doc (wdoc) | 2 | 0 |
-| other - magic search | 2 | 0 |
-| other - url mapping | 1 | 1 |
-| other - apache style url rewrite | 1 | 1 |
-| other - sparql | 1 | 0 |
-| other - bookmarks | 2 | 1 |
-+--------------------------------------------------------------------+----+----+
+.. table::
+
+ +--------------------------------------------------------------------+----+----+
+ | FEATURE | CM | DL |
+ +============+=======================================================+====+====+
+ | base | web request | 2 | 2 |
+ | +-------------------------------------------------------+----+----+
+ | | exceptions | 2 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | session, authentication | 1 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | http caching | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | external resources | 2 | 2 |
+ | +-------------------------------------------------------+----+----+
+ | | static files | 2 | ? |
+ | +-------------------------------------------------------+----+----+
+ | | data sharing | 2 | 2 |
+ | +-------------------------------------------------------+----+----+
+ | | graphical chart customization | 1 | 1 |
+ +------------+-------------------------------------------------------+----+----+
+ | publishing | cycle | 2 | 2 |
+ | +-------------------------------------------------------+----+----+
+ | | error handling | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | transactions | NA | ? |
+ +------------+-------------------------------------------------------+----+----+
+ | controller | base | 2 | 2 |
+ | +-------------------------------------------------------+----+----+
+ | | view | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | edit | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | json | 2 | 1 |
+ +------------+-------------------------------------------------------+----+----+
+ | views | base | 2 | 2 |
+ | +-------------------------------------------------------+----+----+
+ | | templates | 2 | 2 |
+ | +-------------------------------------------------------+----+----+
+ | | boxes | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | components | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | primary | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | tabs | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | xml | 2 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | text | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | table | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | plot | 2 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | navigation | 2 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | calendar, timeline | 2 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | index | 2 | 2 |
+ | +-------------------------------------------------------+----+----+
+ | | breadcrumbs | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | actions | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | debugging | 2 | 1 |
+ +------------+-------------------------------------------------------+----+----+
+ | form | base | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | fields | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | widgets | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | captcha | 2 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | renderers | 2 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | validation error handling | 2 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | autoform | 2 | 2 |
+ | +-------------------------------------------------------+----+----+
+ | | reledit | 2 | 0 |
+ +------------+-------------------------------------------------------+----+----+
+ | facets | base | 2 | ? |
+ | +-------------------------------------------------------+----+----+
+ | | configuration | 2 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | custom facets | 2 | 0 |
+ +------------+-------------------------------------------------------+----+----+
+ | css | base | 1 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | customization | 1 | 1 |
+ +------------+-------------------------------------------------------+----+----+
+ | js | base | 1 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | jquery | 1 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | base functions | 1 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | widgets | 1 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | ajax | 1 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | widgets | 1 | 1 |
+ +------------+-------------------------------------------------------+----+----+
+ | other | page template | 0 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | inline doc (wdoc) | 2 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | magic search | 2 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | url mapping | 1 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | apache style url rewrite | 1 | 1 |
+ | +-------------------------------------------------------+----+----+
+ | | sparql | 1 | 0 |
+ | +-------------------------------------------------------+----+----+
+ | | bookmarks | 2 | 1 |
+ +------------+-------------------------------------------------------+----+----+
Repository development
======================
-+====================================================================+====+====+
-| FEATURE | CM | DL |
-+====================================================================+====+====+
-| base - session | 2 | 2 |
-| base - more security control | 2 | 0 |
-| base - debugging | 2 | 0 |
-+--------------------------------------------------------------------+----+----+
-| hooks - development | 2 | 2 |
-| hooks - abstract hooks | 2 | 0 |
-| hooks - core hooks | 2 | 0 |
-| hooks - control | 2 | 0 |
-| hooks - operation | 2 | 2 |
-+--------------------------------------------------------------------+----+----+
-| notification - sending email | 2 | ? |
-| notification - base views | 1 | ? |
-| notification - supervisions | 1 | 0 |
-+--------------------------------------------------------------------+----+----+
-| source - storages | 2 | 0 |
-| source - authentication plugins | 2 | 0 |
-| source - custom sources | 2 | 0 |
-+--------------------------------------------------------------------+----+----+
+.. table::
+
+ +--------------------------------------------------------------------+----+----+
+ | FEATURE | CM | DL |
+ +==============+=====================================================+====+====+
+ | base | session | 2 | 2 |
+ | +-----------------------------------------------------+----+----+
+ | | more security control | 2 | 0 |
+ | +-----------------------------------------------------+----+----+
+ | | debugging | 2 | 0 |
+ +--------------+-----------------------------------------------------+----+----+
+ | hooks | development | 2 | 2 |
+ | +-----------------------------------------------------+----+----+
+ | | abstract hooks | 2 | 0 |
+ | +-----------------------------------------------------+----+----+
+ | | core hooks | 2 | 0 |
+ | +-----------------------------------------------------+----+----+
+ | | control | 2 | 0 |
+ | +-----------------------------------------------------+----+----+
+ | | operation | 2 | 2 |
+ +--------------+-----------------------------------------------------+----+----+
+ | notification | sending email | 2 | ? |
+ | +-----------------------------------------------------+----+----+
+ | | base views | 1 | ? |
+ | +-----------------------------------------------------+----+----+
+ | | supervisions | 1 | 0 |
+ +--------------+-----------------------------------------------------+----+----+
+ | source | storages | 2 | 0 |
+ | +-----------------------------------------------------+----+----+
+ | | authentication plugins | 2 | 0 |
+ | +-----------------------------------------------------+----+----+
+ | | custom sources | 2 | 0 |
+ +--------------+-----------------------------------------------------+----+----+
+
--- a/doc/tools/mode_plan.py Wed Dec 09 18:42:13 2015 +0100
+++ b/doc/tools/mode_plan.py Thu Dec 10 12:34:15 2015 +0100
@@ -23,17 +23,19 @@
rename A010-joe.en.txt to A030-joe.en.txt
accept [y/N]?
"""
+from __future__ import print_function
+
def ren(a,b):
names = glob.glob('%s*'%a)
for name in names :
- print 'rename %s to %s' % (name, name.replace(a,b))
+ print('rename %s to %s' % (name, name.replace(a,b)))
if raw_input('accept [y/N]?').lower() =='y':
for name in names:
os.system('hg mv %s %s' % (name, name.replace(a,b)))
-def ls(): print '\n'.join(sorted(os.listdir('.')))
+def ls(): print('\n'.join(sorted(os.listdir('.'))))
def move():
filenames = []
@@ -47,4 +49,4 @@
for num, name in filenames:
if num >= start:
- print 'hg mv %s %2i%s' %(name,num+1,name[2:])
+ print('hg mv %s %2i%s' %(name,num+1,name[2:]))
--- a/doc/tutorials/base/customizing-the-application.rst Wed Dec 09 18:42:13 2015 +0100
+++ b/doc/tutorials/base/customizing-the-application.rst Thu Dec 10 12:34:15 2015 +0100
@@ -422,7 +422,7 @@
entity = self.cw_rset.get_entity(row, col)
self.w(u'<h1>Welcome to the "%s" community</h1>' % entity.printable_value('name'))
if entity.display_cw_logo():
- self.w(u'<img src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>')
+ self.w(u'<img src="https://docs.cubicweb.org/_static/logo-cubicweb-small.svg"/>')
if entity.description:
self.w(u'<p>%s</p>' % entity.printable_value('description'))
@@ -522,7 +522,7 @@
def render_entity_attributes(self, entity):
if entity.display_cw_logo():
- self.w(u'<img src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>')
+ self.w(u'<img src="https://docs.cubicweb.org/_static/logo-cubicweb-small.svg"/>')
if entity.description:
self.w(u'<p>%s</p>' % entity.printable_value('description'))
--- a/doc/tutorials/base/discovering-the-ui.rst Wed Dec 09 18:42:13 2015 +0100
+++ b/doc/tutorials/base/discovering-the-ui.rst Thu Dec 10 12:34:15 2015 +0100
@@ -101,16 +101,16 @@
You can achieve the same thing by following the same path as we did for the blog
creation, e.g. by clicking on the `[+]` at the left of the 'Blog entry' link on
-the index page. The diffidence being that since there is no context information,
+the index page. The difference being that since there is no context information,
the 'blog entry of' selector won't be preset to the blog.
If you click on the 'modify' link of the action box, you are back to
the form to edit the entity you just created, except that the form now
has another section with a combo-box entitled 'add relation'. It
-provisos a generic way to edit relations which don't appears in the
+provides a generic way to edit relations which don't appears in the
above form. Choose the relation you want to add and a second combo box
-appears where you can pick existing entities. If there are too many
+appears where you can pick existing entities. If there are too many
of them, you will be offered to navigate to the target entity, that is
go away from the form and go back to it later, once you've selected
the entity you want to link with.
--- a/doc/tutorials/dataimport/diseasome_import.py Wed Dec 09 18:42:13 2015 +0100
+++ b/doc/tutorials/dataimport/diseasome_import.py Thu Dec 10 12:34:15 2015 +0100
@@ -95,7 +95,7 @@
# Perform a first commit, of the entities
store.flush()
kwargs = {}
- for uri, relations in all_relations.iteritems():
+ for uri, relations in all_relations.items():
from_eid = uri_to_eid.get(uri)
# ``subjtype`` should be initialized if ``SQLGenObjectStore`` is used
# and there are inlined relations in the schema.
@@ -108,7 +108,7 @@
kwargs['subjtype'] = uri_to_etype.get(uri)
if not from_eid:
continue
- for rtype, rels in relations.iteritems():
+ for rtype, rels in relations.items():
if rtype in ('classes', 'possible_drugs', 'omim', 'omim_page',
'chromosomal_location', 'same_as', 'gene_id',
'hgnc_id', 'hgnc_page'):
--- a/doc/tutorials/dataimport/diseasome_parser.py Wed Dec 09 18:42:13 2015 +0100
+++ b/doc/tutorials/dataimport/diseasome_parser.py Thu Dec 10 12:34:15 2015 +0100
@@ -97,4 +97,4 @@
entities[subj]['relations'].setdefault(MAPPING_RELS[rel], set())
entities[subj]['relations'][MAPPING_RELS[rel]].add(unicode(obj))
return ((ent.get('attributes'), ent.get('relations'))
- for ent in entities.itervalues())
+ for ent in entities.values())
--- a/entities/__init__.py Wed Dec 09 18:42:13 2015 +0100
+++ b/entities/__init__.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,8 +19,12 @@
__docformat__ = "restructuredtext en"
+from warnings import warn
+
+from six import text_type, string_types
from logilab.common.decorators import classproperty
+from logilab.common.deprecation import deprecated
from cubicweb import Unauthorized
from cubicweb.entity import Entity
@@ -35,7 +39,7 @@
@classproperty
def cw_etype(cls):
"""entity type as a unicode string"""
- return unicode(cls.__regid__)
+ return text_type(cls.__regid__)
@classmethod
def cw_create_url(cls, req, **kwargs):
@@ -43,6 +47,7 @@
return req.build_url('add/%s' % cls.__regid__, **kwargs)
@classmethod
+ @deprecated('[3.22] use cw_fti_index_rql_limit instead')
def cw_fti_index_rql_queries(cls, req):
"""return the list of rql queries to fetch entities to FT-index
@@ -60,6 +65,37 @@
return ['Any %s WHERE %s' % (', '.join(selected),
', '.join(restrictions))]
+ @classmethod
+ def cw_fti_index_rql_limit(cls, req, limit=1000):
+ """generate rsets of entities to FT-index
+
+ By default, each successive result set is limited to 1000 entities
+ """
+ if cls.cw_fti_index_rql_queries.__func__ != AnyEntity.cw_fti_index_rql_queries.__func__:
+ warn("[3.22] cw_fti_index_rql_queries is replaced by cw_fti_index_rql_limit",
+ DeprecationWarning)
+ for rql in cls.cw_fti_index_rql_queries(req):
+ yield req.execute(rql)
+ return
+ restrictions = ['X is %s' % cls.__regid__]
+ selected = ['X']
+ start = 0
+ for attrschema in sorted(cls.e_schema.indexable_attributes()):
+ varname = attrschema.type.upper()
+ restrictions.append('X %s %s' % (attrschema, varname))
+ selected.append(varname)
+ while True:
+ q_restrictions = restrictions + ['X eid > %s' % start]
+ rset = req.execute('Any %s ORDERBY X LIMIT %s WHERE %s' %
+ (', '.join(selected),
+ limit,
+ ', '.join(q_restrictions)))
+ if rset:
+ start = rset[-1][0]
+ yield rset
+ else:
+ break
+
# meta data api ###########################################################
def dc_title(self):
@@ -134,7 +170,7 @@
return self.dc_title().lower()
value = self.cw_attr_value(rtype)
# do not restrict to `unicode` because Bytes will return a `str` value
- if isinstance(value, basestring):
+ if isinstance(value, string_types):
return self.printable_value(rtype, format='text/plain').lower()
return value
--- a/entities/adapters.py Wed Dec 09 18:42:13 2015 +0100
+++ b/entities/adapters.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,7 +20,7 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from itertools import chain
from warnings import warn
@@ -162,7 +162,7 @@
return words
def merge_weight_dict(maindict, newdict):
- for weight, words in newdict.iteritems():
+ for weight, words in newdict.items():
maindict.setdefault(weight, []).extend(words)
class IDownloadableAdapter(view.EntityAdapter):
@@ -171,23 +171,25 @@
__abstract__ = True
def download_url(self, **kwargs): # XXX not really part of this interface
- """return a URL to download entity's content"""
+ """return a URL to download entity's content
+
+ It should be a unicode object containing url-encoded ASCII."""
raise NotImplementedError
def download_content_type(self):
- """return MIME type of the downloadable content"""
+ """return MIME type (unicode) of the downloadable content"""
raise NotImplementedError
def download_encoding(self):
- """return encoding of the downloadable content"""
+ """return encoding (unicode) of the downloadable content"""
raise NotImplementedError
def download_file_name(self):
- """return file name of the downloadable content"""
+ """return file name (unicode) of the downloadable content"""
raise NotImplementedError
def download_data(self):
- """return actual data of the downloadable content"""
+ """return actual data (bytes) of the downloadable content"""
raise NotImplementedError
# XXX should propose to use two different relations for children/parent
@@ -386,7 +388,7 @@
for rschema, attrschema in eschema.attribute_definitions():
rdef = rschema.rdef(eschema, attrschema)
for constraint in rdef.constraints:
- if cstrname == 'cstr' + md5(eschema.type + rschema.type + constraint.type() + (constraint.serialize() or '')).hexdigest():
+ if cstrname == 'cstr' + md5((eschema.type + rschema.type + constraint.type() + (constraint.serialize() or '')).encode('ascii')).hexdigest():
break
else:
continue
--- a/entities/authobjs.py Wed Dec 09 18:42:13 2015 +0100
+++ b/entities/authobjs.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,6 +19,8 @@
__docformat__ = "restructuredtext en"
+from six import string_types
+
from logilab.common.decorators import cached
from cubicweb import Unauthorized
@@ -126,7 +128,7 @@
:type groups: str or iterable(str)
:param groups: a group name or an iterable on group names
"""
- if isinstance(groups, basestring):
+ if isinstance(groups, string_types):
groups = frozenset((groups,))
elif isinstance(groups, (tuple, list)):
groups = frozenset(groups)
--- a/entities/lib.py Wed Dec 09 18:42:13 2015 +0100
+++ b/entities/lib.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,9 +19,10 @@
__docformat__ = "restructuredtext en"
from warnings import warn
+from datetime import datetime
-from urlparse import urlsplit, urlunsplit
-from datetime import datetime
+from six.moves import range
+from six.moves.urllib.parse import urlsplit, urlunsplit
from logilab.mtconverter import xml_escape
@@ -67,7 +68,7 @@
{'y': self.eid})
if skipeids is None:
skipeids = set()
- for i in xrange(len(rset)):
+ for i in range(len(rset)):
eid = rset[i][0]
if eid in skipeids:
continue
@@ -146,4 +147,3 @@
if date:
return date > self.timestamp
return False
-
--- a/entities/sources.py Wed Dec 09 18:42:13 2015 +0100
+++ b/entities/sources.py Thu Dec 10 12:34:15 2015 +0100
@@ -42,7 +42,7 @@
cfg.update(config)
options = SOURCE_TYPES[self.type].options
sconfig = SourceConfiguration(self._cw.vreg.config, options=options)
- for opt, val in cfg.iteritems():
+ for opt, val in cfg.items():
try:
sconfig.set_option(opt, val)
except OptionError:
--- a/entities/test/unittest_base.py Wed Dec 09 18:42:13 2015 +0100
+++ b/entities/test/unittest_base.py Thu Dec 10 12:34:15 2015 +0100
@@ -21,6 +21,7 @@
from logilab.common.testlib import unittest_main
from logilab.common.decorators import clear_cache
+from logilab.common.registry import yes
from cubicweb.devtools.testlib import CubicWebTC
@@ -60,16 +61,35 @@
# XXX move to yams
self.assertEqual(self.schema['CWUser'].meta_attributes(), {})
self.assertEqual(dict((str(k), v)
- for k, v in self.schema['State'].meta_attributes().iteritems()),
+ for k, v in self.schema['State'].meta_attributes().items()),
{'description_format': ('format', 'description')})
def test_fti_rql_method(self):
+ class EmailAddress(AnyEntity):
+ __regid__ = 'EmailAddress'
+ __select__ = AnyEntity.__select__ & yes(2)
+ @classmethod
+ def cw_fti_index_rql_queries(cls, req):
+ return ['EmailAddress Y']
with self.admin_access.web_request() as req:
+ req.create_entity('EmailAddress', address=u'foo@bar.com')
eclass = self.vreg['etypes'].etype_class('EmailAddress')
+ # deprecated
self.assertEqual(['Any X, ADDRESS, ALIAS WHERE X is EmailAddress, '
'X address ADDRESS, X alias ALIAS'],
eclass.cw_fti_index_rql_queries(req))
+ self.assertEqual(['Any X, ADDRESS, ALIAS ORDERBY X LIMIT 1000 WHERE X is EmailAddress, '
+ 'X address ADDRESS, X alias ALIAS, X eid > 0'],
+ [rset.rql for rset in eclass.cw_fti_index_rql_limit(req)])
+
+ # test backwards compatibility with custom method
+ with self.temporary_appobjects(EmailAddress):
+ self.vreg['etypes'].clear_caches()
+ eclass = self.vreg['etypes'].etype_class('EmailAddress')
+ self.assertEqual(['EmailAddress Y'],
+ [rset.rql for rset in eclass.cw_fti_index_rql_limit(req)])
+
class EmailAddressTC(BaseEntityTC):
--- a/entities/test/unittest_wfobjs.py Wed Dec 09 18:42:13 2015 +0100
+++ b/entities/test/unittest_wfobjs.py Thu Dec 10 12:34:15 2015 +0100
@@ -107,7 +107,7 @@
def setup_database(self):
rschema = self.schema['in_state']
- for rdef in rschema.rdefs.itervalues():
+ for rdef in rschema.rdefs.values():
self.assertEqual(rdef.cardinality, '1*')
with self.admin_access.client_cnx() as cnx:
self.member_eid = self.create_user(cnx, 'member').eid
--- a/entities/wfobjs.py Wed Dec 09 18:42:13 2015 +0100
+++ b/entities/wfobjs.py Thu Dec 10 12:34:15 2015 +0100
@@ -21,9 +21,11 @@
* workflow history (TrInfo)
* adapter for workflowable entities (IWorkflowableAdapter)
"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
+from six import text_type, string_types
from logilab.common.decorators import cached, clear_cache
from logilab.common.deprecation import deprecated
@@ -97,7 +99,7 @@
def transition_by_name(self, trname):
rset = self._cw.execute('Any T, TN WHERE T name TN, T name %(n)s, '
'T transition_of WF, WF eid %(wf)s',
- {'n': unicode(trname), 'wf': self.eid})
+ {'n': text_type(trname), 'wf': self.eid})
if rset:
return rset.get_entity(0, 0)
return None
@@ -114,7 +116,7 @@
def add_state(self, name, initial=False, **kwargs):
"""add a state to this workflow"""
- state = self._cw.create_entity('State', name=unicode(name), **kwargs)
+ state = self._cw.create_entity('State', name=text_type(name), **kwargs)
self._cw.execute('SET S state_of WF WHERE S eid %(s)s, WF eid %(wf)s',
{'s': state.eid, 'wf': self.eid})
if initial:
@@ -126,7 +128,7 @@
def _add_transition(self, trtype, name, fromstates,
requiredgroups=(), conditions=(), **kwargs):
- tr = self._cw.create_entity(trtype, name=unicode(name), **kwargs)
+ tr = self._cw.create_entity(trtype, name=text_type(name), **kwargs)
self._cw.execute('SET T transition_of WF '
'WHERE T eid %(t)s, WF eid %(wf)s',
{'t': tr.eid, 'wf': self.eid})
@@ -224,19 +226,19 @@
matches = user.matching_groups(groups)
if matches:
if DBG:
- print 'may_be_fired: %r may fire: user matches %s' % (self.name, groups)
+ print('may_be_fired: %r may fire: user matches %s' % (self.name, groups))
return matches
if 'owners' in groups and user.owns(eid):
if DBG:
- print 'may_be_fired: %r may fire: user is owner' % self.name
+ print('may_be_fired: %r may fire: user is owner' % self.name)
return True
# check one of the rql expression conditions matches if any
if self.condition:
if DBG:
- print ('my_be_fired: %r: %s' %
- (self.name, [(rqlexpr.expression,
+ print('my_be_fired: %r: %s' %
+ (self.name, [(rqlexpr.expression,
rqlexpr.check_expression(self._cw, eid))
- for rqlexpr in self.condition]))
+ for rqlexpr in self.condition]))
for rqlexpr in self.condition:
if rqlexpr.check_expression(self._cw, eid):
return True
@@ -256,13 +258,13 @@
for gname in requiredgroups:
rset = self._cw.execute('SET T require_group G '
'WHERE T eid %(x)s, G name %(gn)s',
- {'x': self.eid, 'gn': unicode(gname)})
+ {'x': self.eid, 'gn': text_type(gname)})
assert rset, '%s is not a known group' % gname
- if isinstance(conditions, basestring):
+ if isinstance(conditions, string_types):
conditions = (conditions,)
for expr in conditions:
- if isinstance(expr, basestring):
- kwargs = {'expr': unicode(expr)}
+ if isinstance(expr, string_types):
+ kwargs = {'expr': text_type(expr)}
else:
assert isinstance(expr, dict)
kwargs = expr
@@ -414,7 +416,7 @@
"""return the default workflow for entities of this type"""
# XXX CWEType method
wfrset = self._cw.execute('Any WF WHERE ET default_workflow WF, '
- 'ET name %(et)s', {'et': unicode(self.entity.cw_etype)})
+ 'ET name %(et)s', {'et': text_type(self.entity.cw_etype)})
if wfrset:
return wfrset.get_entity(0, 0)
self.warning("can't find any workflow for %s", self.entity.cw_etype)
@@ -479,7 +481,7 @@
'Any T,TT, TN WHERE S allowed_transition T, S eid %(x)s, '
'T type TT, T type %(type)s, '
'T name TN, T transition_of WF, WF eid %(wfeid)s',
- {'x': self.current_state.eid, 'type': unicode(type),
+ {'x': self.current_state.eid, 'type': text_type(type),
'wfeid': self.current_workflow.eid})
for tr in rset.entities():
if tr.may_be_fired(self.entity.eid):
@@ -528,7 +530,7 @@
def _get_transition(self, tr):
assert self.current_workflow
- if isinstance(tr, basestring):
+ if isinstance(tr, string_types):
_tr = self.current_workflow.transition_by_name(tr)
assert _tr is not None, 'not a %s transition: %s' % (
self.__regid__, tr)
@@ -549,7 +551,7 @@
tr = self._get_transition(tr)
if any(tr_ for tr_ in self.possible_transitions()
if tr_.eid == tr.eid):
- self.fire_transition(tr)
+ self.fire_transition(tr, comment, commentformat)
def change_state(self, statename, comment=None, commentformat=None, tr=None):
"""change the entity's state to the given state (name or entity) in
--- a/entity.py Wed Dec 09 18:42:13 2015 +0100
+++ b/entity.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,6 +22,9 @@
from warnings import warn
from functools import partial
+from six import text_type, string_types, integer_types
+from six.moves import range
+
from logilab.common.decorators import cached
from logilab.common.deprecation import deprecated
from logilab.common.registry import yes
@@ -57,7 +60,7 @@
"""return True if value can be used at the end of a Rest URL path"""
if value is None:
return False
- value = unicode(value)
+ value = text_type(value)
# the check for ?, /, & are to prevent problems when running
# behind Apache mod_proxy
if value == u'' or u'?' in value or u'/' in value or u'&' in value:
@@ -105,7 +108,7 @@
"""
st = cstr.snippet_rqlst.copy()
# replace relations in ST by eid infos from linkto where possible
- for (info_rtype, info_role), eids in lt_infos.iteritems():
+ for (info_rtype, info_role), eids in lt_infos.items():
eid = eids[0] # NOTE: we currently assume a pruned lt_info with only 1 eid
for rel in st.iget_nodes(RqlRelation):
targetvar = rel_matches(rel, info_rtype, info_role, evar.name)
@@ -132,7 +135,7 @@
def pruned_lt_info(eschema, lt_infos):
pruned = {}
- for (lt_rtype, lt_role), eids in lt_infos.iteritems():
+ for (lt_rtype, lt_role), eids in lt_infos.items():
# we can only use lt_infos describing relation with a cardinality
# of value 1 towards the linked entity
if not len(eids) == 1:
@@ -144,6 +147,7 @@
pruned[(lt_rtype, lt_role)] = eids
return pruned
+
class Entity(AppObject):
"""an entity instance has e_schema automagically set on
the class and instances has access to their issuing cursor.
@@ -279,7 +283,7 @@
select = Select()
mainvar = select.get_variable(mainvar)
select.add_selected(mainvar)
- elif isinstance(mainvar, basestring):
+ elif isinstance(mainvar, string_types):
assert mainvar in select.defined_vars
mainvar = select.get_variable(mainvar)
# eases string -> syntax tree test transition: please remove once stable
@@ -455,7 +459,7 @@
if len(value) == 0:
continue # avoid crash with empty IN clause
elif len(value) == 1:
- value = iter(value).next()
+ value = next(iter(value))
else:
# prepare IN clause
pendingrels.append( (attr, role, value) )
@@ -530,6 +534,7 @@
def __init__(self, req, rset=None, row=None, col=0):
AppObject.__init__(self, req, rset=rset, row=row, col=col)
self._cw_related_cache = {}
+ self._cw_adapters_cache = {}
if rset is not None:
self.eid = rset[row][col]
else:
@@ -545,12 +550,12 @@
raise NotImplementedError('comparison not implemented for %s' % self.__class__)
def __eq__(self, other):
- if isinstance(self.eid, (int, long)):
+ if isinstance(self.eid, integer_types):
return self.eid == other.eid
return self is other
def __hash__(self):
- if isinstance(self.eid, (int, long)):
+ if isinstance(self.eid, integer_types):
return self.eid
return super(Entity, self).__hash__()
@@ -567,10 +572,7 @@
return None if it can not be adapted.
"""
- try:
- cache = self._cw_adapters_cache
- except AttributeError:
- self._cw_adapters_cache = cache = {}
+ cache = self._cw_adapters_cache
try:
return cache[interface]
except KeyError:
@@ -677,8 +679,8 @@
if path is None:
# fallback url: <base-url>/<eid> url is used as cw entities uri,
# prefer it to <base-url>/<etype>/eid/<eid>
- return unicode(value)
- return '%s/%s' % (path, self._cw.url_quote(value))
+ return text_type(value)
+ return u'%s/%s' % (path, self._cw.url_quote(value))
def cw_attr_metadata(self, attr, metadata):
"""return a metadata for an attribute (None if unspecified)"""
@@ -695,7 +697,7 @@
attr = str(attr)
if value is _marker:
value = getattr(self, attr)
- if isinstance(value, basestring):
+ if isinstance(value, string_types):
value = value.strip()
if value is None or value == '': # don't use "not", 0 is an acceptable value
return u''
@@ -849,7 +851,7 @@
if attributes is None:
self._cw_completed = True
varmaker = rqlvar_maker()
- V = varmaker.next()
+ V = next(varmaker)
rql = ['WHERE %s eid %%(x)s' % V]
selected = []
for attr in (attributes or self._cw_to_complete_attributes(skip_bytes, skip_pwd)):
@@ -857,7 +859,7 @@
if attr in self.cw_attr_cache:
continue
# case where attribute must be completed, but is not yet in entity
- var = varmaker.next()
+ var = next(varmaker)
rql.append('%s %s %s' % (V, attr, var))
selected.append((attr, var))
# +1 since this doesn't include the main variable
@@ -876,7 +878,7 @@
# * user has read perm on the relation and on the target entity
assert rschema.inlined
assert role == 'subject'
- var = varmaker.next()
+ var = next(varmaker)
# keep outer join anyway, we don't want .complete to crash on
# missing mandatory relation (see #1058267)
rql.append('%s %s %s?' % (V, rtype, var))
@@ -892,10 +894,10 @@
raise Exception('unable to fetch attributes for entity with eid %s'
% self.eid)
# handle attributes
- for i in xrange(1, lastattr):
+ for i in range(1, lastattr):
self.cw_attr_cache[str(selected[i-1][0])] = rset[i]
# handle relations
- for i in xrange(lastattr, len(rset)):
+ for i in range(lastattr, len(rset)):
rtype, role = selected[i-1][0]
value = rset[i]
if value is None:
@@ -1145,9 +1147,7 @@
self._cw.vreg.solutions(self._cw, select, args)
# insert RQL expressions for schema constraints into the rql syntax tree
if vocabconstraints:
- # RQLConstraint is a subclass for RQLVocabularyConstraint, so they
- # will be included as well
- cstrcls = RQLVocabularyConstraint
+ cstrcls = (RQLVocabularyConstraint, RQLConstraint)
else:
cstrcls = RQLConstraint
lt_infos = pruned_lt_info(self.e_schema, lt_infos or {})
@@ -1236,8 +1236,8 @@
no relation is given
"""
if rtype is None:
- self._cw_related_cache = {}
- self._cw_adapters_cache = {}
+ self._cw_related_cache.clear()
+ self._cw_adapters_cache.clear()
else:
assert role
self._cw_related_cache.pop('%s_%s' % (rtype, role), None)
--- a/etwist/__init__.py Wed Dec 09 18:42:13 2015 +0100
+++ b/etwist/__init__.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,4 +18,3 @@
""" CW - nevow/twisted client
"""
-
--- a/etwist/request.py Wed Dec 09 18:42:13 2015 +0100
+++ b/etwist/request.py Thu Dec 10 12:34:15 2015 +0100
@@ -31,7 +31,7 @@
self._twreq = req
super(CubicWebTwistedRequestAdapter, self).__init__(
vreg, https, req.args, headers=req.received_headers)
- for key, name_stream_list in req.files.iteritems():
+ for key, name_stream_list in req.files.items():
for name, stream in name_stream_list:
if name is not None:
name = unicode(name, self.encoding)
--- a/etwist/server.py Wed Dec 09 18:42:13 2015 +0100
+++ b/etwist/server.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,8 +22,10 @@
import select
import traceback
import threading
-from urlparse import urlsplit, urlunsplit
from cgi import FieldStorage, parse_header
+
+from six.moves.urllib.parse import urlsplit, urlunsplit
+
from cubicweb.statsd_logger import statsd_timeit
from twisted.internet import reactor, task, threads
--- a/etwist/service.py Wed Dec 09 18:42:13 2015 +0100
+++ b/etwist/service.py Thu Dec 10 12:34:15 2015 +0100
@@ -15,6 +15,8 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+from __future__ import print_function
+
import os
import sys
@@ -22,7 +24,7 @@
import win32serviceutil
import win32service
except ImportError:
- print 'Win32 extensions for Python are likely not installed.'
+ print('Win32 extensions for Python are likely not installed.')
sys.exit(3)
from os.path import join
--- a/etwist/twctl.py Wed Dec 09 18:42:13 2015 +0100
+++ b/etwist/twctl.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,10 +17,6 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""cubicweb-clt handlers for twisted"""
-from os.path import join
-
-from logilab.common.shellutils import rm
-
from cubicweb.toolsutils import CommandHandler
from cubicweb.web.webctl import WebCreateHandler, WebUpgradeHandler
@@ -36,9 +32,6 @@
def start_server(self, config):
from cubicweb.etwist import server
- config.info('clear ui caches')
- for cachedir in ('uicache', 'uicachehttps'):
- rm(join(config.appdatahome, cachedir, '*'))
return server.run(config)
class TWStopHandler(CommandHandler):
--- a/ext/rest.py Wed Dec 09 18:42:13 2015 +0100
+++ b/ext/rest.py Thu Dec 10 12:34:15 2015 +0100
@@ -38,7 +38,9 @@
from itertools import chain
from logging import getLogger
from os.path import join
-from urlparse import urlsplit
+
+from six import text_type
+from six.moves.urllib.parse import urlsplit
from docutils import statemachine, nodes, utils, io
from docutils.core import Publisher
@@ -172,7 +174,7 @@
rql = params['rql']
if vid is None:
vid = params.get('vid')
- except (ValueError, KeyError), exc:
+ except (ValueError, KeyError) as exc:
msg = inliner.reporter.error('Could not parse bookmark path %s [%s].'
% (bookmark.path, exc), line=lineno)
prb = inliner.problematic(rawtext, rawtext, msg)
@@ -186,7 +188,7 @@
vid = 'noresult'
view = _cw.vreg['views'].select(vid, _cw, rset=rset)
content = view.render()
- except Exception, exc:
+ except Exception as exc:
content = 'An error occurred while interpreting directive bookmark: %r' % exc
set_classes(options)
return [nodes.raw('', content, format='html')], []
@@ -401,7 +403,7 @@
the data formatted as HTML or the original data if an error occurred
"""
req = context._cw
- if isinstance(data, unicode):
+ if isinstance(data, text_type):
encoding = 'unicode'
# remove unprintable characters unauthorized in xml
data = data.translate(ESC_UCAR_TABLE)
@@ -446,8 +448,8 @@
return res
except BaseException:
LOGGER.exception('error while publishing ReST text')
- if not isinstance(data, unicode):
- data = unicode(data, encoding, 'replace')
+ if not isinstance(data, text_type):
+ data = text_type(data, encoding, 'replace')
return xml_escape(req._('error while publishing ReST text')
+ '\n\n' + data)
--- a/ext/tal.py Wed Dec 09 18:42:13 2015 +0100
+++ b/ext/tal.py Thu Dec 10 12:34:15 2015 +0100
@@ -184,7 +184,10 @@
interpreter.execute(self)
except UnicodeError as unierror:
LOGGER.exception(str(unierror))
- raise simpleTALES.ContextContentException("found non-unicode %r string in Context!" % unierror.args[1]), None, sys.exc_info()[-1]
+ exc = simpleTALES.ContextContentException(
+ "found non-unicode %r string in Context!" % unierror.args[1])
+ exc.__traceback__ = sys.exc_info()[-1]
+ raise exc
def compile_template(template):
@@ -203,7 +206,7 @@
:type filepath: str
:param template: path of the file to compile
"""
- fp = file(filepath)
+ fp = open(filepath)
file_content = unicode(fp.read()) # template file should be pure ASCII
fp.close()
return compile_template(file_content)
@@ -232,7 +235,8 @@
result = eval(expr, globals, locals)
except Exception as ex:
ex = ex.__class__('in %r: %s' % (expr, ex))
- raise ex, None, sys.exc_info()[-1]
+ ex.__traceback__ = sys.exc_info()[-1]
+ raise ex
if (isinstance (result, simpleTALES.ContextVariable)):
return result.value()
return result
--- a/ext/test/data/views.py Wed Dec 09 18:42:13 2015 +0100
+++ b/ext/test/data/views.py Thu Dec 10 12:34:15 2015 +0100
@@ -21,4 +21,3 @@
class CustomRsetTableView(tableview.RsetTableView):
__regid__ = 'mytable'
-
--- a/ext/test/unittest_rest.py Wed Dec 09 18:42:13 2015 +0100
+++ b/ext/test/unittest_rest.py Thu Dec 10 12:34:15 2015 +0100
@@ -15,6 +15,8 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+from six import PY3
+
from logilab.common.testlib import unittest_main
from cubicweb.devtools.testlib import CubicWebTC
@@ -87,7 +89,9 @@
context = self.context(req)
out = rest_publish(context, ':rql:`Any X WHERE X is CWUser:toto`')
self.assertTrue(out.startswith("<p>an error occurred while interpreting this "
- "rql directive: ObjectNotFound(u'toto',)</p>"))
+ "rql directive: ObjectNotFound(%s'toto',)</p>" %
+ ('' if PY3 else 'u')),
+ out)
def test_rql_role_without_vid(self):
with self.admin_access.web_request() as req:
@@ -229,7 +233,7 @@
%(rql)s
""" % {'rql': rql,
'colvids': ', '.join(["%d=%s" % (k, v)
- for k, v in colvids.iteritems()])
+ for k, v in colvids.items()])
})
view = self.vreg['views'].select('table', req, rset=req.execute(rql))
view.cellvids = colvids
--- a/gettext.py Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,795 +0,0 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
-#
-# This file is part of CubicWeb.
-#
-# CubicWeb is free software: you can redistribute it and/or modify it under the
-# terms of the GNU Lesser General Public License as published by the Free
-# Software Foundation, either version 2.1 of the License, or (at your option)
-# any later version.
-#
-# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Lesser General Public License along
-# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""Internationalization and localization support.
-
-This module provides internationalization (I18N) and localization (L10N)
-support for your Python programs by providing an interface to the GNU gettext
-message catalog library.
-
-I18N refers to the operation by which a program is made aware of multiple
-languages. L10N refers to the adaptation of your program, once
-internationalized, to the local language and cultural habits.
-
-"""
-
-# This module represents the integration of work, contributions, feedback, and
-# suggestions from the following people:
-#
-# Martin von Loewis, who wrote the initial implementation of the underlying
-# C-based libintlmodule (later renamed _gettext), along with a skeletal
-# gettext.py implementation.
-#
-# Peter Funk, who wrote fintl.py, a fairly complete wrapper around intlmodule,
-# which also included a pure-Python implementation to read .mo files if
-# intlmodule wasn't available.
-#
-# James Henstridge, who also wrote a gettext.py module, which has some
-# interesting, but currently unsupported experimental features: the notion of
-# a Catalog class and instances, and the ability to add to a catalog file via
-# a Python API.
-#
-# Barry Warsaw integrated these modules, wrote the .install() API and code,
-# and conformed all C and Python code to Python's coding standards.
-#
-# Francois Pinard and Marc-Andre Lemburg also contributed valuably to this
-# module.
-#
-# J. David Ibanez implemented plural forms. Bruno Haible fixed some bugs.
-#
-# TODO:
-# - Lazy loading of .mo files. Currently the entire catalog is loaded into
-# memory, but that's probably bad for large translated programs. Instead,
-# the lexical sort of original strings in GNU .mo files should be exploited
-# to do binary searches and lazy initializations. Or you might want to use
-# the undocumented double-hash algorithm for .mo files with hash tables, but
-# you'll need to study the GNU gettext code to do this.
-#
-# - Support Solaris .mo file formats. Unfortunately, we've been unable to
-# find this format documented anywhere.
-
-
-import locale, copy, os, re, struct, sys
-from errno import ENOENT
-
-
-__all__ = ['NullTranslations', 'GNUTranslations', 'Catalog',
- 'find', 'translation', 'install', 'textdomain', 'bindtextdomain',
- 'dgettext', 'dngettext', 'gettext', 'ngettext',
- ]
-
-_default_localedir = os.path.join(sys.prefix, 'share', 'locale')
-
-
-def test(condition, true, false):
- """
- Implements the C expression:
-
- condition ? true : false
-
- Required to correctly interpret plural forms.
- """
- if condition:
- return true
- else:
- return false
-
-
-def c2py(plural):
- """Gets a C expression as used in PO files for plural forms and returns a
- Python lambda function that implements an equivalent expression.
- """
- # Security check, allow only the "n" identifier
- try:
- from cStringIO import StringIO
- except ImportError:
- from StringIO import StringIO
- import token, tokenize
- tokens = tokenize.generate_tokens(StringIO(plural).readline)
- try:
- danger = [x for x in tokens if x[0] == token.NAME and x[1] != 'n']
- except tokenize.TokenError:
- raise ValueError, \
- 'plural forms expression error, maybe unbalanced parenthesis'
- else:
- if danger:
- raise ValueError, 'plural forms expression could be dangerous'
-
- # Replace some C operators by their Python equivalents
- plural = plural.replace('&&', ' and ')
- plural = plural.replace('||', ' or ')
-
- expr = re.compile(r'\!([^=])')
- plural = expr.sub(' not \\1', plural)
-
- # Regular expression and replacement function used to transform
- # "a?b:c" to "test(a,b,c)".
- expr = re.compile(r'(.*?)\?(.*?):(.*)')
- def repl(x):
- return "test(%s, %s, %s)" % (x.group(1), x.group(2),
- expr.sub(repl, x.group(3)))
-
- # Code to transform the plural expression, taking care of parentheses
- stack = ['']
- for c in plural:
- if c == '(':
- stack.append('')
- elif c == ')':
- if len(stack) == 1:
- # Actually, we never reach this code, because unbalanced
- # parentheses get caught in the security check at the
- # beginning.
- raise ValueError, 'unbalanced parenthesis in plural form'
- s = expr.sub(repl, stack.pop())
- stack[-1] += '(%s)' % s
- else:
- stack[-1] += c
- plural = expr.sub(repl, stack.pop())
-
- return eval('lambda n: int(%s)' % plural)
-
-
-
-def _expand_lang(locale):
- from locale import normalize
- locale = normalize(locale)
- COMPONENT_CODESET = 1 << 0
- COMPONENT_TERRITORY = 1 << 1
- COMPONENT_MODIFIER = 1 << 2
- # split up the locale into its base components
- mask = 0
- pos = locale.find('@')
- if pos >= 0:
- modifier = locale[pos:]
- locale = locale[:pos]
- mask |= COMPONENT_MODIFIER
- else:
- modifier = ''
- pos = locale.find('.')
- if pos >= 0:
- codeset = locale[pos:]
- locale = locale[:pos]
- mask |= COMPONENT_CODESET
- else:
- codeset = ''
- pos = locale.find('_')
- if pos >= 0:
- territory = locale[pos:]
- locale = locale[:pos]
- mask |= COMPONENT_TERRITORY
- else:
- territory = ''
- language = locale
- ret = []
- for i in range(mask+1):
- if not (i & ~mask): # if all components for this combo exist ...
- val = language
- if i & COMPONENT_TERRITORY: val += territory
- if i & COMPONENT_CODESET: val += codeset
- if i & COMPONENT_MODIFIER: val += modifier
- ret.append(val)
- ret.reverse()
- return ret
-
-
-
-class NullTranslations:
- def __init__(self, fp=None):
- self._info = {}
- self._charset = None
- self._output_charset = None
- self._fallback = None
- if fp is not None:
- self._parse(fp)
-
- def _parse(self, fp):
- pass
-
- def add_fallback(self, fallback):
- if self._fallback:
- self._fallback.add_fallback(fallback)
- else:
- self._fallback = fallback
-
- def gettext(self, message):
- if self._fallback:
- return self._fallback.gettext(message)
- return message
-
- def pgettext(self, context, message):
- if self._fallback:
- return self._fallback.pgettext(context, message)
- return message
-
- def lgettext(self, message):
- if self._fallback:
- return self._fallback.lgettext(message)
- return message
-
- def lpgettext(self, context, message):
- if self._fallback:
- return self._fallback.lpgettext(context, message)
- return message
-
- def ngettext(self, msgid1, msgid2, n):
- if self._fallback:
- return self._fallback.ngettext(msgid1, msgid2, n)
- if n == 1:
- return msgid1
- else:
- return msgid2
-
- def npgettext(self, context, msgid1, msgid2, n):
- if self._fallback:
- return self._fallback.npgettext(context, msgid1, msgid2, n)
- if n == 1:
- return msgid1
- else:
- return msgid2
-
- def lngettext(self, msgid1, msgid2, n):
- if self._fallback:
- return self._fallback.lngettext(msgid1, msgid2, n)
- if n == 1:
- return msgid1
- else:
- return msgid2
-
- def lnpgettext(self, context, msgid1, msgid2, n):
- if self._fallback:
- return self._fallback.lnpgettext(context, msgid1, msgid2, n)
- if n == 1:
- return msgid1
- else:
- return msgid2
-
- def ugettext(self, message):
- if self._fallback:
- return self._fallback.ugettext(message)
- return unicode(message)
-
- def upgettext(self, context, message):
- if self._fallback:
- return self._fallback.upgettext(context, message)
- return unicode(message)
-
- def ungettext(self, msgid1, msgid2, n):
- if self._fallback:
- return self._fallback.ungettext(msgid1, msgid2, n)
- if n == 1:
- return unicode(msgid1)
- else:
- return unicode(msgid2)
-
- def unpgettext(self, context, msgid1, msgid2, n):
- if self._fallback:
- return self._fallback.unpgettext(context, msgid1, msgid2, n)
- if n == 1:
- return unicode(msgid1)
- else:
- return unicode(msgid2)
-
- def info(self):
- return self._info
-
- def charset(self):
- return self._charset
-
- def output_charset(self):
- return self._output_charset
-
- def set_output_charset(self, charset):
- self._output_charset = charset
-
- def install(self, unicode=False, names=None):
- import __builtin__
- __builtin__.__dict__['_'] = unicode and self.ugettext or self.gettext
- if hasattr(names, "__contains__"):
- if "gettext" in names:
- __builtin__.__dict__['gettext'] = __builtin__.__dict__['_']
- if "pgettext" in names:
- __builtin__.__dict__['pgettext'] = (unicode and self.upgettext
- or self.pgettext)
- if "ngettext" in names:
- __builtin__.__dict__['ngettext'] = (unicode and self.ungettext
- or self.ngettext)
- if "npgettext" in names:
- __builtin__.__dict__['npgettext'] = \
- (unicode and self.unpgettext or self.npgettext)
- if "lgettext" in names:
- __builtin__.__dict__['lgettext'] = self.lgettext
- if "lpgettext" in names:
- __builtin__.__dict__['lpgettext'] = self.lpgettext
- if "lngettext" in names:
- __builtin__.__dict__['lngettext'] = self.lngettext
- if "lnpgettext" in names:
- __builtin__.__dict__['lnpgettext'] = self.lnpgettext
-
-
-class GNUTranslations(NullTranslations):
- # Magic number of .mo files
- LE_MAGIC = 0x950412deL
- BE_MAGIC = 0xde120495L
-
- # The encoding of a msgctxt and a msgid in a .mo file is
- # msgctxt + "\x04" + msgid (gettext version >= 0.15)
- CONTEXT_ENCODING = "%s\x04%s"
-
- def _parse(self, fp):
- """Override this method to support alternative .mo formats."""
- unpack = struct.unpack
- filename = getattr(fp, 'name', '')
- # Parse the .mo file header, which consists of 5 little endian 32
- # bit words.
- self._catalog = catalog = {}
- self.plural = lambda n: int(n != 1) # germanic plural by default
- buf = fp.read()
- buflen = len(buf)
- # Are we big endian or little endian?
- magic = unpack('<I', buf[:4])[0]
- if magic == self.LE_MAGIC:
- version, msgcount, masteridx, transidx = unpack('<4I', buf[4:20])
- ii = '<II'
- elif magic == self.BE_MAGIC:
- version, msgcount, masteridx, transidx = unpack('>4I', buf[4:20])
- ii = '>II'
- else:
- raise IOError(0, 'Bad magic number', filename)
- # Now put all messages from the .mo file buffer into the catalog
- # dictionary.
- for i in xrange(0, msgcount):
- mlen, moff = unpack(ii, buf[masteridx:masteridx+8])
- mend = moff + mlen
- tlen, toff = unpack(ii, buf[transidx:transidx+8])
- tend = toff + tlen
- if mend < buflen and tend < buflen:
- msg = buf[moff:mend]
- tmsg = buf[toff:tend]
- else:
- raise IOError(0, 'File is corrupt', filename)
- # See if we're looking at GNU .mo conventions for metadata
- if mlen == 0:
- # Catalog description
- lastk = k = None
- for item in tmsg.splitlines():
- item = item.strip()
- if not item:
- continue
- if ':' in item:
- k, v = item.split(':', 1)
- k = k.strip().lower()
- v = v.strip()
- self._info[k] = v
- lastk = k
- elif lastk:
- self._info[lastk] += '\n' + item
- if k == 'content-type':
- self._charset = v.split('charset=')[1]
- elif k == 'plural-forms':
- v = v.split(';')
- plural = v[1].split('plural=')[1]
- self.plural = c2py(plural)
- # Note: we unconditionally convert both msgids and msgstrs to
- # Unicode using the character encoding specified in the charset
- # parameter of the Content-Type header. The gettext documentation
- # strongly encourages msgids to be us-ascii, but some appliations
- # require alternative encodings (e.g. Zope's ZCML and ZPT). For
- # traditional gettext applications, the msgid conversion will
- # cause no problems since us-ascii should always be a subset of
- # the charset encoding. We may want to fall back to 8-bit msgids
- # if the Unicode conversion fails.
- if '\x00' in msg:
- # Plural forms
- msgid1, msgid2 = msg.split('\x00')
- tmsg = tmsg.split('\x00')
- if self._charset:
- msgid1 = unicode(msgid1, self._charset)
- tmsg = [unicode(x, self._charset) for x in tmsg]
- for i in range(len(tmsg)):
- catalog[(msgid1, i)] = tmsg[i]
- else:
- if self._charset:
- msg = unicode(msg, self._charset)
- tmsg = unicode(tmsg, self._charset)
- catalog[msg] = tmsg
- # advance to next entry in the seek tables
- masteridx += 8
- transidx += 8
-
- def gettext(self, message):
- missing = object()
- tmsg = self._catalog.get(message, missing)
- if tmsg is missing:
- if self._fallback:
- return self._fallback.gettext(message)
- return message
- # Encode the Unicode tmsg back to an 8-bit string, if possible
- if self._output_charset:
- return tmsg.encode(self._output_charset)
- elif self._charset:
- return tmsg.encode(self._charset)
- return tmsg
-
- def pgettext(self, context, message):
- ctxt_msg_id = self.CONTEXT_ENCODING % (context, message)
- missing = object()
- tmsg = self._catalog.get(ctxt_msg_id, missing)
- if tmsg is missing:
- if self._fallback:
- return self._fallback.pgettext(context, message)
- return message
- # Encode the Unicode tmsg back to an 8-bit string, if possible
- if self._output_charset:
- return tmsg.encode(self._output_charset)
- elif self._charset:
- return tmsg.encode(self._charset)
- return tmsg
-
- def lgettext(self, message):
- missing = object()
- tmsg = self._catalog.get(message, missing)
- if tmsg is missing:
- if self._fallback:
- return self._fallback.lgettext(message)
- return message
- if self._output_charset:
- return tmsg.encode(self._output_charset)
- return tmsg.encode(locale.getpreferredencoding())
-
- def lpgettext(self, context, message):
- ctxt_msg_id = self.CONTEXT_ENCODING % (context, message)
- missing = object()
- tmsg = self._catalog.get(ctxt_msg_id, missing)
- if tmsg is missing:
- if self._fallback:
- return self._fallback.lpgettext(context, message)
- return message
- if self._output_charset:
- return tmsg.encode(self._output_charset)
- return tmsg.encode(locale.getpreferredencoding())
-
- def ngettext(self, msgid1, msgid2, n):
- try:
- tmsg = self._catalog[(msgid1, self.plural(n))]
- if self._output_charset:
- return tmsg.encode(self._output_charset)
- elif self._charset:
- return tmsg.encode(self._charset)
- return tmsg
- except KeyError:
- if self._fallback:
- return self._fallback.ngettext(msgid1, msgid2, n)
- if n == 1:
- return msgid1
- else:
- return msgid2
-
- def npgettext(self, context, msgid1, msgid2, n):
- ctxt_msg_id = self.CONTEXT_ENCODING % (context, msgid1)
- try:
- tmsg = self._catalog[(ctxt_msg_id, self.plural(n))]
- if self._output_charset:
- return tmsg.encode(self._output_charset)
- elif self._charset:
- return tmsg.encode(self._charset)
- return tmsg
- except KeyError:
- if self._fallback:
- return self._fallback.npgettext(context, msgid1, msgid2, n)
- if n == 1:
- return msgid1
- else:
- return msgid2
-
- def lngettext(self, msgid1, msgid2, n):
- try:
- tmsg = self._catalog[(msgid1, self.plural(n))]
- if self._output_charset:
- return tmsg.encode(self._output_charset)
- return tmsg.encode(locale.getpreferredencoding())
- except KeyError:
- if self._fallback:
- return self._fallback.lngettext(msgid1, msgid2, n)
- if n == 1:
- return msgid1
- else:
- return msgid2
-
- def lnpgettext(self, context, msgid1, msgid2, n):
- ctxt_msg_id = self.CONTEXT_ENCODING % (context, msgid1)
- try:
- tmsg = self._catalog[(ctxt_msg_id, self.plural(n))]
- if self._output_charset:
- return tmsg.encode(self._output_charset)
- return tmsg.encode(locale.getpreferredencoding())
- except KeyError:
- if self._fallback:
- return self._fallback.lnpgettext(context, msgid1, msgid2, n)
- if n == 1:
- return msgid1
- else:
- return msgid2
-
- def ugettext(self, message):
- missing = object()
- tmsg = self._catalog.get(message, missing)
- if tmsg is missing:
- if self._fallback:
- return self._fallback.ugettext(message)
- return unicode(message)
- return tmsg
-
- def upgettext(self, context, message):
- ctxt_message_id = self.CONTEXT_ENCODING % (context, message)
- missing = object()
- tmsg = self._catalog.get(ctxt_message_id, missing)
- if tmsg is missing:
- # XXX logilab patch for compat w/ catalog generated by cw < 3.5
- return self.ugettext(message)
- if self._fallback:
- return self._fallback.upgettext(context, message)
- return unicode(message)
- return tmsg
-
- def ungettext(self, msgid1, msgid2, n):
- try:
- tmsg = self._catalog[(msgid1, self.plural(n))]
- except KeyError:
- if self._fallback:
- return self._fallback.ungettext(msgid1, msgid2, n)
- if n == 1:
- tmsg = unicode(msgid1)
- else:
- tmsg = unicode(msgid2)
- return tmsg
-
- def unpgettext(self, context, msgid1, msgid2, n):
- ctxt_message_id = self.CONTEXT_ENCODING % (context, msgid1)
- try:
- tmsg = self._catalog[(ctxt_message_id, self.plural(n))]
- except KeyError:
- if self._fallback:
- return self._fallback.unpgettext(context, msgid1, msgid2, n)
- if n == 1:
- tmsg = unicode(msgid1)
- else:
- tmsg = unicode(msgid2)
- return tmsg
-
-
-# Locate a .mo file using the gettext strategy
-def find(domain, localedir=None, languages=None, all=0):
- # Get some reasonable defaults for arguments that were not supplied
- if localedir is None:
- localedir = _default_localedir
- if languages is None:
- languages = []
- for envar in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'):
- val = os.environ.get(envar)
- if val:
- languages = val.split(':')
- break
- if 'C' not in languages:
- languages.append('C')
- # now normalize and expand the languages
- nelangs = []
- for lang in languages:
- for nelang in _expand_lang(lang):
- if nelang not in nelangs:
- nelangs.append(nelang)
- # select a language
- if all:
- result = []
- else:
- result = None
- for lang in nelangs:
- if lang == 'C':
- break
- mofile = os.path.join(localedir, lang, 'LC_MESSAGES', '%s.mo' % domain)
- if os.path.exists(mofile):
- if all:
- result.append(mofile)
- else:
- return mofile
- return result
-
-
-
-# a mapping between absolute .mo file path and Translation object
-_translations = {}
-
-def translation(domain, localedir=None, languages=None,
- class_=None, fallback=False, codeset=None):
- if class_ is None:
- class_ = GNUTranslations
- mofiles = find(domain, localedir, languages, all=1)
- if not mofiles:
- if fallback:
- return NullTranslations()
- raise IOError(ENOENT, 'No translation file found for domain', domain)
- # TBD: do we need to worry about the file pointer getting collected?
- # Avoid opening, reading, and parsing the .mo file after it's been done
- # once.
- result = None
- for mofile in mofiles:
- key = os.path.abspath(mofile)
- t = _translations.get(key)
- if t is None:
- t = _translations.setdefault(key, class_(open(mofile, 'rb')))
- # Copy the translation object to allow setting fallbacks and
- # output charset. All other instance data is shared with the
- # cached object.
- t = copy.copy(t)
- if codeset:
- t.set_output_charset(codeset)
- if result is None:
- result = t
- else:
- result.add_fallback(t)
- return result
-
-
-def install(domain, localedir=None, unicode=False, codeset=None, names=None):
- t = translation(domain, localedir, fallback=True, codeset=codeset)
- t.install(unicode, names)
-
-
-
-# a mapping b/w domains and locale directories
-_localedirs = {}
-# a mapping b/w domains and codesets
-_localecodesets = {}
-# current global domain, `messages' used for compatibility w/ GNU gettext
-_current_domain = 'messages'
-
-
-def textdomain(domain=None):
- global _current_domain
- if domain is not None:
- _current_domain = domain
- return _current_domain
-
-
-def bindtextdomain(domain, localedir=None):
- global _localedirs
- if localedir is not None:
- _localedirs[domain] = localedir
- return _localedirs.get(domain, _default_localedir)
-
-
-def bind_textdomain_codeset(domain, codeset=None):
- global _localecodesets
- if codeset is not None:
- _localecodesets[domain] = codeset
- return _localecodesets.get(domain)
-
-
-def dgettext(domain, message):
- try:
- t = translation(domain, _localedirs.get(domain, None),
- codeset=_localecodesets.get(domain))
- except IOError:
- return message
- return t.gettext(message)
-
-def dpgettext(domain, context, message):
- try:
- t = translation(domain, _localedirs.get(domain, None),
- codeset=_localecodesets.get(domain))
- except IOError:
- return message
- return t.pgettext(context, message)
-
-def ldgettext(domain, message):
- try:
- t = translation(domain, _localedirs.get(domain, None),
- codeset=_localecodesets.get(domain))
- except IOError:
- return message
- return t.lgettext(message)
-
-def ldpgettext(domain, context, message):
- try:
- t = translation(domain, _localedirs.get(domain, None),
- codeset=_localecodesets.get(domain))
- except IOError:
- return message
- return t.lpgettext(context, message)
-
-def dngettext(domain, msgid1, msgid2, n):
- try:
- t = translation(domain, _localedirs.get(domain, None),
- codeset=_localecodesets.get(domain))
- except IOError:
- if n == 1:
- return msgid1
- else:
- return msgid2
- return t.ngettext(msgid1, msgid2, n)
-
-def dnpgettext(domain, context, msgid1, msgid2, n):
- try:
- t = translation(domain, _localedirs.get(domain, None),
- codeset=_localecodesets.get(domain))
- except IOError:
- if n == 1:
- return msgid1
- else:
- return msgid2
- return t.npgettext(context, msgid1, msgid2, n)
-
-def ldngettext(domain, msgid1, msgid2, n):
- try:
- t = translation(domain, _localedirs.get(domain, None),
- codeset=_localecodesets.get(domain))
- except IOError:
- if n == 1:
- return msgid1
- else:
- return msgid2
- return t.lngettext(msgid1, msgid2, n)
-
-def ldnpgettext(domain, context, msgid1, msgid2, n):
- try:
- t = translation(domain, _localedirs.get(domain, None),
- codeset=_localecodesets.get(domain))
- except IOError:
- if n == 1:
- return msgid1
- else:
- return msgid2
- return t.lnpgettext(context, msgid1, msgid2, n)
-
-def gettext(message):
- return dgettext(_current_domain, message)
-
-def pgettext(context, message):
- return dpgettext(_current_domain, context, message)
-
-def lgettext(message):
- return ldgettext(_current_domain, message)
-
-def lpgettext(context, message):
- return ldpgettext(_current_domain, context, message)
-
-def ngettext(msgid1, msgid2, n):
- return dngettext(_current_domain, msgid1, msgid2, n)
-
-def npgettext(context, msgid1, msgid2, n):
- return dnpgettext(_current_domain, context, msgid1, msgid2, n)
-
-def lngettext(msgid1, msgid2, n):
- return ldngettext(_current_domain, msgid1, msgid2, n)
-
-def lnpgettext(context, msgid1, msgid2, n):
- return ldnpgettext(_current_domain, context, msgid1, msgid2, n)
-
-# dcgettext() has been deemed unnecessary and is not implemented.
-
-# James Henstridge's Catalog constructor from GNOME gettext. Documented usage
-# was:
-#
-# import gettext
-# cat = gettext.Catalog(PACKAGE, localedir=LOCALEDIR)
-# _ = cat.gettext
-# print _('Hello World')
-
-# The resulting catalog object currently don't support access through a
-# dictionary API, which was supported (but apparently unused) in GNOME
-# gettext.
-
-Catalog = translation
--- a/hooks/__init__.py Wed Dec 09 18:42:13 2015 +0100
+++ b/hooks/__init__.py Thu Dec 10 12:34:15 2015 +0100
@@ -52,7 +52,7 @@
def update_feeds(repo):
# take a list to avoid iterating on a dictionary whose size may
# change
- for uri, source in list(repo.sources_by_uri.iteritems()):
+ for uri, source in list(repo.sources_by_uri.items()):
if (uri == 'system'
or not repo.config.source_enabled(source)
or not source.config['synchronize']):
@@ -72,7 +72,7 @@
def __call__(self):
def expire_dataimports(repo=self.repo):
- for uri, source in repo.sources_by_uri.iteritems():
+ for uri, source in repo.sources_by_uri.items():
if (uri == 'system'
or not repo.config.source_enabled(source)):
continue
--- a/hooks/integrity.py Wed Dec 09 18:42:13 2015 +0100
+++ b/hooks/integrity.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,10 +20,12 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from threading import Lock
+from six import text_type
+
from cubicweb import validation_error, neg_role
from cubicweb.schema import (META_RTYPES, WORKFLOW_RTYPES,
RQLConstraint, RQLUniqueConstraint)
@@ -45,7 +47,7 @@
This lock used to avoid potential integrity pb when checking
RQLUniqueConstraint in two different transactions, as explained in
- http://intranet.logilab.fr/jpl/ticket/36564
+ https://extranet.logilab.fr/3577926
"""
if 'uniquecstrholder' in cnx.transaction_data:
return
@@ -109,9 +111,10 @@
category = 'integrity'
-class EnsureSymmetricRelationsAdd(hook.Hook):
+class _EnsureSymmetricRelationsAdd(hook.Hook):
""" ensure X r Y => Y r X iff r is symmetric """
__regid__ = 'cw.add_ensure_symmetry'
+ __abstract__ = True
category = 'activeintegrity'
events = ('after_add_relation',)
# __select__ is set in the registration callback
@@ -121,9 +124,10 @@
self.rtype, self.eidfrom)
-class EnsureSymmetricRelationsDelete(hook.Hook):
+class _EnsureSymmetricRelationsDelete(hook.Hook):
""" ensure X r Y => Y r X iff r is symmetric """
__regid__ = 'cw.delete_ensure_symmetry'
+ __abstract__ = True
category = 'activeintegrity'
events = ('after_delete_relation',)
# __select__ is set in the registration callback
@@ -247,7 +251,7 @@
def __call__(self):
entity = self.entity
eschema = entity.e_schema
- for attr, val in entity.cw_edited.iteritems():
+ for attr, val in entity.cw_edited.items():
if eschema.subjrels[attr].final and eschema.has_unique_values(attr):
if val is None:
continue
@@ -286,13 +290,13 @@
entity = self.entity
metaattrs = entity.e_schema.meta_attributes()
edited = entity.cw_edited
- for metaattr, (metadata, attr) in metaattrs.iteritems():
+ for metaattr, (metadata, attr) in metaattrs.items():
if metadata == 'format' and attr in edited:
try:
value = edited[attr]
except KeyError:
continue # no text to tidy
- if isinstance(value, unicode): # filter out None and Binary
+ if isinstance(value, text_type): # filter out None and Binary
if getattr(entity, str(metaattr)) == 'text/html':
edited[attr] = soup2xhtml(value, self._cw.encoding)
@@ -335,6 +339,9 @@
vreg.register_all(globals().values(), __name__)
symmetric_rtypes = [rschema.type for rschema in vreg.schema.relations()
if rschema.symmetric]
- EnsureSymmetricRelationsAdd.__select__ = hook.Hook.__select__ & hook.match_rtype(*symmetric_rtypes)
- EnsureSymmetricRelationsDelete.__select__ = hook.Hook.__select__ & hook.match_rtype(*symmetric_rtypes)
-
+ class EnsureSymmetricRelationsAdd(_EnsureSymmetricRelationsAdd):
+ __select__ = _EnsureSymmetricRelationsAdd.__select__ & hook.match_rtype(*symmetric_rtypes)
+ vreg.register(EnsureSymmetricRelationsAdd)
+ class EnsureSymmetricRelationsDelete(_EnsureSymmetricRelationsDelete):
+ __select__ = _EnsureSymmetricRelationsDelete.__select__ & hook.match_rtype(*symmetric_rtypes)
+ vreg.register(EnsureSymmetricRelationsDelete)
--- a/hooks/security.py Wed Dec 09 18:42:13 2015 +0100
+++ b/hooks/security.py Thu Dec 10 12:34:15 2015 +0100
@@ -207,4 +207,3 @@
rdef = rschema.rdef(self._cw.entity_metas(self.eidfrom)['type'],
self._cw.entity_metas(self.eidto)['type'])
rdef.check_perm(self._cw, 'delete', fromeid=self.eidfrom, toeid=self.eidto)
-
--- a/hooks/synccomputed.py Wed Dec 09 18:42:13 2015 +0100
+++ b/hooks/synccomputed.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""Hooks for synchronizing computed attributes"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from collections import defaultdict
@@ -40,7 +40,7 @@
self._container[computed_attribute] = set((eid,))
def precommit_event(self):
- for computed_attribute_rdef, eids in self.get_data().iteritems():
+ for computed_attribute_rdef, eids in self.get_data().items():
attr = computed_attribute_rdef.rtype
formula = computed_attribute_rdef.formula
select = self.cnx.repo.vreg.rqlhelper.parse(formula).children[0]
@@ -110,7 +110,7 @@
def __call__(self):
edited_attributes = frozenset(self.entity.cw_edited)
- for rdef, used_attributes in self.attributes_computed_attributes.iteritems():
+ for rdef, used_attributes in self.attributes_computed_attributes.items():
if edited_attributes.intersection(used_attributes):
# XXX optimize if the modified attributes belong to the same
# entity as the computed attribute
@@ -178,7 +178,7 @@
self.computed_attribute_by_relation[depend_on_rdef].append(rdef)
def generate_entity_creation_hooks(self):
- for etype, computed_attributes in self.computed_attribute_by_etype.iteritems():
+ for etype, computed_attributes in self.computed_attribute_by_etype.items():
regid = 'computed_attribute.%s_created' % etype
selector = hook.is_instance(etype)
yield type('%sCreatedHook' % etype,
@@ -188,7 +188,7 @@
'computed_attributes': computed_attributes})
def generate_relation_change_hooks(self):
- for rdef, computed_attributes in self.computed_attribute_by_relation.iteritems():
+ for rdef, computed_attributes in self.computed_attribute_by_relation.items():
regid = 'computed_attribute.%s_modified' % rdef.rtype
selector = hook.match_rtype(rdef.rtype.type,
frometypes=(rdef.subject.type,),
@@ -206,7 +206,7 @@
'optimized_computed_attributes': optimized_computed_attributes})
def generate_entity_update_hooks(self):
- for etype, attributes_computed_attributes in self.computed_attribute_by_etype_attrs.iteritems():
+ for etype, attributes_computed_attributes in self.computed_attribute_by_etype_attrs.items():
regid = 'computed_attribute.%s_updated' % etype
selector = hook.is_instance(etype)
yield type('%sModifiedHook' % etype,
--- a/hooks/syncschema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/hooks/syncschema.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -24,7 +24,7 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from copy import copy
from hashlib import md5
@@ -37,7 +37,7 @@
from cubicweb import validation_error
from cubicweb.predicates import is_instance
from cubicweb.schema import (SCHEMA_TYPES, META_RTYPES, VIRTUAL_RTYPES,
- CONSTRAINTS, ETYPE_NAME_MAP, display_name)
+ CONSTRAINTS, UNIQUE_CONSTRAINTS, ETYPE_NAME_MAP)
from cubicweb.server import hook, schemaserial as ss, schema2sql as y2sql
from cubicweb.server.sqlutils import SQL_PREFIX
from cubicweb.hooks.synccomputed import RecomputeAttributeOperation
@@ -158,24 +158,26 @@
cnx.transaction_data.setdefault('pendingrtypes', set()).add(rtype)
-class DropColumn(hook.Operation):
+class DropColumn(hook.DataOperationMixIn, hook.Operation):
"""actually remove the attribut's column from entity table in the system
database
"""
- table = column = None # make pylint happy
def precommit_event(self):
- cnx, table, column = self.cnx, self.table, self.column
- source = cnx.repo.system_source
- # drop index if any
- source.drop_index(cnx, table, column)
- if source.dbhelper.alter_column_support:
- cnx.system_sql('ALTER TABLE %s DROP COLUMN %s' % (table, column),
- rollback_on_failure=False)
- self.info('dropped column %s from table %s', column, table)
- else:
- # not supported by sqlite for instance
- self.error('dropping column not supported by the backend, handle '
- 'it yourself (%s.%s)', table, column)
+ cnx = self.cnx
+ for etype, attr in self.get_data():
+ table = SQL_PREFIX + etype
+ column = SQL_PREFIX + attr
+ source = cnx.repo.system_source
+ # drop index if any
+ source.drop_index(cnx, table, column)
+ if source.dbhelper.alter_column_support:
+ cnx.system_sql('ALTER TABLE %s DROP COLUMN %s' % (table, column),
+ rollback_on_failure=False)
+ self.info('dropped column %s from table %s', column, table)
+ else:
+ # not supported by sqlite for instance
+ self.error('dropping column not supported by the backend, handle '
+ 'it yourself (%s.%s)', table, column)
# XXX revertprecommit_event
@@ -208,7 +210,7 @@
repo.set_schema(repo.schema)
# CWUser class might have changed, update current session users
cwuser_cls = self.cnx.vreg['etypes'].etype_class('CWUser')
- for session in repo._sessions.itervalues():
+ for session in repo._sessions.values():
session.user.__class__ = cwuser_cls
except Exception:
self.critical('error while setting schema', exc_info=True)
@@ -330,7 +332,7 @@
self.oldvalues = dict( (attr, getattr(rschema, attr)) for attr in self.values)
self.rschema.__dict__.update(self.values)
# then make necessary changes to the system source database
- if not 'inlined' in self.values:
+ if 'inlined' not in self.values:
return # nothing to do
inlined = self.values['inlined']
# check in-lining is possible when inlined
@@ -360,8 +362,7 @@
# drop existant columns
#if cnx.repo.system_source.dbhelper.alter_column_support:
for etype in rschema.subjects():
- DropColumn(cnx, table=SQL_PREFIX + str(etype),
- column=SQL_PREFIX + rtype)
+ DropColumn.get_instance(cnx).add_data((str(etype), rtype))
else:
for etype in rschema.subjects():
try:
@@ -606,10 +607,24 @@
if rset[0][0] == 0 and not cnx.deleted_in_transaction(rdef.subject.eid):
ptypes = cnx.transaction_data.setdefault('pendingrtypes', set())
ptypes.add(rschema.type)
- DropColumn(cnx, table=SQL_PREFIX + str(rdef.subject),
- column=SQL_PREFIX + str(rschema))
+ DropColumn.get_instance(cnx).add_data((str(rdef.subject), str(rschema)))
+ elif rschema.inlined:
+ cnx.system_sql('UPDATE %s%s SET %s%s=NULL WHERE '
+ 'EXISTS(SELECT 1 FROM entities '
+ ' WHERE eid=%s%s AND type=%%(to_etype)s)'
+ % (SQL_PREFIX, rdef.subject, SQL_PREFIX, rdef.rtype,
+ SQL_PREFIX, rdef.rtype),
+ {'to_etype': rdef.object.type})
elif lastrel:
DropRelationTable(cnx, str(rschema))
+ else:
+ cnx.system_sql('DELETE FROM %s_relation WHERE '
+ 'EXISTS(SELECT 1 FROM entities '
+ ' WHERE eid=eid_from AND type=%%(from_etype)s)'
+ ' AND EXISTS(SELECT 1 FROM entities '
+ ' WHERE eid=eid_to AND type=%%(to_etype)s)'
+ % rschema,
+ {'from_etype': rdef.subject.type, 'to_etype': rdef.object.type})
# then update the in-memory schema
if rdef.subject not in ETYPE_NAME_MAP and rdef.object not in ETYPE_NAME_MAP:
rschema.del_relation_def(rdef.subject, rdef.object)
@@ -647,8 +662,7 @@
if 'indexed' in self.values:
syssource.update_rdef_indexed(cnx, rdef)
self.indexed_changed = True
- if 'cardinality' in self.values and (rdef.rtype.final or
- rdef.rtype.inlined) \
+ if 'cardinality' in self.values and rdef.rtype.final \
and self.values['cardinality'][0] != self.oldvalues['cardinality'][0]:
syssource.update_rdef_null_allowed(self.cnx, rdef)
self.null_allowed_changed = True
@@ -717,8 +731,8 @@
syssource.update_rdef_unique(cnx, rdef)
self.unique_changed = True
if cstrtype in ('BoundaryConstraint', 'IntervalBoundConstraint', 'StaticVocabularyConstraint'):
- cstrname = 'cstr' + md5(rdef.subject.type + rdef.rtype.type + cstrtype +
- (self.oldcstr.serialize() or '')).hexdigest()
+ cstrname = 'cstr' + md5((rdef.subject.type + rdef.rtype.type + cstrtype +
+ (self.oldcstr.serialize() or '')).encode('utf-8')).hexdigest()
cnx.system_sql('ALTER TABLE %s%s DROP CONSTRAINT %s' % (SQL_PREFIX, rdef.subject.type, cstrname))
def revertprecommit_event(self):
@@ -749,7 +763,10 @@
return
rdef = self.rdef = cnx.vreg.schema.schema_by_eid(rdefentity.eid)
cstrtype = self.entity.type
- oldcstr = self.oldcstr = rdef.constraint_by_type(cstrtype)
+ if cstrtype in UNIQUE_CONSTRAINTS:
+ oldcstr = self.oldcstr = rdef.constraint_by_type(cstrtype)
+ else:
+ oldcstr = None
newcstr = self.newcstr = CONSTRAINTS[cstrtype].deserialize(self.entity.value)
# in-place modification of in-memory schema first
_set_modifiable_constraints(rdef)
@@ -769,8 +786,8 @@
self.unique_changed = True
if cstrtype in ('BoundaryConstraint', 'IntervalBoundConstraint', 'StaticVocabularyConstraint'):
if oldcstr is not None:
- oldcstrname = 'cstr' + md5(rdef.subject.type + rdef.rtype.type + cstrtype +
- (self.oldcstr.serialize() or '')).hexdigest()
+ oldcstrname = 'cstr' + md5((rdef.subject.type + rdef.rtype.type + cstrtype +
+ (self.oldcstr.serialize() or '')).encode('ascii')).hexdigest()
cnx.system_sql('ALTER TABLE %s%s DROP CONSTRAINT %s' %
(SQL_PREFIX, rdef.subject.type, oldcstrname))
cstrname, check = y2sql.check_constraint(rdef.subject, rdef.object, rdef.rtype.type,
@@ -905,11 +922,6 @@
# duh, schema not found, log error and skip operation
self.warning('no schema for %s', self.eid)
return
- if isinstance(erschema, RelationSchema): # XXX 3.6 migration
- return
- if isinstance(erschema, RelationDefinitionSchema) and \
- self.action in ('delete', 'add'): # XXX 3.6.1 migration
- return
perms = list(erschema.action_permissions(self.action))
if self.group_eid is not None:
perm = self.cnx.entity_from_eid(self.group_eid).name
@@ -972,7 +984,6 @@
raise validation_error(self.entity, {None: _("can't be deleted")})
# delete every entities of this type
if name not in ETYPE_NAME_MAP:
- self._cw.execute('DELETE %s X' % name)
MemSchemaCWETypeDel(self._cw, etype=name)
DropTable(self._cw, table=SQL_PREFIX + name)
@@ -1155,10 +1166,6 @@
else:
rdeftype = 'CWRelation'
pendingrdefs.add((subjschema, rschema, objschema))
- if not (cnx.deleted_in_transaction(subjschema.eid) or
- cnx.deleted_in_transaction(objschema.eid)):
- cnx.execute('DELETE X %s Y WHERE X is %s, Y is %s'
- % (rschema, subjschema, objschema))
RDefDelOp(cnx, rdef=rdef)
--- a/hooks/syncsession.py Wed Dec 09 18:42:13 2015 +0100
+++ b/hooks/syncsession.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""Core hooks: synchronize living session on persistent data changes"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from cubicweb import UnknownProperty, BadConnectionId, validation_error
from cubicweb.predicates import is_instance
@@ -26,7 +26,7 @@
def get_user_sessions(repo, ueid):
- for session in repo._sessions.itervalues():
+ for session in repo._sessions.values():
if ueid == session.user.eid:
yield session
@@ -114,7 +114,7 @@
def __call__(self):
"""modify user permission, need to update users"""
for session in get_user_sessions(self._cw.repo, self.entity.eid):
- _DelUserOp(self._cw, session.id)
+ _DelUserOp(self._cw, session.sessionid)
# CWProperty hooks #############################################################
--- a/hooks/syncsources.py Wed Dec 09 18:42:13 2015 +0100
+++ b/hooks/syncsources.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,7 +17,7 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""hooks for repository sources synchronization"""
-_ = unicode
+from cubicweb import _
from socket import gethostname
@@ -119,7 +119,7 @@
msg = _("You cannot rename the system source")
raise validation_error(self.entity, {('name', 'subject'): msg})
SourceRenamedOp(self._cw, oldname=oldname, newname=newname)
- if 'config' in self.entity.cw_edited:
+ if 'config' in self.entity.cw_edited or 'url' in self.entity.cw_edited:
if self.entity.name == 'system' and self.entity.config:
msg = _("Configuration of the system source goes to "
"the 'sources' file, not in the database")
--- a/hooks/test/data/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/hooks/test/data/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,7 +22,7 @@
from cubicweb.schema import ERQLExpression
-_ = unicode
+from cubicweb import _
class friend(RelationDefinition):
subject = ('CWUser', 'CWGroup')
--- a/hooks/test/unittest_hooks.py Wed Dec 09 18:42:13 2015 +0100
+++ b/hooks/test/unittest_hooks.py Thu Dec 10 12:34:15 2015 +0100
@@ -24,9 +24,12 @@
from datetime import datetime
+from six import text_type
+
from cubicweb import ValidationError, AuthenticationError, BadConnectionId
from cubicweb.devtools.testlib import CubicWebTC
+
class CoreHooksTC(CubicWebTC):
def test_inlined(self):
@@ -207,7 +210,7 @@
with self.assertRaises(ValidationError) as cm:
cnx.execute('INSERT CWUser X: X login "admin"')
ex = cm.exception
- ex.translate(unicode)
+ ex.translate(text_type)
self.assertIsInstance(ex.entity, int)
self.assertEqual(ex.errors, {'login-subject': 'the value "admin" is already used, use another one'})
--- a/hooks/test/unittest_synccomputed.py Wed Dec 09 18:42:13 2015 +0100
+++ b/hooks/test/unittest_synccomputed.py Thu Dec 10 12:34:15 2015 +0100
@@ -62,7 +62,7 @@
def test_computed_attribute_by_relation(self):
comp_by_rdef = self.dependencies.computed_attribute_by_relation
self.assertEqual(len(comp_by_rdef), 1)
- key, values = iter(comp_by_rdef.iteritems()).next()
+ key, values = next(iter(comp_by_rdef.items()))
self.assertEqual(key.rtype, 'works_for')
self.assertEqual(len(values), 1)
self.assertEqual(values[0].rtype, 'total_salary')
@@ -73,7 +73,7 @@
values = comp_by_attr['Person']
self.assertEqual(len(values), 2)
values = set((rdef.formula, tuple(v))
- for rdef, v in values.iteritems())
+ for rdef, v in values.items())
self.assertEquals(values,
set((('Any 2014 - D WHERE X birth_year D', tuple(('birth_year',))),
('Any SUM(SA) GROUPBY X WHERE P works_for X, P salary SA', tuple(('salary',)))))
--- a/hooks/test/unittest_syncschema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/hooks/test/unittest_syncschema.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,6 +19,7 @@
from logilab.common.testlib import unittest_main
+from yams.constraints import BoundaryConstraint
from cubicweb import ValidationError, Binary
from cubicweb.schema import META_RTYPES
from cubicweb.devtools import startpgcluster, stoppgcluster, PostgresApptestConfiguration
@@ -382,5 +383,23 @@
self.assertEqual(cstr.values, (u'normal', u'auto', u'new'))
cnx.execute('INSERT Transition T: T name "hop", T type "new"')
+ def test_add_constraint(self):
+ with self.admin_access.repo_cnx() as cnx:
+ rdef = self.schema['EmailPart'].rdef('ordernum')
+ cstr = BoundaryConstraint('>=', 0)
+ cnx.execute('INSERT CWConstraint X: X value %(v)s, X cstrtype CT, '
+ 'EDEF constrained_by X WHERE CT name %(ct)s, EDEF eid %(x)s',
+ {'ct': cstr.__class__.__name__, 'v': cstr.serialize(), 'x': rdef.eid})
+ cnx.commit()
+ cstr2 = rdef.constraint_by_type('BoundaryConstraint')
+ self.assertEqual(cstr, cstr2)
+ cstr3 = BoundaryConstraint('<=', 1000)
+ cnx.execute('INSERT CWConstraint X: X value %(v)s, X cstrtype CT, '
+ 'EDEF constrained_by X WHERE CT name %(ct)s, EDEF eid %(x)s',
+ {'ct': cstr3.__class__.__name__, 'v': cstr3.serialize(), 'x': rdef.eid})
+ cnx.commit()
+ self.assertCountEqual(rdef.constraints, [cstr, cstr3])
+
+
if __name__ == '__main__':
unittest_main()
--- a/hooks/test/unittest_syncsession.py Wed Dec 09 18:42:13 2015 +0100
+++ b/hooks/test/unittest_syncsession.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,6 +22,8 @@
syncschema.py hooks are mostly tested in server/test/unittest_migrations.py
"""
+from six import text_type
+
from cubicweb import ValidationError
from cubicweb.devtools.testlib import CubicWebTC
@@ -32,13 +34,13 @@
with self.assertRaises(ValidationError) as cm:
req.execute('INSERT CWProperty X: X pkey "bla.bla", '
'X value "hop", X for_user U')
- cm.exception.translate(unicode)
+ cm.exception.translate(text_type)
self.assertEqual(cm.exception.errors,
{'pkey-subject': 'unknown property key bla.bla'})
with self.assertRaises(ValidationError) as cm:
req.execute('INSERT CWProperty X: X pkey "bla.bla", X value "hop"')
- cm.exception.translate(unicode)
+ cm.exception.translate(text_type)
self.assertEqual(cm.exception.errors,
{'pkey-subject': 'unknown property key bla.bla'})
--- a/hooks/workflow.py Wed Dec 09 18:42:13 2015 +0100
+++ b/hooks/workflow.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""Core hooks: workflow related hooks"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from datetime import datetime
@@ -355,4 +355,3 @@
typewf = entity.cw_adapt_to('IWorkflowable').cwetype_workflow()
if typewf is not None:
_WorkflowChangedOp(self._cw, eid=self.eidfrom, wfeid=typewf.eid)
-
--- a/hooks/zmq.py Wed Dec 09 18:42:13 2015 +0100
+++ b/hooks/zmq.py Thu Dec 10 12:34:15 2015 +0100
@@ -48,5 +48,3 @@
for address in address_sub:
self.repo.app_instances_bus.add_subscriber(address)
self.repo.app_instances_bus.start()
-
-
--- a/i18n.py Wed Dec 09 18:42:13 2015 +0100
+++ b/i18n.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""Some i18n/gettext utilities."""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
@@ -24,6 +25,8 @@
from os.path import join, basename, splitext, exists
from glob import glob
+from six import PY2
+
from cubicweb.toolsutils import create_dir
def extract_from_tal(files, output_file):
@@ -39,10 +42,10 @@
def add_msg(w, msgid, msgctx=None):
"""write an empty pot msgid definition"""
- if isinstance(msgid, unicode):
+ if PY2 and isinstance(msgid, unicode):
msgid = msgid.encode('utf-8')
if msgctx:
- if isinstance(msgctx, unicode):
+ if PY2 and isinstance(msgctx, unicode):
msgctx = msgctx.encode('utf-8')
w('msgctxt "%s"\n' % msgctx)
msgid = msgid.replace('"', r'\"').splitlines()
@@ -80,7 +83,7 @@
"""
from subprocess import CalledProcessError
from logilab.common.fileutils import ensure_fs_mode
- print '-> compiling message catalogs to %s' % destdir
+ print('-> compiling message catalogs to %s' % destdir)
errors = []
for lang in langs:
langdir = join(destdir, lang, 'LC_MESSAGES')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jshintrc Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,115 @@
+{
+ // --------------------------------------------------------------------
+ // JSHint Configuration, Strict Edition
+ // --------------------------------------------------------------------
+ //
+ // This is a options template for [JSHint][1], using [JSHint example][2]
+ // and [Ory Band's example][3] as basis and setting config values to
+ // be most strict:
+ //
+ // * set all enforcing options to true
+ // * set all relaxing options to false
+ // * set all environment options to false, except the browser value
+ // * set all JSLint legacy options to false
+ //
+ // [1]: http://www.jshint.com/
+ // [2]: https://github.com/jshint/node-jshint/blob/master/example/config.json
+ // [3]: https://github.com/oryband/dotfiles/blob/master/jshintrc
+ //
+ // @author http://michael.haschke.biz/
+ // @license http://unlicense.org/
+
+ // == Enforcing Options ===============================================
+ //
+ // These options tell JSHint to be more strict towards your code. Use
+ // them if you want to allow only a safe subset of JavaScript, very
+ // useful when your codebase is shared with a big number of developers
+ // with different skill levels.
+
+ "bitwise" : true, // Prohibit bitwise operators (&, |, ^, etc.).
+ "curly" : true, // Require {} for every new block or scope.
+ "eqeqeq" : true, // Require triple equals i.e. `===`.
+ "forin" : true, // Tolerate `for in` loops without `hasOwnPrototype`.
+ "immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );`
+ "latedef" : true, // Prohibit variable use before definition.
+ "newcap" : true, // Require capitalization of all constructor functions e.g. `new F()`.
+ "noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`.
+ "noempty" : true, // Prohibit use of empty blocks.
+ "nonew" : true, // Prohibit use of constructors for side-effects.
+ "plusplus" : true, // Prohibit use of `++` & `--`.
+ "regexp" : true, // Prohibit `.` and `[^...]` in regular expressions.
+ "undef" : true, // Require all non-global variables be declared before they are used.
+ "strict" : true, // Require `use strict` pragma in every file.
+ "trailing" : true, // Prohibit trailing whitespaces.
+
+ // == Relaxing Options ================================================
+ //
+ // These options allow you to suppress certain types of warnings. Use
+ // them only if you are absolutely positive that you know what you are
+ // doing.
+
+ "asi" : false, // Tolerate Automatic Semicolon Insertion (no semicolons).
+ "boss" : false, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments.
+ "debug" : false, // Allow debugger statements e.g. browser breakpoints.
+ "eqnull" : false, // Tolerate use of `== null`.
+ "es5" : false, // Allow EcmaScript 5 syntax.
+ "esnext" : false, // Allow ES.next specific features such as `const` and `let`.
+ "evil" : false, // Tolerate use of `eval`.
+ "expr" : false, // Tolerate `ExpressionStatement` as Programs.
+ "funcscope" : false, // Tolerate declarations of variables inside of control structures while accessing them later from the outside.
+ "globalstrict" : false, // Allow global "use strict" (also enables 'strict').
+ "iterator" : false, // Allow usage of __iterator__ property.
+ "lastsemic" : false, // Tolerat missing semicolons when the it is omitted for the last statement in a one-line block.
+ "laxbreak" : false, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons.
+ "laxcomma" : false, // Suppress warnings about comma-first coding style.
+ "loopfunc" : false, // Allow functions to be defined within loops.
+ "multistr" : false, // Tolerate multi-line strings.
+ "onecase" : false, // Tolerate switches with just one case.
+ "proto" : false, // Tolerate __proto__ property. This property is deprecated.
+ "regexdash" : false, // Tolerate unescaped last dash i.e. `[-...]`.
+ "scripturl" : false, // Tolerate script-targeted URLs.
+ "smarttabs" : false, // Tolerate mixed tabs and spaces when the latter are used for alignmnent only.
+ "shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`.
+ "sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`.
+ "supernew" : false, // Tolerate `new function () { ... };` and `new Object;`.
+ "validthis" : false, // Tolerate strict violations when the code is running in strict mode and you use this in a non-constructor function.
+
+ // == Environments ====================================================
+ //
+ // These options pre-define global variables that are exposed by
+ // popular JavaScript libraries and runtime environments—such as
+ // browser or node.js.
+
+ "browser" : true, // Standard browser globals e.g. `window`, `document`.
+ "couch" : false, // Enable globals exposed by CouchDB.
+ "devel" : false, // Allow development statements e.g. `console.log();`.
+ "dojo" : false, // Enable globals exposed by Dojo Toolkit.
+ "jquery" : false, // Enable globals exposed by jQuery JavaScript library.
+ "mootools" : false, // Enable globals exposed by MooTools JavaScript framework.
+ "node" : false, // Enable globals available when code is running inside of the NodeJS runtime environment.
+ "nonstandard" : false, // Define non-standard but widely adopted globals such as escape and unescape.
+ "prototypejs" : false, // Enable globals exposed by Prototype JavaScript framework.
+ "rhino" : false, // Enable globals available when your code is running inside of the Rhino runtime environment.
+ "wsh" : false, // Enable globals available when your code is running as a script for the Windows Script Host.
+
+ // == JSLint Legacy ===================================================
+ //
+ // These options are legacy from JSLint. Aside from bug fixes they will
+ // not be improved in any way and might be removed at any point.
+
+ "nomen" : false, // Prohibit use of initial or trailing underbars in names.
+ "onevar" : false, // Allow only one `var` statement per function.
+ "passfail" : false, // Stop on first error.
+ "white" : false, // Check against strict whitespace and indentation rules.
+
+ // == Undocumented Options ============================================
+ //
+ // While I've found these options in [example1][2] and [example2][3]
+ // they are not described in the [JSHint Options documentation][4].
+ //
+ // [4]: http://www.jshint.com/options/
+
+ "maxerr" : 100, // Maximum errors before stopping.
+ "predef" : [], // Extra globals.
+ "indent" : 4 // Specify indentation spacing
+}
--- a/mail.py Wed Dec 09 18:42:13 2015 +0100
+++ b/mail.py Thu Dec 10 12:34:15 2015 +0100
@@ -28,16 +28,27 @@
from email.utils import formatdate
from socket import gethostname
+from six import PY2, PY3, text_type
+
+
def header(ustring):
+ if PY3:
+ return Header(ustring, 'utf-8')
return Header(ustring.encode('UTF-8'), 'UTF-8')
def addrheader(uaddr, uname=None):
# even if an email address should be ascii, encode it using utf8 since
# automatic tests may generate non ascii email address
- addr = uaddr.encode('UTF-8')
+ if PY2:
+ addr = uaddr.encode('UTF-8')
+ else:
+ addr = uaddr
if uname:
- return '%s <%s>' % (header(uname).encode(), addr)
- return addr
+ val = '%s <%s>' % (header(uname).encode(), addr)
+ else:
+ val = addr
+ assert isinstance(val, str) # bytes in py2, ascii-encoded unicode in py3
+ return val
def construct_message_id(appid, eid, withtimestamp=True):
@@ -46,7 +57,7 @@
else:
addrpart = 'eid=%s' % eid
# we don't want any equal sign nor trailing newlines
- leftpart = b64encode(addrpart, '.-').rstrip().rstrip('=')
+ leftpart = b64encode(addrpart.encode('ascii'), b'.-').decode('ascii').rstrip().rstrip('=')
return '<%s@%s.%s>' % (leftpart, appid, gethostname())
@@ -75,7 +86,7 @@
to_addrs and cc_addrs are expected to be a list of email address without
name
"""
- assert type(content) is unicode, repr(content)
+ assert isinstance(content, text_type), repr(content)
msg = MIMEText(content.encode('UTF-8'), 'plain', 'UTF-8')
# safety: keep only the first newline
try:
@@ -86,13 +97,13 @@
if uinfo.get('email'):
email = uinfo['email']
elif config and config['sender-addr']:
- email = unicode(config['sender-addr'])
+ email = text_type(config['sender-addr'])
else:
email = u''
if uinfo.get('name'):
name = uinfo['name']
elif config and config['sender-name']:
- name = unicode(config['sender-name'])
+ name = text_type(config['sender-name'])
else:
name = u''
msg['From'] = addrheader(email, name)
--- a/md5crypt.py Wed Dec 09 18:42:13 2015 +0100
+++ b/md5crypt.py Thu Dec 10 12:34:15 2015 +0100
@@ -38,31 +38,37 @@
this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
"""
-MAGIC = '$1$' # Magic string
-ITOA64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+MAGIC = b'$1$' # Magic string
+ITOA64 = b"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
from hashlib import md5 # pylint: disable=E0611
+from six import text_type, indexbytes
+from six.moves import range
+
+
def to64 (v, n):
- ret = ''
+ ret = bytearray()
while (n - 1 >= 0):
n = n - 1
- ret = ret + ITOA64[v & 0x3f]
+ ret.append(ITOA64[v & 0x3f])
v = v >> 6
return ret
def crypt(pw, salt):
- if isinstance(pw, unicode):
+ if isinstance(pw, text_type):
pw = pw.encode('utf-8')
+ if isinstance(salt, text_type):
+ salt = salt.encode('ascii')
# Take care of the magic string if present
if salt.startswith(MAGIC):
salt = salt[len(MAGIC):]
# salt can have up to 8 characters:
- salt = salt.split('$', 1)[0]
+ salt = salt.split(b'$', 1)[0]
salt = salt[:8]
ctx = pw + MAGIC + salt
final = md5(pw + salt + pw).digest()
- for pl in xrange(len(pw), 0, -16):
+ for pl in range(len(pw), 0, -16):
if pl > 16:
ctx = ctx + final[:16]
else:
@@ -71,7 +77,7 @@
i = len(pw)
while i:
if i & 1:
- ctx = ctx + chr(0) #if ($i & 1) { $ctx->add(pack("C", 0)); }
+ ctx = ctx + b'\0' #if ($i & 1) { $ctx->add(pack("C", 0)); }
else:
ctx = ctx + pw[0]
i = i >> 1
@@ -79,8 +85,8 @@
# The following is supposed to make
# things run slower.
# my question: WTF???
- for i in xrange(1000):
- ctx1 = ''
+ for i in range(1000):
+ ctx1 = b''
if i & 1:
ctx1 = ctx1 + pw
else:
@@ -95,21 +101,21 @@
ctx1 = ctx1 + pw
final = md5(ctx1).digest()
# Final xform
- passwd = ''
- passwd = passwd + to64((int(ord(final[0])) << 16)
- |(int(ord(final[6])) << 8)
- |(int(ord(final[12]))),4)
- passwd = passwd + to64((int(ord(final[1])) << 16)
- |(int(ord(final[7])) << 8)
- |(int(ord(final[13]))), 4)
- passwd = passwd + to64((int(ord(final[2])) << 16)
- |(int(ord(final[8])) << 8)
- |(int(ord(final[14]))), 4)
- passwd = passwd + to64((int(ord(final[3])) << 16)
- |(int(ord(final[9])) << 8)
- |(int(ord(final[15]))), 4)
- passwd = passwd + to64((int(ord(final[4])) << 16)
- |(int(ord(final[10])) << 8)
- |(int(ord(final[5]))), 4)
- passwd = passwd + to64((int(ord(final[11]))), 2)
+ passwd = b''
+ passwd += to64((indexbytes(final, 0) << 16)
+ |(indexbytes(final, 6) << 8)
+ |(indexbytes(final, 12)),4)
+ passwd += to64((indexbytes(final, 1) << 16)
+ |(indexbytes(final, 7) << 8)
+ |(indexbytes(final, 13)), 4)
+ passwd += to64((indexbytes(final, 2) << 16)
+ |(indexbytes(final, 8) << 8)
+ |(indexbytes(final, 14)), 4)
+ passwd += to64((indexbytes(final, 3) << 16)
+ |(indexbytes(final, 9) << 8)
+ |(indexbytes(final, 15)), 4)
+ passwd += to64((indexbytes(final, 4) << 16)
+ |(indexbytes(final, 10) << 8)
+ |(indexbytes(final, 5)), 4)
+ passwd += to64((indexbytes(final, 11)), 2)
return passwd
--- a/migration.py Wed Dec 09 18:42:13 2015 +0100
+++ b/migration.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""utilities for instances migration"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
@@ -25,6 +26,9 @@
import tempfile
from os.path import exists, join, basename, splitext
from itertools import chain
+from warnings import warn
+
+from six import string_types
from logilab.common import IGNORED_EXTENSIONS
from logilab.common.decorators import cached
@@ -49,7 +53,7 @@
assert fromversion <= toversion, (fromversion, toversion)
if not exists(directory):
if not quiet:
- print directory, "doesn't exists, no migration path"
+ print(directory, "doesn't exists, no migration path")
return []
if fromversion == toversion:
return []
@@ -93,9 +97,9 @@
stream = open(scriptpath)
scriptcontent = stream.read()
stream.close()
- print
- print scriptcontent
- print
+ print()
+ print(scriptcontent)
+ print()
else:
return True
@@ -139,9 +143,6 @@
raise
raise AttributeError(name)
- def repo_connect(self):
- return self.config.repository()
-
def migrate(self, vcconf, toupgrade, options):
"""upgrade the given set of cubes
@@ -243,7 +244,7 @@
# avoid '_' to be added to builtins by sys.display_hook
def do_not_add___to_builtins(obj):
if obj is not None:
- print repr(obj)
+ print(repr(obj))
sys.displayhook = do_not_add___to_builtins
local_ctx = self._create_context()
try:
@@ -349,7 +350,16 @@
else:
pyname = splitext(basename(migrscript))[0]
scriptlocals['__name__'] = pyname
- execfile(migrscript, scriptlocals)
+ with open(migrscript, 'rb') as fobj:
+ fcontent = fobj.read()
+ try:
+ code = compile(fcontent, migrscript, 'exec')
+ except SyntaxError:
+ # try without print_function
+ code = compile(fcontent, migrscript, 'exec', 0, True)
+ warn('[3.22] script %r should be updated to work with print_function'
+ % migrscript, DeprecationWarning)
+ exec(code, scriptlocals)
if funcname is not None:
try:
func = scriptlocals[funcname]
@@ -399,7 +409,7 @@
"""modify the list of used cubes in the in-memory config
returns newly inserted cubes, including dependencies
"""
- if isinstance(cubes, basestring):
+ if isinstance(cubes, string_types):
cubes = (cubes,)
origcubes = self.config.cubes()
newcubes = [p for p in self.config.expand_cubes(cubes)
@@ -454,6 +464,10 @@
def version_strictly_lower(a, b):
+ if a is None:
+ return True
+ if b is None:
+ return False
if a:
a = Version(a)
if b:
@@ -491,8 +505,8 @@
self.dependencies[cube] = dict(self.config.cube_dependencies(cube))
self.dependencies[cube]['cubicweb'] = self.config.cube_depends_cubicweb_version(cube)
# compute reverse dependencies
- for cube, dependencies in self.dependencies.iteritems():
- for name, constraint in dependencies.iteritems():
+ for cube, dependencies in self.dependencies.items():
+ for name, constraint in dependencies.items():
self.reverse_dependencies.setdefault(name,set())
if constraint:
try:
@@ -522,9 +536,9 @@
elif op == None:
continue
else:
- print ('unable to handle %s in %s, set to `%s %s` '
- 'but currently up to `%s %s`' %
- (cube, source, oper, version, op, ver))
+ print('unable to handle %s in %s, set to `%s %s` '
+ 'but currently up to `%s %s`' %
+ (cube, source, oper, version, op, ver))
# "solve" constraint satisfaction problem
if cube not in self.cubes:
self.errors.append( ('add', cube, version, source) )
@@ -536,4 +550,4 @@
elif oper is None:
pass # no constraint on version
else:
- print 'unknown operator', oper
+ print('unknown operator', oper)
--- a/misc/cwfs/cwfs.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/cwfs/cwfs.py Thu Dec 10 12:34:15 2015 +0100
@@ -80,17 +80,17 @@
self._restrictions = []
def parse(self) :
- self._entity = self._components.next()
+ self._entity = next(self._components)
try:
self.process_entity()
except StopIteration :
pass
def process_entity(self) :
- _next = self._components.next()
+ _next = next(self._components)
if _next in self.schema.get_attrs(self._entity) :
self._attr = _next
- _next = self._components.next()
+ _next = next(self._components)
self._restrictions.append( (self._entity, self._attr, _next) )
self._attr = None
self._rel = None
@@ -136,7 +136,7 @@
def parse(self):
self._var = self._alphabet.pop(0)
- self._e_type = self._components.next()
+ self._e_type = next(self._components)
e_type = self._e_type.capitalize()
self._restrictions.append('%s is %s' % (self._var, e_type))
try:
@@ -146,11 +146,11 @@
return 'Any %s WHERE %s' % (self._var, ', '.join(self._restrictions))
def process_entity(self) :
- _next = self._components.next()
+ _next = next(self._components)
if _next in self.schema.get_attrs(self._e_type) :
attr = _next
try:
- _next = self._components.next()
+ _next = next(self._components)
self._restrictions.append('%s %s %s' % (self._var, attr, _next))
except StopIteration:
a_var = self._alphabet.pop(0)
@@ -163,7 +163,7 @@
self._restrictions.append('%s %s %s' % (self._var, rel, r_var))
self._var = r_var
try:
- _next = self._components.next()
+ _next = next(self._components)
self._restrictions.append('%s is %s' % (r_var, _next.capitalize()))
except StopIteration:
raise
@@ -173,4 +173,3 @@
def to_rql(path) :
p = SytPathParser(SCHEMA,path)
return p.parse()
-
--- a/misc/cwfs/cwfs_test.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/cwfs/cwfs_test.py Thu Dec 10 12:34:15 2015 +0100
@@ -30,7 +30,7 @@
sections = []
buffer = ""
in_section = False
- for line in file(filename) :
+ for line in open(filename) :
if line.startswith('Test::'):
in_section = True
buffer = ""
--- a/misc/cwzope/cwzope.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/cwzope/cwzope.py Thu Dec 10 12:34:15 2015 +0100
@@ -48,4 +48,3 @@
cnx = connect(user, password, host, database, group)
CNX_CACHE[key] = cnx
return cnx
-
--- a/misc/migration/3.10.0_Any.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/migration/3.10.0_Any.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,3 +1,5 @@
+from six import text_type
+
from cubicweb.server.session import hooks_control
for uri, cfg in config.read_sources_file().items():
@@ -24,7 +26,7 @@
repo.sources_by_uri.pop(uri)
config = u'\n'.join('%s=%s' % (key, value) for key, value in cfg.items()
if key != 'adapter' and value is not None)
- create_entity('CWSource', name=unicode(uri), type=unicode(cfg['adapter']),
+ create_entity('CWSource', name=text_type(uri), type=text_type(cfg['adapter']),
config=config)
commit()
@@ -33,4 +35,3 @@
'X pkey ~= "boxes.%" OR '
'X pkey ~= "contentnavigation.%"').entities():
x.cw_set(pkey=u'ctxcomponents.' + x.pkey.split('.', 1)[1])
-
--- a/misc/migration/3.14.0_Any.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/migration/3.14.0_Any.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,3 +1,5 @@
+from __future__ import print_function
+
config['rql-cache-size'] = config['rql-cache-size'] * 10
add_entity_type('CWDataImport')
@@ -10,4 +12,4 @@
mainvars = guess_rrqlexpr_mainvars(expression)
yamscstr = CONSTRAINTS[rqlcstr.type](expression, mainvars)
rqlcstr.cw_set(value=yamscstr.serialize())
- print 'updated', rqlcstr.type, rqlcstr.value.strip()
+ print('updated', rqlcstr.type, rqlcstr.value.strip())
--- a/misc/migration/3.15.4_Any.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/migration/3.15.4_Any.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,3 +1,5 @@
+from __future__ import print_function
+
from logilab.common.shellutils import generate_password
from cubicweb.server.utils import crypt_password
@@ -5,7 +7,7 @@
salt = user.upassword.getvalue()
if crypt_password('', salt) == salt:
passwd = generate_password()
- print 'setting random password for user %s' % user.login
+ print('setting random password for user %s' % user.login)
user.set_attributes(upassword=passwd)
commit()
--- a/misc/migration/3.21.0_Any.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/migration/3.21.0_Any.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,3 +1,5 @@
+from __future__ import print_function
+
from cubicweb.schema import PURE_VIRTUAL_RTYPES
from cubicweb.server.schema2sql import rschema_has_table
@@ -27,7 +29,7 @@
' SELECT eid FROM entities) AS eids' % args,
ask_confirm=False)[0][0]
if count:
- print '%s references %d unknown entities, deleting' % (rschema, count)
+ print('%s references %d unknown entities, deleting' % (rschema, count))
sql('DELETE FROM %(r)s_relation '
'WHERE eid_from IN (SELECT eid_from FROM %(r)s_relation EXCEPT SELECT eid FROM entities)' % args)
sql('DELETE FROM %(r)s_relation '
@@ -65,14 +67,14 @@
broken_eids = sql('SELECT cw_eid FROM cw_%(e)s WHERE cw_%(r)s IS NULL' % args,
ask_confirm=False)
if broken_eids:
- print 'Required relation %(e)s.%(r)s missing' % args
+ print('Required relation %(e)s.%(r)s missing' % args)
args['eids'] = ', '.join(str(eid) for eid, in broken_eids)
rql('DELETE %(e)s X WHERE X eid IN (%(eids)s)' % args)
broken_eids = sql('SELECT cw_eid FROM cw_%(e)s WHERE cw_%(r)s IN (SELECT cw_%(r)s FROM cw_%(e)s '
'EXCEPT SELECT eid FROM entities)' % args,
ask_confirm=False)
if broken_eids:
- print 'Required relation %(e)s.%(r)s references unknown objects, deleting subject entities' % args
+ print('Required relation %(e)s.%(r)s references unknown objects, deleting subject entities' % args)
args['eids'] = ', '.join(str(eid) for eid, in broken_eids)
rql('DELETE %(e)s X WHERE X eid IN (%(eids)s)' % args)
else:
@@ -81,7 +83,7 @@
' EXCEPT'
' SELECT eid FROM entities) AS eids' % args,
ask_confirm=False)[0][0]:
- print '%(e)s.%(r)s references unknown entities, deleting relation' % args
+ print('%(e)s.%(r)s references unknown entities, deleting relation' % args)
sql('UPDATE cw_%(e)s SET cw_%(r)s = NULL WHERE cw_%(r)s IS NOT NULL AND cw_%(r)s IN '
'(SELECT cw_%(r)s FROM cw_%(e)s EXCEPT SELECT eid FROM entities)' % args)
@@ -104,7 +106,7 @@
' EXCEPT'
' SELECT eid FROM entities) AS eids' % args,
ask_confirm=False)[0][0]:
- print '%(e)s has nonexistent entities, deleting' % args
+ print('%(e)s has nonexistent entities, deleting' % args)
sql('DELETE FROM cw_%(e)s WHERE cw_eid IN '
'(SELECT cw_eid FROM cw_%(e)s EXCEPT SELECT eid FROM entities)' % args)
args['c'] = 'cw_%(e)s_cw_eid_fkey' % args
--- a/misc/migration/3.8.5_Any.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/migration/3.8.5_Any.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,3 +1,5 @@
+from __future__ import print_function
+
def migrate_varchar_to_nvarchar():
dbdriver = config.system_source_config['db-driver']
if dbdriver != "sqlserver2005":
@@ -52,7 +54,7 @@
for statement in generated_statements:
- print statement
+ print(statement)
sql(statement, ask_confirm=False)
commit()
--- a/misc/migration/bootstrapmigration_repository.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/migration/bootstrapmigration_repository.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,6 +19,9 @@
it should only include low level schema changes
"""
+from __future__ import print_function
+
+from six import text_type
from cubicweb import ConfigurationError
from cubicweb.server.session import hooks_control
@@ -77,8 +80,8 @@
sql('ALTER TABLE "entities" DROP COLUMN "mtime"')
sql('ALTER TABLE "entities" DROP COLUMN "source"')
except: # programming error, already migrated
- print "Failed to drop mtime or source database columns"
- print "'entities' table of the database has probably been already updated"
+ print("Failed to drop mtime or source database columns")
+ print("'entities' table of the database has probably been already updated")
commit()
@@ -101,7 +104,7 @@
driver = config.system_source_config['db-driver']
if not (driver == 'postgres' or driver.startswith('sqlserver')):
import sys
- print >>sys.stderr, 'This migration is not supported for backends other than sqlserver or postgres (yet).'
+ print('This migration is not supported for backends other than sqlserver or postgres (yet).', file=sys.stderr)
sys.exit(1)
add_relation_definition('CWAttribute', 'add_permission', 'CWGroup')
@@ -148,7 +151,7 @@
default = yams.DATE_FACTORY_MAP[atype](default)
else:
assert atype == 'String', atype
- default = unicode(default)
+ default = text_type(default)
return Binary.zpickle(default)
dbh = repo.system_source.dbhelper
@@ -196,7 +199,7 @@
(rschema.type, ','.join(subjects))))
if martians:
martians = ','.join(martians)
- print 'deleting broken relations %s for eids %s' % (rschema.type, martians)
+ print('deleting broken relations %s for eids %s' % (rschema.type, martians))
sql('DELETE FROM %s_relation WHERE eid_from IN (%s) OR eid_to IN (%s)' % (rschema.type, martians, martians))
with session.deny_all_hooks_but():
rql('SET X %(r)s Y WHERE Y %(r)s X, NOT X %(r)s Y' % {'r': rschema.type})
@@ -219,20 +222,20 @@
if driver == 'postgres':
for indexname, in sql('select indexname from pg_indexes'):
if indexname.startswith('unique_'):
- print 'dropping index', indexname
+ print('dropping index', indexname)
sql('DROP INDEX %s' % indexname)
commit()
elif driver.startswith('sqlserver'):
for viewname, in sql('select name from sys.views'):
if viewname.startswith('utv_'):
- print 'dropping view (index should be cascade-deleted)', viewname
+ print('dropping view (index should be cascade-deleted)', viewname)
sql('DROP VIEW %s' % viewname)
commit()
# recreate the constraints, hook will lead to low-level recreation
for eschema in sorted(schema.entities()):
if eschema._unique_together:
- print 'recreate unique indexes for', eschema
+ print('recreate unique indexes for', eschema)
rql_args = schemaserial.uniquetogether2rqls(eschema)
for rql, args in rql_args:
args['x'] = eschema.eid
@@ -243,10 +246,10 @@
for rschema in sorted(schema.relations()):
if rschema.final:
if rschema.type in fsschema:
- print 'sync perms for', rschema.type
+ print('sync perms for', rschema.type)
sync_schema_props_perms(rschema.type, syncprops=False, ask_confirm=False, commit=False)
else:
- print 'WARNING: attribute %s missing from fs schema' % rschema.type
+ print('WARNING: attribute %s missing from fs schema' % rschema.type)
commit()
if applcubicwebversion < (3, 17, 0) and cubicwebversion >= (3, 17, 0):
@@ -298,7 +301,7 @@
with hooks_control(session, session.HOOKS_ALLOW_ALL, 'integrity'):
for rschema in repo.schema.relations():
rpermsdict = permsdict.get(rschema.eid, {})
- for rdef in rschema.rdefs.itervalues():
+ for rdef in rschema.rdefs.values():
for action in rdef.ACTIONS:
actperms = []
for something in rpermsdict.get(action == 'update' and 'add' or action, ()):
--- a/misc/migration/postcreate.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/migration/postcreate.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,13 +16,19 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""cubicweb post creation script, set user's workflow"""
+from __future__ import print_function
+
+from six import text_type
+
+from cubicweb import _
+
# insert versions
create_entity('CWProperty', pkey=u'system.version.cubicweb',
- value=unicode(config.cubicweb_version()))
+ value=text_type(config.cubicweb_version()))
for cube in config.cubes():
create_entity('CWProperty', pkey=u'system.version.%s' % cube.lower(),
- value=unicode(config.cube_version(cube)))
+ value=text_type(config.cube_version(cube)))
# some entities have been added before schema entities, fix the 'is' and
# 'is_instance_of' relations
@@ -30,8 +36,8 @@
sql('INSERT INTO %s_relation '
'SELECT X.eid, ET.cw_eid FROM entities as X, cw_CWEType as ET '
'WHERE X.type=ET.cw_name AND NOT EXISTS('
- ' SELECT 1 from is_relation '
- ' WHERE eid_from=X.eid AND eid_to=ET.cw_eid)' % rtype)
+ ' SELECT 1 from %s_relation '
+ ' WHERE eid_from=X.eid AND eid_to=ET.cw_eid)' % (rtype, rtype))
# user workflow
userwf = add_workflow(_('default user workflow'), 'CWUser')
@@ -46,11 +52,11 @@
if hasattr(config, 'anonymous_user'):
anonlogin, anonpwd = config.anonymous_user()
if anonlogin == session.user.login:
- print 'you are using a manager account as anonymous user.'
- print 'Hopefully this is not a production instance...'
+ print('you are using a manager account as anonymous user.')
+ print('Hopefully this is not a production instance...')
elif anonlogin:
from cubicweb.server import create_user
- create_user(session, unicode(anonlogin), anonpwd, u'guests')
+ create_user(session, text_type(anonlogin), anonpwd, u'guests')
# need this since we already have at least one user in the database (the default admin)
for user in rql('Any X WHERE X is CWUser').entities():
--- a/misc/scripts/cwuser_ldap2system.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/scripts/cwuser_ldap2system.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,3 +1,5 @@
+from __future__ import print_function
+
import base64
from cubicweb.server.utils import crypt_password
@@ -20,10 +22,10 @@
rset = sql("SELECT eid,type,source,extid,mtime FROM entities WHERE source!='system'", ask_confirm=False)
for eid, type, source, extid, mtime in rset:
if type != 'CWUser':
- print "don't know what to do with entity type", type
+ print("don't know what to do with entity type", type)
continue
if not source.lower().startswith('ldap'):
- print "don't know what to do with source type", source
+ print("don't know what to do with source type", source)
continue
extid = base64.decodestring(extid)
ldapinfos = [x.strip().split('=') for x in extid.split(',')]
@@ -33,7 +35,7 @@
args = dict(eid=eid, type=type, source=source, login=login,
firstname=firstname, surname=surname, mtime=mtime,
pwd=dbhelper.binary_value(crypt_password('toto')))
- print args
+ print(args)
sql(insert, args)
sql(update, args)
--- a/misc/scripts/detect_cycle.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/scripts/detect_cycle.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,9 +1,10 @@
+from __future__ import print_function
try:
rtype, = __args__
except ValueError:
- print 'USAGE: cubicweb-ctl shell <instance> detect_cycle.py -- <relation type>'
- print
+ print('USAGE: cubicweb-ctl shell <instance> detect_cycle.py -- <relation type>')
+ print()
graph = {}
for fromeid, toeid in rql('Any X,Y WHERE X %s Y' % rtype):
@@ -12,4 +13,4 @@
from logilab.common.graph import get_cycles
for cycle in get_cycles(graph):
- print 'cycle', '->'.join(str(n) for n in cycle)
+ print('cycle', '->'.join(str(n) for n in cycle))
--- a/misc/scripts/ldap_change_base_dn.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/scripts/ldap_change_base_dn.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,10 +1,12 @@
+from __future__ import print_function
+
from base64 import b64decode, b64encode
try:
uri, newdn = __args__
except ValueError:
- print 'USAGE: cubicweb-ctl shell <instance> ldap_change_base_dn.py -- <ldap source uri> <new dn>'
- print
- print 'you should not have updated your sources file yet'
+ print('USAGE: cubicweb-ctl shell <instance> ldap_change_base_dn.py -- <ldap source uri> <new dn>')
+ print()
+ print('you should not have updated your sources file yet')
olddn = repo.sources_by_uri[uri].config['user-base-dn']
@@ -16,9 +18,9 @@
olduserdn = b64decode(extid)
newuserdn = olduserdn.replace(olddn, newdn)
if newuserdn != olduserdn:
- print olduserdn, '->', newuserdn
+ print(olduserdn, '->', newuserdn)
sql("UPDATE entities SET extid='%s' WHERE eid=%s" % (b64encode(newuserdn), eid))
commit()
-print 'you can now update the sources file to the new dn and restart the instance'
+print('you can now update the sources file to the new dn and restart the instance')
--- a/misc/scripts/ldapuser2ldapfeed.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/scripts/ldapuser2ldapfeed.py Thu Dec 10 12:34:15 2015 +0100
@@ -2,6 +2,8 @@
Once this script is run, execute c-c db-check to cleanup relation tables.
"""
+from __future__ import print_function
+
import sys
from collections import defaultdict
from logilab.common.shellutils import generate_password
@@ -14,12 +16,12 @@
' on the command line)')
sys.exit(1)
except KeyError:
- print '%s is not an active source' % source_name
+ print('%s is not an active source' % source_name)
sys.exit(1)
# check source is reachable before doing anything
if not source.get_connection().cnx:
- print '%s is not reachable. Fix this before running this script' % source_name
+ print('%s is not reachable. Fix this before running this script' % source_name)
sys.exit(1)
raw_input('Ensure you have shutdown all instances of this application before continuing.'
@@ -31,7 +33,7 @@
from cubicweb.server.edition import EditedEntity
-print '******************** backport entity content ***************************'
+print('******************** backport entity content ***************************')
todelete = defaultdict(list)
extids = set()
@@ -39,17 +41,17 @@
for entity in rql('Any X WHERE X cw_source S, S eid %(s)s', {'s': source.eid}).entities():
etype = entity.cw_etype
if not source.support_entity(etype):
- print "source doesn't support %s, delete %s" % (etype, entity.eid)
+ print("source doesn't support %s, delete %s" % (etype, entity.eid))
todelete[etype].append(entity)
continue
try:
entity.complete()
except Exception:
- print '%s %s much probably deleted, delete it (extid %s)' % (
- etype, entity.eid, entity.cw_metainformation()['extid'])
+ print('%s %s much probably deleted, delete it (extid %s)' % (
+ etype, entity.eid, entity.cw_metainformation()['extid']))
todelete[etype].append(entity)
continue
- print 'get back', etype, entity.eid
+ print('get back', etype, entity.eid)
entity.cw_edited = EditedEntity(entity, **entity.cw_attr_cache)
if not entity.creation_date:
entity.cw_edited['creation_date'] = datetime.now()
@@ -61,7 +63,7 @@
if not entity.cwuri:
entity.cw_edited['cwuri'] = '%s/?dn=%s' % (
source.urls[0], extid.decode('utf-8', 'ignore'))
- print entity.cw_edited
+ print(entity.cw_edited)
if extid in extids:
duplicates.append(extid)
continue
@@ -73,13 +75,13 @@
# only cleanup entities table, remaining stuff should be cleaned by a c-c
# db-check to be run after this script
if duplicates:
- print 'found %s duplicate entries' % len(duplicates)
+ print('found %s duplicate entries' % len(duplicates))
from pprint import pprint
pprint(duplicates)
-print len(todelete), 'entities will be deleted'
-for etype, entities in todelete.iteritems():
- print 'deleting', etype, [e.login for e in entities]
+print(len(todelete), 'entities will be deleted')
+for etype, entities in todelete.items():
+ print('deleting', etype, [e.login for e in entities])
system_source.delete_info_multi(session, entities, source_name)
@@ -89,9 +91,8 @@
if raw_input('Commit?') in 'yY':
- print 'committing'
+ print('committing')
commit()
else:
rollback()
- print 'rolled back'
-
+ print('rolled back')
--- a/misc/scripts/pyroforge2datafeed.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/scripts/pyroforge2datafeed.py Thu Dec 10 12:34:15 2015 +0100
@@ -2,6 +2,8 @@
Once this script is run, execute c-c db-check to cleanup relation tables.
"""
+from __future__ import print_function
+
import sys
try:
@@ -12,14 +14,14 @@
' on the command line)')
sys.exit(1)
except KeyError:
- print '%s is not an active source' % source_name
+ print('%s is not an active source' % source_name)
sys.exit(1)
# check source is reachable before doing anything
try:
source.get_connection()._repo
except AttributeError:
- print '%s is not reachable. Fix this before running this script' % source_name
+ print('%s is not reachable. Fix this before running this script' % source_name)
sys.exit(1)
raw_input('Ensure you have shutdown all instances of this application before continuing.'
@@ -39,7 +41,7 @@
))
-print '******************** backport entity content ***************************'
+print('******************** backport entity content ***************************')
from cubicweb.server import debugged
todelete = {}
@@ -47,20 +49,20 @@
for entity in rql('Any X WHERE X cw_source S, S eid %(s)s', {'s': source.eid}).entities():
etype = entity.cw_etype
if not source.support_entity(etype):
- print "source doesn't support %s, delete %s" % (etype, entity.eid)
+ print("source doesn't support %s, delete %s" % (etype, entity.eid))
elif etype in DONT_GET_BACK_ETYPES:
- print 'ignore %s, delete %s' % (etype, entity.eid)
+ print('ignore %s, delete %s' % (etype, entity.eid))
else:
try:
entity.complete()
if not host in entity.cwuri:
- print 'SKIP foreign entity', entity.cwuri, source.config['base-url']
+ print('SKIP foreign entity', entity.cwuri, source.config['base-url'])
continue
except Exception:
- print '%s %s much probably deleted, delete it (extid %s)' % (
- etype, entity.eid, entity.cw_metainformation()['extid'])
+ print('%s %s much probably deleted, delete it (extid %s)' % (
+ etype, entity.eid, entity.cw_metainformation()['extid']))
else:
- print 'get back', etype, entity.eid
+ print('get back', etype, entity.eid)
entity.cw_edited = EditedEntity(entity, **entity.cw_attr_cache)
system_source.add_entity(session, entity)
sql("UPDATE entities SET asource=%(asource)s, source='system', extid=%(extid)s "
@@ -72,11 +74,11 @@
# only cleanup entities table, remaining stuff should be cleaned by a c-c
# db-check to be run after this script
-for entities in todelete.itervalues():
+for entities in todelete.values():
system_source.delete_info_multi(session, entities, source_name)
-print '******************** backport mapping **********************************'
+print('******************** backport mapping **********************************')
session.disable_hook_categories('cw.sources')
mapping = []
for mappart in rql('Any X,SCH WHERE X cw_schema SCH, X cw_for_source S, S eid %(s)s',
@@ -85,13 +87,13 @@
if schemaent.cw_etype != 'CWEType':
assert schemaent.cw_etype == 'CWRType'
sch = schema._eid_index[schemaent.eid]
- for rdef in sch.rdefs.itervalues():
+ for rdef in sch.rdefs.values():
if not source.support_entity(rdef.subject) \
or not source.support_entity(rdef.object):
continue
if rdef.subject in DONT_GET_BACK_ETYPES \
and rdef.object in DONT_GET_BACK_ETYPES:
- print 'dont map', rdef
+ print('dont map', rdef)
continue
if rdef.subject in DONT_GET_BACK_ETYPES:
options = u'action=link\nlinkattr=name'
@@ -105,7 +107,7 @@
roles = 'object',
else:
roles = 'subject',
- print 'map', rdef, options, roles
+ print('map', rdef, options, roles)
for role in roles:
mapping.append( (
(str(rdef.subject), str(rdef.rtype), str(rdef.object)),
--- a/misc/scripts/repair_file_1-9_migration.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/scripts/repair_file_1-9_migration.py Thu Dec 10 12:34:15 2015 +0100
@@ -4,13 +4,14 @@
* on our intranet on July 07 2010
* on our extranet on July 16 2010
"""
+from __future__ import print_function
try:
backupinstance, = __args__
except ValueError:
- print 'USAGE: cubicweb-ctl shell <instance> repair_file_1-9_migration.py -- <backup instance id>'
- print
- print 'you should restored the backup on a new instance, accessible through pyro'
+ print('USAGE: cubicweb-ctl shell <instance> repair_file_1-9_migration.py -- <backup instance id>')
+ print()
+ print('you should restored the backup on a new instance, accessible through pyro')
from cubicweb import cwconfig, dbapi
from cubicweb.server.session import hooks_control
@@ -32,20 +33,20 @@
'XX from_entity YY, YY name "File")'):
if rtype in ('is', 'is_instance_of'):
continue
- print rtype
+ print(rtype)
for feid, xeid in backupcu.execute('Any F,X WHERE F %s X, F is IN (File,Image)' % rtype):
- print 'restoring relation %s between file %s and %s' % (rtype, feid, xeid),
- print rql('SET F %s X WHERE F eid %%(f)s, X eid %%(x)s, NOT F %s X' % (rtype, rtype),
- {'f': feid, 'x': xeid})
+ print('restoring relation %s between file %s and %s' % (rtype, feid, xeid), end=' ')
+ print(rql('SET F %s X WHERE F eid %%(f)s, X eid %%(x)s, NOT F %s X' % (rtype, rtype),
+ {'f': feid, 'x': xeid}))
for rtype, in backupcu.execute('DISTINCT Any RTN WHERE X relation_type RT, RT name RTN,'
'X to_entity Y, Y name "Image", X is CWRelation, '
'EXISTS(XX is CWRelation, XX relation_type RT, '
'XX to_entity YY, YY name "File")'):
- print rtype
+ print(rtype)
for feid, xeid in backupcu.execute('Any F,X WHERE X %s F, F is IN (File,Image)' % rtype):
- print 'restoring relation %s between %s and file %s' % (rtype, xeid, feid),
- print rql('SET X %s F WHERE F eid %%(f)s, X eid %%(x)s, NOT X %s F' % (rtype, rtype),
- {'f': feid, 'x': xeid})
+ print('restoring relation %s between %s and file %s' % (rtype, xeid, feid), end=' ')
+ print(rql('SET X %s F WHERE F eid %%(f)s, X eid %%(x)s, NOT X %s F' % (rtype, rtype),
+ {'f': feid, 'x': xeid}))
commit()
--- a/misc/scripts/repair_splitbrain_ldapuser_source.py Wed Dec 09 18:42:13 2015 +0100
+++ b/misc/scripts/repair_splitbrain_ldapuser_source.py Thu Dec 10 12:34:15 2015 +0100
@@ -14,6 +14,7 @@
deciding to apply it for you. And then ADAPT it tou your needs.
"""
+from __future__ import print_function
import base64
from collections import defaultdict
@@ -28,12 +29,12 @@
' on the command line)')
sys.exit(1)
except KeyError:
- print '%s is not an active source' % source_name
+ print('%s is not an active source' % source_name)
sys.exit(1)
# check source is reachable before doing anything
if not source.get_connection().cnx:
- print '%s is not reachable. Fix this before running this script' % source_name
+ print('%s is not reachable. Fix this before running this script' % source_name)
sys.exit(1)
def find_dupes():
@@ -52,11 +53,11 @@
CWUser = schema['CWUser']
for extid, eids in dupes.items():
newest = eids.pop() # we merge everything on the newest
- print 'merging ghosts of', extid, 'into', newest
+ print('merging ghosts of', extid, 'into', newest)
# now we merge pairwise into the newest
for old in eids:
subst = {'old': old, 'new': newest}
- print ' merging', old
+ print(' merging', old)
gone_eids.append(old)
for rschema in CWUser.subject_relations():
if rschema.final or rschema == 'identity':
@@ -83,24 +84,24 @@
rollback()
return
commit() # XXX flushing operations is wanted rather than really committing
- print 'clean up entities table'
+ print('clean up entities table')
sql('DELETE FROM entities WHERE eid IN (%s)' % (', '.join(str(x) for x in gone_eids)))
commit()
def main():
dupes = find_dupes()
if not dupes:
- print 'No duplicate user'
+ print('No duplicate user')
return
- print 'Found %s duplicate user instances' % len(dupes)
+ print('Found %s duplicate user instances' % len(dupes))
while True:
- print 'Fix or dry-run? (f/d) ... or Ctrl-C to break out'
+ print('Fix or dry-run? (f/d) ... or Ctrl-C to break out')
answer = raw_input('> ')
if answer.lower() not in 'fd':
continue
- print 'Please STOP THE APPLICATION INSTANCES (service or interactive), and press Return when done.'
+ print('Please STOP THE APPLICATION INSTANCES (service or interactive), and press Return when done.')
raw_input('<I swear all running instances and workers of the application are stopped>')
with hooks_control(session, session.HOOKS_DENY_ALL):
merge_dupes(dupes, docommit=answer=='f')
--- a/multipart.py Wed Dec 09 18:42:13 2015 +0100
+++ b/multipart.py Thu Dec 10 12:34:15 2015 +0100
@@ -41,14 +41,13 @@
from wsgiref.headers import Headers
import re, sys
try:
- from urlparse import parse_qs
-except ImportError: # pragma: no cover (fallback for Python 2.5)
- from cgi import parse_qs
-try:
from io import BytesIO
except ImportError: # pragma: no cover (fallback for Python 2.5)
from StringIO import StringIO as BytesIO
+from six import PY3, text_type
+from six.moves.urllib.parse import parse_qs
+
##############################################################################
################################ Helper & Misc ################################
##############################################################################
@@ -63,7 +62,7 @@
""" A dict that remembers old values for each key """
def __init__(self, *a, **k):
self.dict = dict()
- for k, v in dict(*a, **k).iteritems():
+ for k, v in dict(*a, **k).items():
self[k] = v
def __len__(self): return len(self.dict)
@@ -84,12 +83,12 @@
return self.dict[key][index]
def iterallitems(self):
- for key, values in self.dict.iteritems():
+ for key, values in self.dict.items():
for value in values:
yield key, value
def tob(data, enc='utf8'): # Convert strings to bytes (py2 and py3)
- return data.encode(enc) if isinstance(data, unicode) else data
+ return data.encode(enc) if isinstance(data, text_type) else data
def copy_file(stream, target, maxread=-1, buffer_size=2*16):
''' Read from :stream and write to :target until :maxread or EOF. '''
@@ -397,17 +396,21 @@
'application/x-url-encoded'):
mem_limit = kw.get('mem_limit', 2**20)
if content_length > mem_limit:
- raise MultipartError("Request to big. Increase MAXMEM.")
+ raise MultipartError("Request too big. Increase MAXMEM.")
data = stream.read(mem_limit)
if stream.read(1): # These is more that does not fit mem_limit
- raise MultipartError("Request to big. Increase MAXMEM.")
+ raise MultipartError("Request too big. Increase MAXMEM.")
+ if PY3:
+ data = data.decode('ascii')
data = parse_qs(data, keep_blank_values=True)
- for key, values in data.iteritems():
+ for key, values in data.items():
for value in values:
- forms[key] = value.decode(charset)
+ if PY3:
+ forms[key] = value
+ else:
+ forms[key.decode(charset)] = value.decode(charset)
else:
raise MultipartError("Unsupported content type.")
except MultipartError:
if strict: raise
return forms, files
-
--- a/predicates.py Wed Dec 09 18:42:13 2015 +0100
+++ b/predicates.py Thu Dec 10 12:34:15 2015 +0100
@@ -24,6 +24,9 @@
from warnings import warn
from operator import eq
+from six import string_types, integer_types
+from six.moves import range
+
from logilab.common.deprecation import deprecated
from logilab.common.registry import Predicate, objectify_predicate, yes
@@ -106,7 +109,7 @@
if accept_none is None:
accept_none = self.accept_none
if not accept_none and \
- any(rset[i][col] is None for i in xrange(len(rset))):
+ any(row[col] is None for row in rset):
return 0
etypes = rset.column_types(col)
else:
@@ -332,7 +335,7 @@
# on rset containing several entity types, each row may be
# individually adaptable, while the whole rset won't be if the
# same adapter can't be used for each type
- for row in xrange(len(kwargs['rset'])):
+ for row in range(len(kwargs['rset'])):
kwargs.setdefault('col', 0)
_score = super(adaptable, self).__call__(cls, req, row=row, **kwargs)
if not _score:
@@ -489,10 +492,13 @@
page_size = kwargs.get('page_size')
if page_size is None:
page_size = req.form.get('page_size')
+ if page_size is not None:
+ try:
+ page_size = int(page_size)
+ except ValueError:
+ page_size = None
if page_size is None:
page_size = req.property_value('navigation.page-size')
- else:
- page_size = int(page_size)
if len(rset) <= (page_size*self.nbpages):
return 0
return self.nbpages
@@ -611,7 +617,7 @@
super(is_instance, self).__init__(**kwargs)
self.expected_etypes = expected_etypes
for etype in self.expected_etypes:
- assert isinstance(etype, basestring), etype
+ assert isinstance(etype, string_types), etype
def __str__(self):
return '%s(%s)' % (self.__class__.__name__,
@@ -671,7 +677,7 @@
score = scorefunc(*args, **kwargs)
if not score:
return 0
- if isinstance(score, (int, long)):
+ if isinstance(score, integer_types):
return score
return 1
self.score_entity = intscore
@@ -828,7 +834,7 @@
class has_related_entities(EntityPredicate):
"""Return 1 if entity support the specified relation and has some linked
- entities by this relation , optionaly filtered according to the specified
+ entities by this relation , optionally filtered according to the specified
target type.
The relation is specified by the following initializer arguments:
@@ -1091,7 +1097,7 @@
"""
if from_state_name is not None:
warn("on_fire_transition's from_state_name argument is unused", DeprecationWarning)
- if isinstance(tr_names, basestring):
+ if isinstance(tr_names, string_types):
tr_names = set((tr_names,))
def match_etype_and_transition(trinfo):
# take care trinfo.transition is None when calling change_state
@@ -1291,7 +1297,7 @@
raise ValueError("match_form_params() can't be called with both "
"positional and named arguments")
if expected:
- if len(expected) == 1 and not isinstance(expected[0], basestring):
+ if len(expected) == 1 and not isinstance(expected[0], string_types):
raise ValueError("match_form_params() positional arguments "
"must be strings")
super(match_form_params, self).__init__(*expected)
--- a/pylintext.py Wed Dec 09 18:42:13 2015 +0100
+++ b/pylintext.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,7 +17,7 @@
def cubicweb_transform(module):
# handle objectify_predicate decorator (and its former name until bw compat
# is kept). Only look at module level functions, should be enough.
- for assnodes in module.locals.itervalues():
+ for assnodes in module.locals.values():
for node in assnodes:
if isinstance(node, scoped_nodes.Function) and node.decorators:
for decorator in node.decorators.nodes:
@@ -48,4 +48,3 @@
def register(linter):
"""called when loaded by pylint --load-plugins, nothing to do here"""
MANAGER.register_transform(nodes.Module, cubicweb_transform)
-
--- a/repoapi.py Wed Dec 09 18:42:13 2015 +0100
+++ b/repoapi.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,21 +17,17 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""Official API to access the content of a repository
"""
+from warnings import warn
+
+from six import add_metaclass
+
from logilab.common.deprecation import class_deprecated
from cubicweb.utils import parse_repo_uri
-from cubicweb import ConnectionError, AuthenticationError
+from cubicweb import AuthenticationError
from cubicweb.server.session import Connection
-### private function for specific method ############################
-
-def _get_inmemory_repo(config, vreg=None):
- from cubicweb.server.repository import Repository
- from cubicweb.server.utils import TasksManager
- return Repository(config, TasksManager(), vreg=vreg)
-
-
### public API ######################################################
def get_repository(uri=None, config=None, vreg=None):
@@ -41,16 +37,11 @@
The returned repository may be an in-memory repository or a proxy object
using a specific RPC method, depending on the given URI.
"""
- if uri is None:
- return _get_inmemory_repo(config, vreg)
-
- protocol, hostport, appid = parse_repo_uri(uri)
+ if uri is not None:
+ warn('[3.22] get_repository only wants a config')
- if protocol == 'inmemory':
- # me may have been called with a dummy 'inmemory://' uri ...
- return _get_inmemory_repo(config, vreg)
-
- raise ConnectionError('unknown protocol: `%s`' % protocol)
+ assert config is not None, 'get_repository(config=config)'
+ return config.repository(vreg)
def connect(repo, login, **kwargs):
"""Take credential and return associated Connection.
@@ -75,6 +66,6 @@
return connect(repo, anon_login, password=anon_password)
+@add_metaclass(class_deprecated)
class ClientConnection(Connection):
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.20] %(cls)s is deprecated, use Connection instead'
--- a/req.py Wed Dec 09 18:42:13 2015 +0100
+++ b/req.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,10 +20,10 @@
__docformat__ = "restructuredtext en"
from warnings import warn
-from urlparse import urlsplit, urlunsplit
-from urllib import quote as urlquote, unquote as urlunquote
from datetime import time, datetime, timedelta
-from cgi import parse_qs, parse_qsl
+
+from six import PY2, PY3, text_type
+from six.moves.urllib.parse import parse_qs, parse_qsl, quote as urlquote, unquote as urlunquote, urlsplit, urlunsplit
from logilab.common.decorators import cached
from logilab.common.deprecation import deprecated
@@ -73,7 +73,7 @@
# connection
self.user = None
self.local_perm_cache = {}
- self._ = unicode
+ self._ = text_type
def _set_user(self, orig_user):
"""set the user for this req_session_base
@@ -219,7 +219,7 @@
parts.append(
'%(varname)s %(attr)s X, '
'%(varname)s eid %%(reverse_%(attr)s)s'
- % {'attr': attr, 'varname': varmaker.next()})
+ % {'attr': attr, 'varname': next(varmaker)})
else:
assert attr in eschema.subjrels, \
'%s not in %s subject relations' % (attr, eschema)
@@ -300,7 +300,7 @@
def build_url_params(self, **kwargs):
"""return encoded params to incorporate them in a URL"""
args = []
- for param, values in kwargs.iteritems():
+ for param, values in kwargs.items():
if not isinstance(values, (list, tuple)):
values = (values,)
for value in values:
@@ -313,7 +313,7 @@
necessary encoding / decoding. Also it's designed to quote each
part of a url path and so the '/' character will be encoded as well.
"""
- if isinstance(value, unicode):
+ if PY2 and isinstance(value, unicode):
quoted = urlquote(value.encode(self.encoding), safe=safe)
return unicode(quoted, self.encoding)
return urlquote(str(value), safe=safe)
@@ -324,6 +324,8 @@
decoding is based on `self.encoding` which is the encoding
used in `url_quote`
"""
+ if PY3:
+ return urlunquote(quoted)
if isinstance(quoted, unicode):
quoted = quoted.encode(self.encoding)
try:
@@ -333,6 +335,10 @@
def url_parse_qsl(self, querystring):
"""return a list of (key, val) found in the url quoted query string"""
+ if PY3:
+ for key, val in parse_qsl(querystring):
+ yield key, val
+ return
if isinstance(querystring, unicode):
querystring = querystring.encode(self.encoding)
for key, val in parse_qsl(querystring):
@@ -348,12 +354,12 @@
newparams may only be mono-valued.
"""
- if isinstance(url, unicode):
+ if PY2 and isinstance(url, unicode):
url = url.encode(self.encoding)
schema, netloc, path, query, fragment = urlsplit(url)
query = parse_qs(query)
# sort for testing predictability
- for key, val in sorted(newparams.iteritems()):
+ for key, val in sorted(newparams.items()):
query[key] = (self.url_quote(val),)
query = '&'.join(u'%s=%s' % (param, value)
for param, values in sorted(query.items())
--- a/rqlrewrite.py Wed Dec 09 18:42:13 2015 +0100
+++ b/rqlrewrite.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,6 +22,8 @@
"""
__docformat__ = "restructuredtext en"
+from six import text_type, string_types
+
from rql import nodes as n, stmts, TypeResolverException
from rql.utils import common_parent
@@ -54,7 +56,7 @@
eschema = schema.eschema
allpossibletypes = {}
for solution in solutions:
- for varname, etype in solution.iteritems():
+ for varname, etype in solution.items():
# XXX not considering aliases by design, right ?
if varname not in newroot.defined_vars or eschema(etype).final:
continue
@@ -92,7 +94,7 @@
for etype in sorted(possibletypes):
node.append(n.Constant(etype, 'etype'))
else:
- etype = iter(possibletypes).next()
+ etype = next(iter(possibletypes))
node = n.Constant(etype, 'etype')
comp = mytyperel.children[1]
comp.replace(comp.children[0], node)
@@ -286,7 +288,7 @@
if fnode.name == 'FTIRANK':
# we've to fetch the has_text relation as well
var = fnode.children[0].variable
- rel = iter(var.stinfo['ftirels']).next()
+ rel = next(iter(var.stinfo['ftirels']))
assert not rel.ored(), 'unsupported'
newselect.add_restriction(rel.copy(newselect))
# remove relation from the orig select and
@@ -330,7 +332,7 @@
union.replace(select, newselect)
elif not () in localchecks:
union.remove(select)
- for lcheckdef, lchecksolutions in localchecks.iteritems():
+ for lcheckdef, lchecksolutions in localchecks.items():
if not lcheckdef:
continue
myrqlst = select.copy(solutions=lchecksolutions)
@@ -427,7 +429,7 @@
def insert_varmap_snippets(self, varmap, rqlexprs, varexistsmap):
try:
self.init_from_varmap(varmap, varexistsmap)
- except VariableFromSubQuery, ex:
+ except VariableFromSubQuery as ex:
# variable may have been moved to a newly inserted subquery
# we should insert snippet in that subquery
subquery = self.select.aliases[ex.variable].query
@@ -548,7 +550,7 @@
'cant check security of %s, ambigous type for %s in %s',
stmt, varname, key[0]) # key[0] == the rql expression
raise Unauthorized()
- etype = iter(ptypes).next()
+ etype = next(iter(ptypes))
eschema = self.schema.eschema(etype)
if not eschema.has_perm(self.session, action):
rqlexprs = eschema.get_rqlexprs(action)
@@ -621,7 +623,7 @@
while argname in self.kwargs:
argname = subselect.allocate_varname()
subselect.add_constant_restriction(subselect.get_variable(self.u_varname),
- 'eid', unicode(argname), 'Substitute')
+ 'eid', text_type(argname), 'Substitute')
self.kwargs[argname] = self.session.user.eid
add_types_restriction(self.schema, subselect, subselect,
solutions=self.solutions)
@@ -646,7 +648,7 @@
# insert "is" where necessary
varexistsmap = {}
self.removing_ambiguity = True
- for (erqlexpr, varmap, oldvarname), etype in variantes[0].iteritems():
+ for (erqlexpr, varmap, oldvarname), etype in variantes[0].items():
varname = self.rewritten[(erqlexpr, varmap, oldvarname)]
var = self.select.defined_vars[varname]
exists = var.references()[0].scope
@@ -655,7 +657,7 @@
# insert ORED exists where necessary
for variante in variantes[1:]:
self.insert_snippets(snippets, varexistsmap)
- for key, etype in variante.iteritems():
+ for key, etype in variante.items():
varname = self.rewritten[key]
try:
var = self.select.defined_vars[varname]
@@ -674,7 +676,7 @@
variantes = set()
for sol in newsolutions:
variante = []
- for key, newvar in self.rewritten.iteritems():
+ for key, newvar in self.rewritten.items():
variante.append( (key, sol[newvar]) )
variantes.add(tuple(variante))
# rebuild variantes as dict
@@ -682,7 +684,7 @@
# remove variable which have always the same type
for key in self.rewritten:
it = iter(variantes)
- etype = it.next()[key]
+ etype = next(it)[key]
for variante in it:
if variante[key] != etype:
break
@@ -700,7 +702,7 @@
# no more references, undefine the variable
del self.select.defined_vars[vref.name]
removed.add(vref.name)
- for key, newvar in self.rewritten.items(): # I mean items we alter it
+ for key, newvar in list(self.rewritten.items()):
if newvar in removed:
del self.rewritten[key]
@@ -760,7 +762,7 @@
# insert "U eid %(u)s"
stmt.add_constant_restriction(
stmt.get_variable(self.u_varname),
- 'eid', unicode(argname), 'Substitute')
+ 'eid', text_type(argname), 'Substitute')
self.kwargs[argname] = self.session.user.eid
return self.u_varname
key = (self.current_expr, self.varmap, vname)
@@ -883,7 +885,7 @@
return n.Constant(vi['const'], 'Int')
return n.VariableRef(stmt.get_variable(selectvar))
vname_or_term = self._get_varname_or_term(node.name)
- if isinstance(vname_or_term, basestring):
+ if isinstance(vname_or_term, string_types):
return n.VariableRef(stmt.get_variable(vname_or_term))
# shared term
return vname_or_term.copy(stmt)
--- a/rset.py Wed Dec 09 18:42:13 2015 +0100
+++ b/rset.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,11 +16,13 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""The `ResultSet` class which is returned as result of an rql query"""
-
__docformat__ = "restructuredtext en"
from warnings import warn
+from six import PY3
+from six.moves import range
+
from logilab.common import nullobject
from logilab.common.decorators import cached, clear_cache, copy_cache
from rql import nodes, stmts
@@ -101,7 +103,7 @@
if self._rsetactions is None:
self._rsetactions = {}
if kwargs:
- key = tuple(sorted(kwargs.iteritems()))
+ key = tuple(sorted(kwargs.items()))
else:
key = None
try:
@@ -120,10 +122,6 @@
"""returns the ith element of the result set"""
return self.rows[i] #ResultSetRow(self.rows[i])
- def __getslice__(self, i, j):
- """returns slice [i:j] of the result set"""
- return self.rows[i:j]
-
def __iter__(self):
"""Returns an iterator over rows"""
return iter(self.rows)
@@ -186,7 +184,7 @@
"""
rows, descr = [], []
rset = self.copy(rows, descr)
- for i in xrange(len(self)):
+ for i in range(len(self)):
if not filtercb(self.get_entity(i, col)):
continue
rows.append(self.rows[i])
@@ -215,10 +213,10 @@
rset = self.copy(rows, descr)
if col >= 0:
entities = sorted(enumerate(self.entities(col)),
- key=lambda (i, e): keyfunc(e), reverse=reverse)
+ key=lambda t: keyfunc(t[1]), reverse=reverse)
else:
entities = sorted(enumerate(self),
- key=lambda (i, e): keyfunc(e), reverse=reverse)
+ key=lambda t: keyfunc(t[1]), reverse=reverse)
for index, _ in entities:
rows.append(self.rows[index])
descr.append(self.description[index])
@@ -311,7 +309,7 @@
newselect.limit = limit
newselect.offset = offset
aliases = [nodes.VariableRef(newselect.get_variable(chr(65+i), i))
- for i in xrange(len(rqlst.children[0].selection))]
+ for i in range(len(rqlst.children[0].selection))]
for vref in aliases:
newselect.append_selected(nodes.VariableRef(vref.variable))
newselect.set_with([nodes.SubQuery(aliases, rqlst)], check=False)
@@ -322,7 +320,7 @@
return rql
def limit(self, limit, offset=0, inplace=False):
- """limit the result set to the given number of rows optionaly starting
+ """limit the result set to the given number of rows optionally starting
from an index different than 0
:type limit: int
@@ -373,6 +371,8 @@
warn('[3.21] the "encoded" argument is deprecated', DeprecationWarning)
encoding = self.req.encoding
rqlstr = self.syntax_tree().as_string(kwargs=self.args)
+ if PY3:
+ return rqlstr
# sounds like we get encoded or unicode string due to a bug in as_string
if not encoded:
if isinstance(rqlstr, unicode):
@@ -387,7 +387,7 @@
def entities(self, col=0):
"""iter on entities with eid in the `col` column of the result set"""
- for i in xrange(len(self)):
+ for i in range(len(self)):
# may have None values in case of outer join (or aggregat on eid
# hacks)
if self.rows[i][col] is not None:
@@ -507,9 +507,9 @@
eschema = entity.e_schema
eid_col, attr_cols, rel_cols = self._rset_structure(eschema, col)
entity.eid = rowvalues[eid_col]
- for attr, col_idx in attr_cols.iteritems():
+ for attr, col_idx in attr_cols.items():
entity.cw_attr_cache[attr] = rowvalues[col_idx]
- for (rtype, role), col_idx in rel_cols.iteritems():
+ for (rtype, role), col_idx in rel_cols.items():
value = rowvalues[col_idx]
if value is None:
if role == 'subject':
@@ -606,7 +606,7 @@
except AttributeError:
# not a variable
continue
- for i in xrange(len(select.selection)):
+ for i in range(len(select.selection)):
if i == col:
continue
coletype = self.description[row][i]
--- a/rtags.py Wed Dec 09 18:42:13 2015 +0100
+++ b/rtags.py Thu Dec 10 12:34:15 2015 +0100
@@ -40,6 +40,8 @@
import logging
from warnings import warn
+from six import string_types
+
from logilab.common.logging_ext import set_log_methods
from logilab.common.registry import RegistrableInstance, yes
@@ -95,7 +97,7 @@
def init(self, schema, check=True):
# XXX check existing keys against schema
if check:
- for (stype, rtype, otype, tagged), value in self._tagdefs.items():
+ for (stype, rtype, otype, tagged), value in list(self._tagdefs.items()):
for ertype in (stype, rtype, otype):
if ertype != '*' and not ertype in schema:
self.warning('removing rtag %s: %s, %s undefined in schema',
@@ -145,7 +147,7 @@
return tag
def _tag_etype_attr(self, etype, attr, desttype='*', *args, **kwargs):
- if isinstance(attr, basestring):
+ if isinstance(attr, string_types):
attr, role = attr, 'subject'
else:
attr, role = attr
--- a/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,15 +16,18 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""classes to define schemas for CubicWeb"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
-_ = unicode
import re
from os.path import join, basename
from logging import getLogger
from warnings import warn
+from six import PY2, text_type, string_types, add_metaclass
+from six.moves import range
+
from logilab.common import tempattr
from logilab.common.decorators import cached, clear_cache, monkeypatch, cachedproperty
from logilab.common.logging_ext import set_log_methods
@@ -45,7 +48,7 @@
from rql.analyze import ETypeResolver
import cubicweb
-from cubicweb import ETYPE_NAME_MAP, ValidationError, Unauthorized
+from cubicweb import ETYPE_NAME_MAP, ValidationError, Unauthorized, _
try:
from cubicweb import server
@@ -102,6 +105,9 @@
INTERNAL_TYPES = set(('CWProperty', 'CWCache', 'ExternalUri', 'CWDataImport',
'CWSource', 'CWSourceHostConfig', 'CWSourceSchemaConfig'))
+UNIQUE_CONSTRAINTS = ('SizeConstraint', 'FormatConstraint',
+ 'StaticVocabularyConstraint',
+ 'RQLVocabularyConstraint')
_LOGGER = getLogger('cubicweb.schemaloader')
@@ -142,7 +148,10 @@
suppressing and reinserting an expression if only a space has been
added/removed for instance)
"""
- return u', '.join(' '.join(expr.split()) for expr in rqlstring.split(','))
+ union = parse(u'Any 1 WHERE %s' % rqlstring).as_string()
+ if PY2 and isinstance(union, str):
+ union = union.decode('utf-8')
+ return union.split(' WHERE ', 1)[1]
def _check_valid_formula(rdef, formula_rqlst):
@@ -204,7 +213,7 @@
"""
self.eid = eid # eid of the entity representing this rql expression
assert mainvars, 'bad mainvars %s' % mainvars
- if isinstance(mainvars, basestring):
+ if isinstance(mainvars, string_types):
mainvars = set(splitstrip(mainvars))
elif not isinstance(mainvars, set):
mainvars = set(mainvars)
@@ -246,6 +255,9 @@
return self.expression == other.expression
return False
+ def __ne__(self, other):
+ return not (self == other)
+
def __hash__(self):
return hash(self.expression)
@@ -271,7 +283,7 @@
def transform_has_permission(self):
found = None
rqlst = self.rqlst
- for var in rqlst.defined_vars.itervalues():
+ for var in rqlst.defined_vars.values():
for varref in var.references():
rel = varref.relation()
if rel is None:
@@ -319,7 +331,7 @@
"""
creating = kwargs.get('creating')
if not creating and self.eid is not None:
- key = (self.eid, tuple(sorted(kwargs.iteritems())))
+ key = (self.eid, tuple(sorted(kwargs.items())))
try:
return _cw.local_perm_cache[key]
except KeyError:
@@ -363,7 +375,7 @@
get_eschema = _cw.vreg.schema.eschema
try:
for eaction, col in has_perm_defs:
- for i in xrange(len(rset)):
+ for i in range(len(rset)):
eschema = get_eschema(rset.description[i][col])
eschema.check_perm(_cw, eaction, eid=rset[i][col])
if self.eid is not None:
@@ -400,13 +412,35 @@
return self._check(_cw, x=eid, **kwargs)
return self._check(_cw, **kwargs)
-def constraint_by_eid(self, eid):
- for cstr in self.constraints:
- if cstr.eid == eid:
- return cstr
- raise ValueError('No constraint with eid %d' % eid)
-RelationDefinitionSchema.constraint_by_eid = constraint_by_eid
+
+class CubicWebRelationDefinitionSchema(RelationDefinitionSchema):
+ def constraint_by_eid(self, eid):
+ for cstr in self.constraints:
+ if cstr.eid == eid:
+ return cstr
+ raise ValueError('No constraint with eid %d' % eid)
+
+ def rql_expression(self, expression, mainvars=None, eid=None):
+ """rql expression factory"""
+ if self.rtype.final:
+ return ERQLExpression(expression, mainvars, eid)
+ return RRQLExpression(expression, mainvars, eid)
+ def check_permission_definitions(self):
+ super(CubicWebRelationDefinitionSchema, self).check_permission_definitions()
+ schema = self.subject.schema
+ for action, groups in self.permissions.items():
+ for group_or_rqlexpr in groups:
+ if action == 'read' and \
+ isinstance(group_or_rqlexpr, RQLExpression):
+ msg = "can't use rql expression for read permission of %s"
+ raise BadSchemaDefinition(msg % self)
+ if self.final and isinstance(group_or_rqlexpr, RRQLExpression):
+ msg = "can't use RRQLExpression on %s, use an ERQLExpression"
+ raise BadSchemaDefinition(msg % self)
+ if not self.final and isinstance(group_or_rqlexpr, ERQLExpression):
+ msg = "can't use ERQLExpression on %s, use a RRQLExpression"
+ raise BadSchemaDefinition(msg % self)
def vargraph(rqlst):
""" builds an adjacency graph of variables from the rql syntax tree, e.g:
@@ -522,7 +556,7 @@
if not deps:
eschemas.append(eschema)
del graph[eschema]
- for deps in graph.itervalues():
+ for deps in graph.values():
try:
deps.remove(eschema)
except KeyError:
@@ -548,9 +582,9 @@
key = key + '_' + form
# ensure unicode
if context is not None:
- return unicode(req.pgettext(context, key))
+ return text_type(req.pgettext(context, key))
else:
- return unicode(req._(key))
+ return text_type(req._(key))
# Schema objects definition ###################################################
@@ -576,7 +610,7 @@
assert action in self.ACTIONS, action
#assert action in self._groups, '%s %s' % (self, action)
try:
- return frozenset(g for g in self.permissions[action] if isinstance(g, basestring))
+ return frozenset(g for g in self.permissions[action] if isinstance(g, string_types))
except KeyError:
return ()
PermissionMixIn.get_groups = get_groups
@@ -595,7 +629,7 @@
assert action in self.ACTIONS, action
#assert action in self._rqlexprs, '%s %s' % (self, action)
try:
- return tuple(g for g in self.permissions[action] if not isinstance(g, basestring))
+ return tuple(g for g in self.permissions[action] if not isinstance(g, string_types))
except KeyError:
return ()
PermissionMixIn.get_rqlexprs = get_rqlexprs
@@ -665,7 +699,7 @@
groups = self.get_groups(action)
if _cw.user.matching_groups(groups):
if DBG:
- print ('check_perm: %r %r: user matches %s' % (action, _self_str, groups))
+ print('check_perm: %r %r: user matches %s' % (action, _self_str, groups))
return
# if 'owners' in allowed groups, check if the user actually owns this
# object, if so that's enough
@@ -676,14 +710,14 @@
kwargs.get('creating')
or ('eid' in kwargs and _cw.user.owns(kwargs['eid']))):
if DBG:
- print ('check_perm: %r %r: user is owner or creation time' %
- (action, _self_str))
+ print('check_perm: %r %r: user is owner or creation time' %
+ (action, _self_str))
return
# else if there is some rql expressions, check them
if DBG:
- print ('check_perm: %r %r %s' %
- (action, _self_str, [(rqlexpr, kwargs, rqlexpr.check(_cw, **kwargs))
- for rqlexpr in self.get_rqlexprs(action)]))
+ print('check_perm: %r %r %s' %
+ (action, _self_str, [(rqlexpr, kwargs, rqlexpr.check(_cw, **kwargs))
+ for rqlexpr in self.get_rqlexprs(action)]))
if any(rqlexpr.check(_cw, **kwargs)
for rqlexpr in self.get_rqlexprs(action)):
return
@@ -691,35 +725,10 @@
PermissionMixIn.check_perm = check_perm
-RelationDefinitionSchema._RPROPERTIES['eid'] = None
+CubicWebRelationDefinitionSchema._RPROPERTIES['eid'] = None
# remember rproperties defined at this point. Others will have to be serialized in
# CWAttribute.extra_props
-KNOWN_RPROPERTIES = RelationDefinitionSchema.ALL_PROPERTIES()
-
-def rql_expression(self, expression, mainvars=None, eid=None):
- """rql expression factory"""
- if self.rtype.final:
- return ERQLExpression(expression, mainvars, eid)
- return RRQLExpression(expression, mainvars, eid)
-RelationDefinitionSchema.rql_expression = rql_expression
-
-orig_check_permission_definitions = RelationDefinitionSchema.check_permission_definitions
-def check_permission_definitions(self):
- orig_check_permission_definitions(self)
- schema = self.subject.schema
- for action, groups in self.permissions.iteritems():
- for group_or_rqlexpr in groups:
- if action == 'read' and \
- isinstance(group_or_rqlexpr, RQLExpression):
- msg = "can't use rql expression for read permission of %s"
- raise BadSchemaDefinition(msg % self)
- if self.final and isinstance(group_or_rqlexpr, RRQLExpression):
- msg = "can't use RRQLExpression on %s, use an ERQLExpression"
- raise BadSchemaDefinition(msg % self)
- if not self.final and isinstance(group_or_rqlexpr, ERQLExpression):
- msg = "can't use ERQLExpression on %s, use a RRQLExpression"
- raise BadSchemaDefinition(msg % self)
-RelationDefinitionSchema.check_permission_definitions = check_permission_definitions
+KNOWN_RPROPERTIES = CubicWebRelationDefinitionSchema.ALL_PROPERTIES()
class CubicWebEntitySchema(EntitySchema):
@@ -763,7 +772,7 @@
def check_permission_definitions(self):
super(CubicWebEntitySchema, self).check_permission_definitions()
- for groups in self.permissions.itervalues():
+ for groups in self.permissions.values():
for group_or_rqlexpr in groups:
if isinstance(group_or_rqlexpr, RRQLExpression):
msg = "can't use RRQLExpression on %s, use an ERQLExpression"
@@ -870,6 +879,7 @@
class CubicWebRelationSchema(PermissionMixIn, RelationSchema):
permissions = {}
ACTIONS = ()
+ rdef_class = CubicWebRelationDefinitionSchema
def __init__(self, schema=None, rdef=None, eid=None, **kwargs):
if rdef is not None:
@@ -906,7 +916,7 @@
if rdef.may_have_permission(action, req):
return True
else:
- for rdef in self.rdefs.itervalues():
+ for rdef in self.rdefs.values():
if rdef.may_have_permission(action, req):
return True
return False
@@ -948,7 +958,7 @@
if not rdef.has_perm(_cw, action, **kwargs):
return False
else:
- for rdef in self.rdefs.itervalues():
+ for rdef in self.rdefs.values():
if not rdef.has_perm(_cw, action, **kwargs):
return False
return True
@@ -986,7 +996,7 @@
etype_name_re = r'[A-Z][A-Za-z0-9]*[a-z]+[A-Za-z0-9]*$'
def add_entity_type(self, edef):
- edef.name = edef.name.encode()
+ edef.name = str(edef.name)
edef.name = bw_normalize_etype(edef.name)
if not re.match(self.etype_name_re, edef.name):
raise BadSchemaDefinition(
@@ -1011,7 +1021,7 @@
raise BadSchemaDefinition(
'%r is not a valid name for a relation type. It should be '
'lower cased' % rdef.name)
- rdef.name = rdef.name.encode()
+ rdef.name = str(rdef.name)
rschema = super(CubicWebSchema, self).add_relation_type(rdef)
self._eid_index[rschema.eid] = rschema
return rschema
@@ -1071,7 +1081,7 @@
def iter_computed_attributes(self):
for relation in self.relations():
- for rdef in relation.rdefs.itervalues():
+ for rdef in relation.rdefs.values():
if rdef.final and rdef.formula is not None:
yield rdef
@@ -1198,11 +1208,11 @@
return ';%s;%s\n%s' % (','.join(sorted(self.mainvars)), self.expression,
self.msg or '')
+ @classmethod
def deserialize(cls, value):
value, msg = value.split('\n', 1)
_, mainvars, expression = value.split(';', 2)
return cls(expression, mainvars, msg)
- deserialize = classmethod(deserialize)
def repo_check(self, session, eidfrom, rtype, eidto=None):
"""raise ValidationError if the relation doesn't satisfy the constraint
@@ -1245,7 +1255,7 @@
return _cw.execute(rql, args, build_descr=False)
-class RQLConstraint(RepoEnforcedRQLConstraintMixIn, RQLVocabularyConstraint):
+class RQLConstraint(RepoEnforcedRQLConstraintMixIn, BaseRQLConstraint):
"""the rql constraint is similar to the RQLVocabularyConstraint but
are also enforced at the repository level
"""
@@ -1287,12 +1297,13 @@
make_workflowable(cls)
return cls
+
+@add_metaclass(workflowable_definition)
class WorkflowableEntityType(ybo.EntityType):
"""Use this base class instead of :class:`EntityType` to have workflow
relations (i.e. `in_state`, `wf_info_for` and `custom_workflow`) on your
entity type.
"""
- __metaclass__ = workflowable_definition
__abstract__ = True
--- a/schemas/Bookmark.py Wed Dec 09 18:42:13 2015 +0100
+++ b/schemas/Bookmark.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,7 +19,7 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from yams.buildobjs import EntityType, RelationType, SubjectRelation, String
from cubicweb.schema import RRQLExpression
--- a/schemas/base.py Wed Dec 09 18:42:13 2015 +0100
+++ b/schemas/base.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""core CubicWeb schema, but not necessary at bootstrap time"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from yams.buildobjs import (EntityType, RelationType, RelationDefinition,
SubjectRelation,
@@ -379,5 +379,3 @@
'add': ('managers', RRQLExpression('U has_update_permission S'),),
'delete': ('managers', RRQLExpression('U has_update_permission S'),),
}
-
-
--- a/schemas/bootstrap.py Wed Dec 09 18:42:13 2015 +0100
+++ b/schemas/bootstrap.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,7 +19,7 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from yams.buildobjs import (EntityType, RelationType, RelationDefinition, Bytes,
SubjectRelation, RichString, String, Boolean, Int)
--- a/schemas/workflow.py Wed Dec 09 18:42:13 2015 +0100
+++ b/schemas/workflow.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,7 +19,7 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from yams.buildobjs import (EntityType, RelationType, RelationDefinition,
SubjectRelation,
@@ -273,7 +273,7 @@
"""indicate the current state of an entity"""
__permissions__ = RO_REL_PERMS
- # not inlined intentionnaly since when using ldap sources, user'state
+ # not inlined intentionnally since when using ldap sources, user'state
# has to be stored outside the CWUser table
inlined = False
--- a/selectors.py Wed Dec 09 18:42:13 2015 +0100
+++ b/selectors.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,6 +18,8 @@
from warnings import warn
+from six import string_types
+
from logilab.common.deprecation import deprecated, class_renamed
from cubicweb.predicates import *
@@ -84,7 +86,7 @@
See `EntityPredicate` documentation for behaviour when row is not specified.
- :param *etypes: entity types (`basestring`) which should be refused
+ :param *etypes: entity types (`string_types`) which should be refused
"""
def __init__(self, *etypes):
super(_but_etype, self).__init__()
--- a/server/__init__.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/__init__.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,6 +20,7 @@
The server module contains functions to initialize a new repository.
"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
@@ -28,6 +29,9 @@
from glob import glob
from contextlib import contextmanager
+from six import text_type, string_types
+from six.moves import filter
+
from logilab.common.modutils import LazyObject
from logilab.common.textutils import splitstrip
from logilab.common.registry import yes
@@ -138,7 +142,7 @@
if not debugmode:
DEBUG = 0
return
- if isinstance(debugmode, basestring):
+ if isinstance(debugmode, string_types):
for mode in splitstrip(debugmode, sep='|'):
DEBUG |= globals()[mode]
else:
@@ -196,7 +200,7 @@
user = session.create_entity('CWUser', login=login, upassword=pwd)
for group in groups:
session.execute('SET U in_group G WHERE U eid %(u)s, G name %(group)s',
- {'u': user.eid, 'group': unicode(group)})
+ {'u': user.eid, 'group': text_type(group)})
return user
def init_repository(config, interactive=True, drop=False, vreg=None,
@@ -225,67 +229,72 @@
sourcescfg = config.read_sources_file()
source = sourcescfg['system']
driver = source['db-driver']
- sqlcnx = repo.system_source.get_connection()
- sqlcursor = sqlcnx.cursor()
- execute = sqlcursor.execute
- if drop:
- helper = database.get_db_helper(driver)
- dropsql = sql_drop_all_user_tables(helper, sqlcursor)
- # We may fail dropping some tables because of table dependencies, in a first pass.
- # So, we try a second drop sequence to drop remaining tables if needed.
- # Note that 2 passes is an arbitrary choice as it seems enougth for our usecases.
- # (looping may induce infinite recursion when user have no right for example)
- # Here we try to keep code simple and backend independant. That why we don't try to
- # distinguish remaining tables (wrong right, dependencies, ...).
- failed = sqlexec(dropsql, execute, cnx=sqlcnx,
- pbtitle='-> dropping tables (first pass)')
+ with repo.internal_cnx() as cnx:
+ sqlcnx = cnx.cnxset.cnx
+ sqlcursor = cnx.cnxset.cu
+ execute = sqlcursor.execute
+ if drop:
+ helper = database.get_db_helper(driver)
+ dropsql = sql_drop_all_user_tables(helper, sqlcursor)
+ # We may fail dropping some tables because of table dependencies, in a first pass.
+ # So, we try a second drop sequence to drop remaining tables if needed.
+ # Note that 2 passes is an arbitrary choice as it seems enough for our usecases
+ # (looping may induce infinite recursion when user have no rights for example).
+ # Here we try to keep code simple and backend independent. That's why we don't try to
+ # distinguish remaining tables (missing privileges, dependencies, ...).
+ failed = sqlexec(dropsql, execute, cnx=sqlcnx,
+ pbtitle='-> dropping tables (first pass)')
+ if failed:
+ failed = sqlexec(failed, execute, cnx=sqlcnx,
+ pbtitle='-> dropping tables (second pass)')
+ remainings = list(filter(drop_filter, helper.list_tables(sqlcursor)))
+ assert not remainings, 'Remaining tables: %s' % ', '.join(remainings)
+ handler = config.migration_handler(schema, interactive=False, repo=repo, cnx=cnx)
+ # install additional driver specific sql files
+ handler.cmd_install_custom_sql_scripts()
+ for cube in reversed(config.cubes()):
+ handler.cmd_install_custom_sql_scripts(cube)
+ _title = '-> creating tables '
+ print(_title, end=' ')
+ # schema entities and relations tables
+ # can't skip entities table even if system source doesn't support them,
+ # they are used sometimes by generated sql. Keeping them empty is much
+ # simpler than fixing this...
+ schemasql = sqlschema(schema, driver)
+ #skip_entities=[str(e) for e in schema.entities()
+ # if not repo.system_source.support_entity(str(e))])
+ failed = sqlexec(schemasql, execute, pbtitle=_title, delimiter=';;')
if failed:
- failed = sqlexec(failed, execute, cnx=sqlcnx,
- pbtitle='-> dropping tables (second pass)')
- remainings = filter(drop_filter, helper.list_tables(sqlcursor))
- assert not remainings, 'Remaining tables: %s' % ', '.join(remainings)
- _title = '-> creating tables '
- print _title,
- # schema entities and relations tables
- # can't skip entities table even if system source doesn't support them,
- # they are used sometimes by generated sql. Keeping them empty is much
- # simpler than fixing this...
- schemasql = sqlschema(schema, driver)
- #skip_entities=[str(e) for e in schema.entities()
- # if not repo.system_source.support_entity(str(e))])
- failed = sqlexec(schemasql, execute, pbtitle=_title, delimiter=';;')
- if failed:
- print 'The following SQL statements failed. You should check your schema.'
- print failed
- raise Exception('execution of the sql schema failed, you should check your schema')
- sqlcursor.close()
- sqlcnx.commit()
- sqlcnx.close()
+ print('The following SQL statements failed. You should check your schema.')
+ print(failed)
+ raise Exception('execution of the sql schema failed, you should check your schema')
+ sqlcursor.close()
+ sqlcnx.commit()
with repo.internal_cnx() as cnx:
# insert entity representing the system source
ssource = cnx.create_entity('CWSource', type=u'native', name=u'system')
repo.system_source.eid = ssource.eid
cnx.execute('SET X cw_source X WHERE X eid %(x)s', {'x': ssource.eid})
# insert base groups and default admin
- print '-> inserting default user and default groups.'
+ print('-> inserting default user and default groups.')
try:
- login = unicode(sourcescfg['admin']['login'])
+ login = text_type(sourcescfg['admin']['login'])
pwd = sourcescfg['admin']['password']
except KeyError:
if interactive:
msg = 'enter login and password of the initial manager account'
login, pwd = manager_userpasswd(msg=msg, confirm=True)
else:
- login, pwd = unicode(source['db-user']), source['db-password']
+ login, pwd = text_type(source['db-user']), source['db-password']
# sort for eid predicatability as expected in some server tests
for group in sorted(BASE_GROUPS):
- cnx.create_entity('CWGroup', name=unicode(group))
+ cnx.create_entity('CWGroup', name=text_type(group))
admin = create_user(cnx, login, pwd, u'managers')
cnx.execute('SET X owned_by U WHERE X is IN (CWGroup,CWSource), U eid %(u)s',
{'u': admin.eid})
cnx.commit()
repo.shutdown()
- # reloging using the admin user
+ # re-login using the admin user
config._cubes = None # avoid assertion error
repo = get_repository(config=config)
with connect(repo, login, password=pwd) as cnx:
@@ -293,10 +302,6 @@
repo.system_source.eid = ssource.eid # redo this manually
handler = config.migration_handler(schema, interactive=False,
cnx=cnx, repo=repo)
- # install additional driver specific sql files
- handler.cmd_install_custom_sql_scripts()
- for cube in reversed(config.cubes()):
- handler.cmd_install_custom_sql_scripts(cube)
# serialize the schema
initialize_schema(config, schema, handler)
# yoo !
@@ -310,7 +315,7 @@
# (drop instance attribute to get back to class attribute)
del config.cubicweb_appobject_path
del config.cube_appobject_path
- print '-> database for instance %s initialized.' % config.appid
+ print('-> database for instance %s initialized.' % config.appid)
def initialize_schema(config, schema, mhandler, event='create'):
--- a/server/checkintegrity.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/checkintegrity.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,6 +20,8 @@
* integrity of a CubicWeb repository. Hum actually only the system database is
checked.
"""
+from __future__ import print_function
+
__docformat__ = "restructuredtext en"
import sys
@@ -27,7 +29,7 @@
from logilab.common.shellutils import ProgressBar
-from cubicweb.schema import PURE_VIRTUAL_RTYPES, VIRTUAL_RTYPES
+from cubicweb.schema import PURE_VIRTUAL_RTYPES, VIRTUAL_RTYPES, UNIQUE_CONSTRAINTS
from cubicweb.server.sqlutils import SQL_PREFIX
def notify_fixed(fix):
@@ -90,11 +92,11 @@
dbhelper = repo.system_source.dbhelper
cursor = cnx.cnxset.cu
if not dbhelper.has_fti_table(cursor):
- print 'no text index table'
+ print('no text index table')
dbhelper.init_fti(cursor)
repo.system_source.do_fti = True # ensure full-text indexation is activated
if etypes is None:
- print 'Reindexing entities'
+ print('Reindexing entities')
etypes = set()
for eschema in schema.entities():
if eschema.final:
@@ -107,8 +109,8 @@
# clear fti table first
cnx.system_sql('DELETE FROM %s' % dbhelper.fti_table)
else:
- print 'Reindexing entities of type %s' % \
- ', '.join(sorted(str(e) for e in etypes))
+ print('Reindexing entities of type %s' % \
+ ', '.join(sorted(str(e) for e in etypes)))
# clear fti table first. Use subquery for sql compatibility
cnx.system_sql("DELETE FROM %s WHERE EXISTS(SELECT 1 FROM ENTITIES "
"WHERE eid=%s AND type IN (%s))" % (
@@ -122,8 +124,7 @@
source = repo.system_source
for eschema in etypes:
etype_class = cnx.vreg['etypes'].etype_class(str(eschema))
- for fti_rql in etype_class.cw_fti_index_rql_queries(cnx):
- rset = cnx.execute(fti_rql)
+ for rset in etype_class.cw_fti_index_rql_limit(cnx):
source.fti_index_entities(cnx, rset.entities())
# clear entity cache to avoid high memory consumption on big tables
cnx.drop_entity_cache()
@@ -135,10 +136,7 @@
def check_schema(schema, cnx, eids, fix=1):
"""check serialized schema"""
- print 'Checking serialized schema'
- unique_constraints = ('SizeConstraint', 'FormatConstraint',
- 'VocabularyConstraint',
- 'RQLVocabularyConstraint')
+ print('Checking serialized schema')
rql = ('Any COUNT(X),RN,SN,ON,CTN GROUPBY RN,SN,ON,CTN ORDERBY 1 '
'WHERE X is CWConstraint, R constrained_by X, '
'R relation_type RT, RT name RN, R from_entity ST, ST name SN, '
@@ -146,17 +144,17 @@
for count, rn, sn, on, cstrname in cnx.execute(rql):
if count == 1:
continue
- if cstrname in unique_constraints:
- print "ERROR: got %s %r constraints on relation %s.%s.%s" % (
- count, cstrname, sn, rn, on)
+ if cstrname in UNIQUE_CONSTRAINTS:
+ print("ERROR: got %s %r constraints on relation %s.%s.%s" % (
+ count, cstrname, sn, rn, on))
if fix:
- print 'dunno how to fix, do it yourself'
+ print('dunno how to fix, do it yourself')
def check_text_index(schema, cnx, eids, fix=1):
"""check all entities registered in the text index"""
- print 'Checking text index'
+ print('Checking text index')
msg = ' Entity with eid %s exists in the text index but in no source (autofix will remove from text index)'
cursor = cnx.system_sql('SELECT uid FROM appears;')
for row in cursor.fetchall():
@@ -170,7 +168,7 @@
def check_entities(schema, cnx, eids, fix=1):
"""check all entities registered in the repo system table"""
- print 'Checking entities system table'
+ print('Checking entities system table')
# system table but no source
msg = ' Entity %s with eid %s exists in the system table but in no source (autofix will delete the entity)'
cursor = cnx.system_sql('SELECT eid,type FROM entities;')
@@ -228,7 +226,7 @@
'WHERE s.cw_name=e.type AND NOT EXISTS(SELECT 1 FROM is_instance_of_relation as cs '
' WHERE cs.eid_from=e.eid AND cs.eid_to=s.cw_eid)')
notify_fixed(True)
- print 'Checking entities tables'
+ print('Checking entities tables')
msg = ' Entity with eid %s exists in the %s table but not in the system table (autofix will delete the entity)'
for eschema in schema.entities():
if eschema.final:
@@ -263,7 +261,7 @@
"""check that eids referenced by relations are registered in the repo system
table
"""
- print 'Checking relations'
+ print('Checking relations')
for rschema in schema.relations():
if rschema.final or rschema.type in PURE_VIRTUAL_RTYPES:
continue
@@ -287,7 +285,7 @@
cursor = cnx.system_sql('SELECT eid_from FROM %s_relation;' % rschema)
except Exception as ex:
# usually because table doesn't exist
- print 'ERROR', ex
+ print('ERROR', ex)
continue
for row in cursor.fetchall():
eid = row[0]
@@ -310,14 +308,14 @@
def check_mandatory_relations(schema, cnx, eids, fix=1):
"""check entities missing some mandatory relation"""
- print 'Checking mandatory relations'
+ print('Checking mandatory relations')
msg = '%s #%s is missing mandatory %s relation %s (autofix will delete the entity)'
for rschema in schema.relations():
if rschema.final or rschema in PURE_VIRTUAL_RTYPES or rschema in ('is', 'is_instance_of'):
continue
smandatory = set()
omandatory = set()
- for rdef in rschema.rdefs.itervalues():
+ for rdef in rschema.rdefs.values():
if rdef.cardinality[0] in '1+':
smandatory.add(rdef.subject)
if rdef.cardinality[1] in '1+':
@@ -340,12 +338,12 @@
"""check for entities stored in the system source missing some mandatory
attribute
"""
- print 'Checking mandatory attributes'
+ print('Checking mandatory attributes')
msg = '%s #%s is missing mandatory attribute %s (autofix will delete the entity)'
for rschema in schema.relations():
if not rschema.final or rschema in VIRTUAL_RTYPES:
continue
- for rdef in rschema.rdefs.itervalues():
+ for rdef in rschema.rdefs.values():
if rdef.cardinality[0] in '1+':
rql = 'Any X WHERE X %s NULL, X is %s, X cw_source S, S name "system"' % (
rschema, rdef.subject)
@@ -361,7 +359,7 @@
FIXME: rewrite using RQL queries ?
"""
- print 'Checking metadata'
+ print('Checking metadata')
cursor = cnx.system_sql("SELECT DISTINCT type FROM entities;")
eidcolumn = SQL_PREFIX + 'eid'
msg = ' %s with eid %s has no %s (autofix will set it to now)'
@@ -403,9 +401,9 @@
if fix:
cnx.commit()
else:
- print
+ print()
if not fix:
- print 'WARNING: Diagnostic run, nothing has been corrected'
+ print('WARNING: Diagnostic run, nothing has been corrected')
if reindex:
cnx.rollback()
reindex_entities(repo.schema, cnx, withpb=withpb)
--- a/server/cwzmq.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/cwzmq.py Thu Dec 10 12:34:15 2015 +0100
@@ -65,7 +65,7 @@
def add_subscriber(self, address):
subscriber = Subscriber(self.ioloop, address)
- for topic, callback in self._topics.iteritems():
+ for topic, callback in self._topics.items():
subscriber.subscribe(topic, callback)
self._subscribers.append(subscriber)
--- a/server/edition.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/edition.py Thu Dec 10 12:34:15 2015 +0100
@@ -38,7 +38,7 @@
class EditedEntity(dict):
"""encapsulate entities attributes being written by an RQL query"""
def __init__(self, entity, **kwargs):
- dict.__init__(self, **kwargs)
+ super(EditedEntity, self).__init__(**kwargs)
self.entity = entity
self.skip_security = set()
self.querier_pending_relations = {}
@@ -50,15 +50,18 @@
def __lt__(self, other):
# we don't want comparison by value inherited from dict
- return id(self) < id(other)
+ raise NotImplementedError
def __eq__(self, other):
- return id(self) == id(other)
+ return self is other
+
+ def __ne__(self, other):
+ return not (self == other)
def __setitem__(self, attr, value):
assert attr != 'eid'
# don't add attribute into skip_security if already in edited
- # attributes, else we may accidentaly skip a desired security check
+ # attributes, else we may accidentally skip a desired security check
if attr not in self:
self.skip_security.add(attr)
self.edited_attribute(attr, value)
@@ -83,7 +86,7 @@
def setdefault(self, attr, default):
assert attr != 'eid'
# don't add attribute into skip_security if already in edited
- # attributes, else we may accidentaly skip a desired security check
+ # attributes, else we may accidentally skip a desired security check
if attr not in self:
self[attr] = default
return self[attr]
@@ -93,7 +96,7 @@
setitem = self.__setitem__
else:
setitem = self.edited_attribute
- for attr, value in values.iteritems():
+ for attr, value in values.items():
setitem(attr, value)
def edited_attribute(self, attr, value):
--- a/server/hook.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/hook.py Thu Dec 10 12:34:15 2015 +0100
@@ -248,6 +248,8 @@
.. autoclass:: cubicweb.server.hook.LateOperation
.. autoclass:: cubicweb.server.hook.DataOperationMixIn
"""
+from __future__ import print_function
+
__docformat__ = "restructuredtext en"
from warnings import warn
@@ -331,7 +333,7 @@
with cnx.running_hooks_ops():
for hook in hooks:
if debug:
- print event, _kwargs, hook
+ print(event, _kwargs, hook)
hook()
def get_pruned_hooks(self, cnx, event, entities, eids_from_to, kwargs):
@@ -370,7 +372,7 @@
pruned = set()
cnx.pruned_hooks_cache[cache_key] = pruned
if look_for_selector is not None:
- for id, hooks in self.iteritems():
+ for id, hooks in self.items():
for hook in hooks:
enabled_cat, main_filter = hook.filterable_selectors()
if enabled_cat is not None:
@@ -382,14 +384,14 @@
(main_filter.frometypes is not None or \
main_filter.toetypes is not None):
continue
- first_kwargs = _iter_kwargs(entities, eids_from_to, kwargs).next()
+ first_kwargs = next(_iter_kwargs(entities, eids_from_to, kwargs))
if not main_filter(hook, cnx, **first_kwargs):
pruned.add(hook)
return pruned
def filtered_possible_objects(self, pruned, *args, **kwargs):
- for appobjects in self.itervalues():
+ for appobjects in self.values():
if pruned:
filtered_objects = [obj for obj in appobjects if obj not in pruned]
if not filtered_objects:
@@ -636,7 +638,7 @@
# to set in concrete class (mandatory)
subject_relations = None
object_relations = None
- # to set in concrete class (optionaly)
+ # to set in concrete class (optionally)
skip_subject_relations = ()
skip_object_relations = ()
@@ -713,7 +715,7 @@
the transaction has been either rolled back either:
- * intentionaly
+ * intentionally
* a 'precommit' event failed, in which case all operations are rolled back
once 'revertprecommit'' has been called
--- a/server/hooksmanager.py Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
-#
-# This file is part of CubicWeb.
-#
-# CubicWeb is free software: you can redistribute it and/or modify it under the
-# terms of the GNU Lesser General Public License as published by the Free
-# Software Foundation, either version 2.1 of the License, or (at your option)
-# any later version.
-#
-# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Lesser General Public License along
-# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-from logilab.common.deprecation import class_renamed, class_moved
-from cubicweb.server import hook
-
-SystemHook = class_renamed('SystemHook', hook.Hook)
-Hook = class_moved(hook.Hook)
--- a/server/migractions.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/migractions.py Thu Dec 10 12:34:15 2015 +0100
@@ -26,6 +26,8 @@
* add an entity
* execute raw RQL queries
"""
+from __future__ import print_function
+
__docformat__ = "restructuredtext en"
import sys
@@ -40,6 +42,8 @@
from warnings import warn
from contextlib import contextmanager
+from six import PY2, text_type
+
from logilab.common.deprecation import deprecated
from logilab.common.decorators import cached, clear_cache
@@ -93,7 +97,7 @@
self.repo = repo
self.session = cnx.session
elif connect:
- self.repo_connect()
+ self.repo = config.repository()
self.set_cnx()
else:
self.session = None
@@ -134,30 +138,24 @@
try:
self.cnx = repoapi.connect(self.repo, login, password=pwd)
if not 'managers' in self.cnx.user.groups:
- print 'migration need an account in the managers group'
+ print('migration need an account in the managers group')
else:
break
except AuthenticationError:
- print 'wrong user/password'
+ print('wrong user/password')
except (KeyboardInterrupt, EOFError):
- print 'aborting...'
+ print('aborting...')
sys.exit(0)
try:
login, pwd = manager_userpasswd()
except (KeyboardInterrupt, EOFError):
- print 'aborting...'
+ print('aborting...')
sys.exit(0)
self.session = self.repo._get_session(self.cnx.sessionid)
-
- @cached
- def repo_connect(self):
- self.repo = repoapi.get_repository(config=self.config)
- return self.repo
-
def cube_upgraded(self, cube, version):
self.cmd_set_property('system.version.%s' % cube.lower(),
- unicode(version))
+ text_type(version))
self.commit()
def shutdown(self):
@@ -191,7 +189,7 @@
def backup_database(self, backupfile=None, askconfirm=True, format='native'):
config = self.config
- repo = self.repo_connect()
+ repo = self.repo
# paths
timestamp = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
instbkdir = osp.join(config.appdatahome, 'backup')
@@ -202,13 +200,13 @@
# check backup has to be done
if osp.exists(backupfile) and not \
self.confirm('Backup file %s exists, overwrite it?' % backupfile):
- print '-> no backup done.'
+ print('-> no backup done.')
return
elif askconfirm and not self.confirm('Backup %s database?' % config.appid):
- print '-> no backup done.'
+ print('-> no backup done.')
return
open(backupfile,'w').close() # kinda lock
- os.chmod(backupfile, 0600)
+ os.chmod(backupfile, 0o600)
# backup
source = repo.system_source
tmpdir = tempfile.mkdtemp()
@@ -217,7 +215,7 @@
try:
source.backup(osp.join(tmpdir, source.uri), self.confirm, format=format)
except Exception as ex:
- print '-> error trying to backup %s [%s]' % (source.uri, ex)
+ print('-> error trying to backup %s [%s]' % (source.uri, ex))
if not self.confirm('Continue anyway?', default='n'):
raise SystemExit(1)
else:
@@ -226,7 +224,7 @@
format_file.write('%s\n' % format)
with open(osp.join(tmpdir, 'versions.txt'), 'w') as version_file:
versions = repo.get_versions()
- for cube, version in versions.iteritems():
+ for cube, version in versions.items():
version_file.write('%s %s\n' % (cube, version))
if not failed:
bkup = tarfile.open(backupfile, 'w|gz')
@@ -236,7 +234,7 @@
# call hooks
repo.hm.call_hooks('server_backup', repo=repo, timestamp=timestamp)
# done
- print '-> backup file', backupfile
+ print('-> backup file', backupfile)
finally:
shutil.rmtree(tmpdir)
@@ -268,19 +266,19 @@
if written_format in ('portable', 'native'):
format = written_format
self.config.init_cnxset_pool = False
- repo = self.repo_connect()
+ repo = self.repo = self.config.repository()
source = repo.system_source
try:
source.restore(osp.join(tmpdir, source.uri), self.confirm, drop, format)
except Exception as exc:
- print '-> error trying to restore %s [%s]' % (source.uri, exc)
+ print('-> error trying to restore %s [%s]' % (source.uri, exc))
if not self.confirm('Continue anyway?', default='n'):
raise SystemExit(1)
shutil.rmtree(tmpdir)
# call hooks
repo.init_cnxset_pool()
repo.hm.call_hooks('server_restore', repo=repo, timestamp=backupfile)
- print '-> database restored.'
+ print('-> database restored.')
def commit(self):
self.cnx.commit()
@@ -362,11 +360,11 @@
directory = osp.join(self.config.cube_dir(cube), 'schema')
sql_scripts = glob(osp.join(directory, '*.%s.sql' % driver))
for fpath in sql_scripts:
- print '-> installing', fpath
+ print('-> installing', fpath)
failed = sqlexec(open(fpath).read(), self.cnx.system_sql, False,
delimiter=';;')
if failed:
- print '-> ERROR, skipping', fpath
+ print('-> ERROR, skipping', fpath)
# schema synchronization internals ########################################
@@ -424,7 +422,7 @@
{'x': expreid}, ask_confirm=False)
else:
newexprs.pop(expression)
- for expression in newexprs.itervalues():
+ for expression in newexprs.values():
expr = expression.expression
if not confirm or self.confirm('Add %s expression for %s permission of %s?'
% (expr, action, erschema)):
@@ -460,7 +458,10 @@
assert reporschema.eid, reporschema
self.rqlexecall(ss.updaterschema2rql(rschema, reporschema.eid),
ask_confirm=self.verbosity>=2)
- if syncrdefs:
+ if rschema.rule:
+ if syncperms:
+ self._synchronize_permissions(rschema, reporschema.eid)
+ elif syncrdefs:
for subj, obj in rschema.rdefs:
if (subj, obj) not in reporschema.rdefs:
continue
@@ -552,12 +553,12 @@
for name in cols:
rschema = repoeschema.subjrels.get(name)
if rschema is None:
- print 'dont add %s unique constraint on %s, missing %s' % (
- ','.join(cols), eschema, name)
+ print('dont add %s unique constraint on %s, missing %s' % (
+ ','.join(cols), eschema, name))
return False
if not (rschema.final or rschema.inlined):
- print 'dont add %s unique constraint on %s, %s is neither final nor inlined' % (
- ','.join(cols), eschema, name)
+ print('dont add %s unique constraint on %s, %s is neither final nor inlined' % (
+ ','.join(cols), eschema, name))
return False
return True
@@ -574,6 +575,7 @@
against its current definition:
* order and other properties
* constraints
+ * permissions
"""
subjtype, objtype = str(subjtype), str(objtype)
rschema = self.fs_schema.rschema(rtype)
@@ -743,8 +745,8 @@
rschema = self.repo.schema.rschema(attrname)
attrtype = rschema.objects(etype)[0]
except KeyError:
- print 'warning: attribute %s %s is not known, skip deletion' % (
- etype, attrname)
+ print('warning: attribute %s %s is not known, skip deletion' % (
+ etype, attrname))
else:
self.cmd_drop_relation_definition(etype, attrname, attrtype,
commit=commit)
@@ -781,7 +783,7 @@
instschema = self.repo.schema
eschema = self.fs_schema.eschema(etype)
if etype in instschema and not (eschema.final and eschema.eid is None):
- print 'warning: %s already known, skip addition' % etype
+ print('warning: %s already known, skip addition' % etype)
return
confirm = self.verbosity >= 2
groupmap = self.group_mapping()
@@ -899,9 +901,11 @@
self.commit()
def cmd_drop_entity_type(self, etype, commit=True):
- """unregister an existing entity type
+ """Drop an existing entity type.
- This will trigger deletion of necessary relation types and definitions
+ This will trigger deletion of necessary relation types and definitions.
+ Note that existing entities of the given type will be deleted without
+ any hooks called.
"""
# XXX what if we delete an entity type which is specialized by other types
# unregister the entity from CWEType
@@ -918,7 +922,7 @@
"""
schema = self.repo.schema
if oldname not in schema:
- print 'warning: entity type %s is unknown, skip renaming' % oldname
+ print('warning: entity type %s is unknown, skip renaming' % oldname)
return
# if merging two existing entity types
if newname in schema:
@@ -997,7 +1001,7 @@
# elif simply renaming an entity type
else:
self.rqlexec('SET ET name %(newname)s WHERE ET is CWEType, ET name %(on)s',
- {'newname' : unicode(newname), 'on' : oldname},
+ {'newname' : text_type(newname), 'on' : oldname},
ask_confirm=False)
if commit:
self.commit()
@@ -1017,8 +1021,8 @@
rschema = self.fs_schema.rschema(rtype)
execute = self.cnx.execute
if rtype in reposchema:
- print 'warning: relation type %s is already known, skip addition' % (
- rtype)
+ print('warning: relation type %s is already known, skip addition' % (
+ rtype))
elif rschema.rule:
gmap = self.group_mapping()
ss.execschemarql(execute, rschema, ss.crschema2rql(rschema, gmap))
@@ -1060,7 +1064,11 @@
self.commit()
def cmd_drop_relation_type(self, rtype, commit=True):
- """unregister an existing relation type"""
+ """Drop an existing relation type.
+
+ Note that existing relations of the given type will be deleted without
+ any hooks called.
+ """
self.rqlexec('DELETE CWRType X WHERE X name %r' % rtype,
ask_confirm=self.verbosity>=2)
self.rqlexec('DELETE CWComputedRType X WHERE X name %r' % rtype,
@@ -1098,8 +1106,8 @@
if not rtype in self.repo.schema:
self.cmd_add_relation_type(rtype, addrdef=False, commit=True)
if (subjtype, objtype) in self.repo.schema.rschema(rtype).rdefs:
- print 'warning: relation %s %s %s is already known, skip addition' % (
- subjtype, rtype, objtype)
+ print('warning: relation %s %s %s is already known, skip addition' % (
+ subjtype, rtype, objtype))
return
rdef = self._get_rdef(rschema, subjtype, objtype)
ss.execschemarql(self.cnx.execute, rdef,
@@ -1120,7 +1128,11 @@
return rdef
def cmd_drop_relation_definition(self, subjtype, rtype, objtype, commit=True):
- """unregister an existing relation definition"""
+ """Drop an existing relation definition.
+
+ Note that existing relations of the given definition will be deleted
+ without any hooks called.
+ """
rschema = self.repo.schema.rschema(rtype)
if rschema.rule:
raise ExecutionError('Cannot drop a relation definition for a '
@@ -1200,7 +1212,7 @@
values = []
for k, v in kwargs.items():
values.append('X %s %%(%s)s' % (k, k))
- if isinstance(v, str):
+ if PY2 and isinstance(v, str):
kwargs[k] = unicode(v)
rql = 'SET %s WHERE %s' % (','.join(values), ','.join(restriction))
self.rqlexec(rql, kwargs, ask_confirm=self.verbosity>=2)
@@ -1233,7 +1245,7 @@
self.rqlexec('SET C value %%(v)s WHERE X from_entity S, X relation_type R,'
'X constrained_by C, C cstrtype CT, CT name "SizeConstraint",'
'S name "%s", R name "%s"' % (etype, rtype),
- {'v': unicode(SizeConstraint(size).serialize())},
+ {'v': text_type(SizeConstraint(size).serialize())},
ask_confirm=self.verbosity>=2)
else:
self.rqlexec('DELETE X constrained_by C WHERE X from_entity S, X relation_type R,'
@@ -1270,7 +1282,7 @@
:rtype: `Workflow`
"""
- wf = self.cmd_create_entity('Workflow', name=unicode(name),
+ wf = self.cmd_create_entity('Workflow', name=text_type(name),
**kwargs)
if not isinstance(wfof, (list, tuple)):
wfof = (wfof,)
@@ -1278,19 +1290,19 @@
return 'missing workflow relations, see make_workflowable(%s)' % etype
for etype in wfof:
eschema = self.repo.schema[etype]
- etype = unicode(etype)
+ etype = text_type(etype)
if ensure_workflowable:
assert 'in_state' in eschema.subjrels, _missing_wf_rel(etype)
assert 'custom_workflow' in eschema.subjrels, _missing_wf_rel(etype)
assert 'wf_info_for' in eschema.objrels, _missing_wf_rel(etype)
rset = self.rqlexec(
'SET X workflow_of ET WHERE X eid %(x)s, ET name %(et)s',
- {'x': wf.eid, 'et': unicode(etype)}, ask_confirm=False)
+ {'x': wf.eid, 'et': text_type(etype)}, ask_confirm=False)
assert rset, 'unexistant entity type %s' % etype
if default:
self.rqlexec(
'SET ET default_workflow X WHERE X eid %(x)s, ET name %(et)s',
- {'x': wf.eid, 'et': unicode(etype)}, ask_confirm=False)
+ {'x': wf.eid, 'et': text_type(etype)}, ask_confirm=False)
if commit:
self.commit()
return wf
@@ -1321,13 +1333,13 @@
To set a user specific property value, use appropriate method on CWUser
instance.
"""
- value = unicode(value)
+ value = text_type(value)
try:
prop = self.rqlexec(
'CWProperty X WHERE X pkey %(k)s, NOT X for_user U',
- {'k': unicode(pkey)}, ask_confirm=False).get_entity(0, 0)
+ {'k': text_type(pkey)}, ask_confirm=False).get_entity(0, 0)
except Exception:
- self.cmd_create_entity('CWProperty', pkey=unicode(pkey), value=value)
+ self.cmd_create_entity('CWProperty', pkey=text_type(pkey), value=value)
else:
prop.cw_set(value=value)
@@ -1351,7 +1363,7 @@
# remove from entity cache to avoid memory exhaustion
del entity.cw_attr_cache[attribute]
pb.update()
- print
+ print()
source.set_storage(etype, attribute, storage)
def cmd_create_entity(self, etype, commit=False, **kwargs):
@@ -1564,12 +1576,14 @@
else:
raise StopIteration
- def next(self):
+ def __next__(self):
if self._rsetit is not None:
- return self._rsetit.next()
+ return next(self._rsetit)
rset = self._get_rset()
self._rsetit = iter(rset)
- return self._rsetit.next()
+ return next(self._rsetit)
+
+ next = __next__
def entities(self):
try:
--- a/server/querier.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/querier.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,10 +18,15 @@
"""Helper classes to execute RQL queries on a set of sources, performing
security checking and data aggregation.
"""
+from __future__ import print_function
+
__docformat__ = "restructuredtext en"
from itertools import repeat
+from six import text_type, string_types, integer_types
+from six.moves import range
+
from rql import RQLSyntaxError, CoercionError
from rql.stmts import Union
from rql.nodes import ETYPE_PYOBJ_MAP, etype_from_pyobj, Relation, Exists, Not
@@ -61,7 +66,7 @@
def check_no_password_selected(rqlst):
"""check that Password entities are not selected"""
for solution in rqlst.solutions:
- for var, etype in solution.iteritems():
+ for var, etype in solution.items():
if etype == 'Password':
raise Unauthorized('Password selection is not allowed (%s)' % var)
@@ -103,13 +108,13 @@
solution, args))
if not user.matching_groups(rdef.get_groups('read')):
if DBG:
- print ('check_read_access: %s %s does not match %s' %
- (rdef, user.groups, rdef.get_groups('read')))
+ print('check_read_access: %s %s does not match %s' %
+ (rdef, user.groups, rdef.get_groups('read')))
# XXX rqlexpr not allowed
raise Unauthorized('read', rel.r_type)
if DBG:
- print ('check_read_access: %s %s matches %s' %
- (rdef, user.groups, rdef.get_groups('read')))
+ print('check_read_access: %s %s matches %s' %
+ (rdef, user.groups, rdef.get_groups('read')))
def get_local_checks(cnx, rqlst, solution):
"""Check that the given user has credentials to access data read by the
@@ -138,8 +143,8 @@
ex = Unauthorized('read', solution[varname])
ex.var = varname
if DBG:
- print ('check_read_access: %s %s %s %s' %
- (varname, eschema, user.groups, eschema.get_groups('read')))
+ print('check_read_access: %s %s %s %s' %
+ (varname, eschema, user.groups, eschema.get_groups('read')))
raise ex
# don't insert security on variable only referenced by 'NOT X relation Y' or
# 'NOT EXISTS(X relation Y)'
@@ -265,7 +270,7 @@
# which have a known eid
varkwargs = {}
if not cnx.transaction_data.get('security-rqlst-cache'):
- for var in rqlst.defined_vars.itervalues():
+ for var in rqlst.defined_vars.values():
if var.stinfo['constnode'] is not None:
eid = var.stinfo['constnode'].eval(self.args)
varkwargs[var.name] = int(eid)
@@ -285,7 +290,7 @@
newsolutions.append(solution)
# try to benefit of rqlexpr.check cache for entities which
# are specified by eid in query'args
- for varname, eid in varkwargs.iteritems():
+ for varname, eid in varkwargs.items():
try:
rqlexprs = localcheck.pop(varname)
except KeyError:
@@ -303,7 +308,7 @@
# mark variables protected by an rql expression
restricted_vars.update(localcheck)
# turn local check into a dict key
- localcheck = tuple(sorted(localcheck.iteritems()))
+ localcheck = tuple(sorted(localcheck.items()))
localchecks.setdefault(localcheck, []).append(solution)
# raise Unautorized exception if the user can't access to any solution
if not newsolutions:
@@ -334,7 +339,7 @@
def __init__(self, querier, rqlst, args, cnx):
ExecutionPlan.__init__(self, querier, rqlst, args, cnx)
- # save originaly selected variable, we may modify this
+ # save originally selected variable, we may modify this
# dictionary for substitution (query parameters)
self.selected = rqlst.selection
# list of rows of entities definition (ssplanner.EditedEntity)
@@ -414,7 +419,7 @@
def relation_defs(self):
"""return the list for relation definitions to insert"""
- for rdefs in self._expanded_r_defs.itervalues():
+ for rdefs in self._expanded_r_defs.values():
for rdef in rdefs:
yield rdef
for rdef in self.r_defs:
@@ -446,13 +451,13 @@
relations = {}
for subj, rtype, obj in self.relation_defs():
# if a string is given into args instead of an int, we get it here
- if isinstance(subj, basestring):
+ if isinstance(subj, string_types):
subj = int(subj)
- elif not isinstance(subj, (int, long)):
+ elif not isinstance(subj, integer_types):
subj = subj.entity.eid
- if isinstance(obj, basestring):
+ if isinstance(obj, string_types):
obj = int(obj)
- elif not isinstance(obj, (int, long)):
+ elif not isinstance(obj, integer_types):
obj = obj.entity.eid
if repo.schema.rschema(rtype).inlined:
if subj not in edited_entities:
@@ -468,7 +473,7 @@
else:
relations[rtype] = [(subj, obj)]
repo.glob_add_relations(cnx, relations)
- for edited in edited_entities.itervalues():
+ for edited in edited_entities.values():
repo.glob_update_entity(cnx, edited)
@@ -507,7 +512,7 @@
def parse(self, rql, annotate=False):
"""return a rql syntax tree for the given rql"""
try:
- return self._parse(unicode(rql), annotate=annotate)
+ return self._parse(text_type(rql), annotate=annotate)
except UnicodeError:
raise RQLSyntaxError(rql)
@@ -539,8 +544,8 @@
"""
if server.DEBUG & (server.DBG_RQL | server.DBG_SQL):
if server.DEBUG & (server.DBG_MORE | server.DBG_SQL):
- print '*'*80
- print 'querier input', repr(rql), repr(args)
+ print('*'*80)
+ print('querier input', repr(rql), repr(args))
# parse the query and binds variables
cachekey = (rql,)
try:
@@ -601,7 +606,7 @@
if args:
# different SQL generated when some argument is None or not (IS
# NULL). This should be considered when computing sql cache key
- cachekey += tuple(sorted([k for k, v in args.iteritems()
+ cachekey += tuple(sorted([k for k, v in args.items()
if v is None]))
# make an execution plan
plan = self.plan_factory(rqlst, args, cnx)
@@ -641,7 +646,7 @@
# so compute description manually even if there is only
# one solution
basedescr = [None] * len(plan.selected)
- todetermine = zip(xrange(len(plan.selected)), repeat(False))
+ todetermine = list(zip(range(len(plan.selected)), repeat(False)))
descr = _build_descr(cnx, results, basedescr, todetermine)
# FIXME: get number of affected entities / relations on non
# selection queries ?
@@ -668,7 +673,7 @@
unstables = rqlst.get_variable_indices()
basedescr = []
todetermine = []
- for i in xrange(len(rqlst.children[0].selection)):
+ for i in range(len(rqlst.children[0].selection)):
ttype = _selection_idx_type(i, rqlst, args)
if ttype is None or ttype == 'Any':
ttype = None
--- a/server/repository.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/repository.py Thu Dec 10 12:34:15 2015 +0100
@@ -25,15 +25,18 @@
point to a cubicweb instance.
* handles session management
"""
+from __future__ import print_function
+
__docformat__ = "restructuredtext en"
import threading
-import Queue
from warnings import warn
from itertools import chain
from time import time, localtime, strftime
from contextlib import contextmanager
+from six.moves import range, queue
+
from logilab.common.decorators import cached, clear_cache
from logilab.common.deprecation import deprecated
@@ -186,18 +189,18 @@
# registry hook to fix user class on registry reload
@onevent('after-registry-reload', self)
def fix_user_classes(self):
- # After registery reload the 'CWUser' class used for CWEtype
- # changed. To any existing user object have a different class than
+ # After registry reload the 'CWUser' class used for CWEtype
+ # changed. So any existing user object have a different class than
# the new loaded one. We are hot fixing this.
usercls = self.vreg['etypes'].etype_class('CWUser')
- for session in self._sessions.itervalues():
+ for session in self._sessions.values():
if not isinstance(session.user, InternalManager):
session.user.__class__ = usercls
def init_cnxset_pool(self):
"""should be called bootstrap_repository, as this is what it does"""
config = self.config
- self._cnxsets_pool = Queue.Queue()
+ self._cnxsets_pool = queue.Queue()
# 0. init a cnxset that will be used to fetch bootstrap information from
# the database
self._cnxsets_pool.put_nowait(self.system_source.wrapped_connection())
@@ -240,7 +243,7 @@
# proper initialization
self._get_cnxset().close(True)
self.cnxsets = [] # list of available cnxsets (can't iterate on a Queue)
- for i in xrange(config['connections-pool-size']):
+ for i in range(config['connections-pool-size']):
self.cnxsets.append(self.system_source.wrapped_connection())
self._cnxsets_pool.put_nowait(self.cnxsets[-1])
@@ -308,7 +311,7 @@
else:
self.vreg._set_schema(schema)
self.querier.set_schema(schema)
- for source in self.sources_by_uri.itervalues():
+ for source in self.sources_by_uri.values():
source.set_schema(schema)
self.schema = schema
@@ -377,7 +380,7 @@
def _get_cnxset(self):
try:
return self._cnxsets_pool.get(True, timeout=5)
- except Queue.Empty:
+ except queue.Empty:
raise Exception('no connections set available after 5 secs, probably either a '
'bug in code (too many uncommited/rolled back '
'connections) or too much load on the server (in '
@@ -387,13 +390,6 @@
def _free_cnxset(self, cnxset):
self._cnxsets_pool.put_nowait(cnxset)
- def pinfo(self):
- # XXX: session.cnxset is accessed from a local storage, would be interesting
- # to see if there is a cnxset set in any thread specific data)
- return '%s: %s (%s)' % (self._cnxsets_pool.qsize(),
- ','.join(session.user.login for session in self._sessions.itervalues()
- if session.cnxset),
- threading.currentThread())
def shutdown(self):
"""called on server stop event to properly close opened sessions and
connections
@@ -441,7 +437,7 @@
"""
# iter on sources_by_uri then check enabled source since sources doesn't
# contain copy based sources
- for source in self.sources_by_uri.itervalues():
+ for source in self.sources_by_uri.values():
if self.config.source_enabled(source) and source.support_entity('CWUser'):
try:
return source.authenticate(cnx, login, **authinfo)
@@ -575,7 +571,7 @@
"""
sources = {}
# remove sensitive information
- for uri, source in self.sources_by_uri.iteritems():
+ for uri, source in self.sources_by_uri.items():
sources[uri] = source.public_config
return sources
@@ -623,7 +619,7 @@
raise Exception('bad input for find_user')
with self.internal_cnx() as cnx:
varmaker = rqlvar_maker()
- vars = [(attr, varmaker.next()) for attr in fetch_attrs]
+ vars = [(attr, next(varmaker)) for attr in fetch_attrs]
rql = 'Any %s WHERE X is CWUser, ' % ','.join(var[1] for var in vars)
rql += ','.join('X %s %s' % (var[0], var[1]) for var in vars) + ','
rset = cnx.execute(rql + ','.join('X %s %%(%s)s' % (attr, attr)
@@ -779,6 +775,7 @@
args[key] = int(args[key])
return tuple(cachekey)
+ @deprecated('[3.22] use the new store API')
def extid2eid(self, source, extid, etype, cnx, insert=True,
sourceparams=None):
"""Return eid from a local id. If the eid is a negative integer, that
@@ -919,7 +916,7 @@
# set caches asap
extid = self.init_entity_caches(cnx, entity, source)
if server.DEBUG & server.DBG_REPO:
- print 'ADD entity', self, entity.cw_etype, entity.eid, edited
+ print('ADD entity', self, entity.cw_etype, entity.eid, edited)
prefill_entity_caches(entity)
self.hm.call_hooks('before_add_entity', cnx, entity=entity)
relations = preprocess_inlined_relations(cnx, entity)
@@ -950,8 +947,8 @@
"""
entity = edited.entity
if server.DEBUG & server.DBG_REPO:
- print 'UPDATE entity', entity.cw_etype, entity.eid, \
- entity.cw_attr_cache, edited
+ print('UPDATE entity', entity.cw_etype, entity.eid,
+ entity.cw_attr_cache, edited)
hm = self.hm
eschema = entity.e_schema
cnx.set_entity_cache(entity)
@@ -1043,9 +1040,9 @@
except KeyError:
data_by_etype[etype] = [entity]
source = self.system_source
- for etype, entities in data_by_etype.iteritems():
+ for etype, entities in data_by_etype.items():
if server.DEBUG & server.DBG_REPO:
- print 'DELETE entities', etype, [entity.eid for entity in entities]
+ print('DELETE entities', etype, [entity.eid for entity in entities])
self.hm.call_hooks('before_delete_entity', cnx, entities=entities)
self._delete_cascade_multi(cnx, entities)
source.delete_entities(cnx, entities)
@@ -1067,10 +1064,10 @@
subjects_by_types = {}
objects_by_types = {}
activintegrity = cnx.is_hook_category_activated('activeintegrity')
- for rtype, eids_subj_obj in relations.iteritems():
+ for rtype, eids_subj_obj in relations.items():
if server.DEBUG & server.DBG_REPO:
for subjeid, objeid in eids_subj_obj:
- print 'ADD relation', subjeid, rtype, objeid
+ print('ADD relation', subjeid, rtype, objeid)
for subjeid, objeid in eids_subj_obj:
if rtype in relations_by_rtype:
relations_by_rtype[rtype].append((subjeid, objeid))
@@ -1105,22 +1102,22 @@
objects[objeid] = len(relations_by_rtype[rtype])
continue
objects[objeid] = len(relations_by_rtype[rtype])
- for rtype, source_relations in relations_by_rtype.iteritems():
+ for rtype, source_relations in relations_by_rtype.items():
self.hm.call_hooks('before_add_relation', cnx,
rtype=rtype, eids_from_to=source_relations)
- for rtype, source_relations in relations_by_rtype.iteritems():
+ for rtype, source_relations in relations_by_rtype.items():
source.add_relations(cnx, rtype, source_relations)
rschema = self.schema.rschema(rtype)
for subjeid, objeid in source_relations:
cnx.update_rel_cache_add(subjeid, rtype, objeid, rschema.symmetric)
- for rtype, source_relations in relations_by_rtype.iteritems():
+ for rtype, source_relations in relations_by_rtype.items():
self.hm.call_hooks('after_add_relation', cnx,
rtype=rtype, eids_from_to=source_relations)
def glob_delete_relation(self, cnx, subject, rtype, object):
"""delete a relation from the repository"""
if server.DEBUG & server.DBG_REPO:
- print 'DELETE relation', subject, rtype, object
+ print('DELETE relation', subject, rtype, object)
source = self.system_source
self.hm.call_hooks('before_delete_relation', cnx,
eidfrom=subject, rtype=rtype, eidto=object)
--- a/server/rqlannotation.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/rqlannotation.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,6 +18,7 @@
"""Functions to add additional annotations on a rql syntax tree to ease later
code generation.
"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
@@ -33,7 +34,7 @@
#if server.DEBUG:
# print '-------- sql annotate', repr(rqlst)
getrschema = annotator.schema.rschema
- for var in rqlst.defined_vars.itervalues():
+ for var in rqlst.defined_vars.values():
stinfo = var.stinfo
if stinfo.get('ftirels'):
has_text_query = True
@@ -144,7 +145,7 @@
stinfo['invariant'] = False
# see unittest_rqlannotation. test_has_text_security_cache_bug
# XXX probably more to do, but yet that work without more...
- for col_alias in rqlst.aliases.itervalues():
+ for col_alias in rqlst.aliases.values():
if col_alias.stinfo.get('ftirels'):
has_text_query = True
return has_text_query
@@ -194,7 +195,7 @@
# if DISTINCT query, can use variable from a different scope as principal
# since introduced duplicates will be removed
if scope.stmt.distinct and diffscope_rels:
- return iter(_sort(diffscope_rels)).next()
+ return next(iter(_sort(diffscope_rels)))
# XXX could use a relation from a different scope if it can't generate
# duplicates, so we should have to check cardinality
raise CantSelectPrincipal()
@@ -231,7 +232,7 @@
for select in union.children:
for subquery in select.with_:
set_qdata(getrschema, subquery.query, noinvariant)
- for var in select.defined_vars.itervalues():
+ for var in select.defined_vars.values():
if var.stinfo['invariant']:
if var in noinvariant and not var.stinfo['principal'].r_type == 'has_text':
var._q_invariant = False
@@ -317,7 +318,7 @@
def compute(self, rqlst):
# set domains for each variable
- for varname, var in rqlst.defined_vars.iteritems():
+ for varname, var in rqlst.defined_vars.items():
if var.stinfo['uidrel'] is not None or \
self.eschema(rqlst.solutions[0][varname]).final:
ptypes = var.stinfo['possibletypes']
@@ -354,9 +355,9 @@
continue
def _debug_print(self):
- print 'varsols', dict((x, sorted(str(v) for v in values))
- for x, values in self.varsols.iteritems())
- print 'ambiguous vars', sorted(self.ambiguousvars)
+ print('varsols', dict((x, sorted(str(v) for v in values))
+ for x, values in self.varsols.items()))
+ print('ambiguous vars', sorted(self.ambiguousvars))
def set_rel_constraint(self, term, rel, etypes_func):
if isinstance(term, VariableRef) and self.is_ambiguous(term.variable):
--- a/server/schema2sql.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/schema2sql.py Thu Dec 10 12:34:15 2015 +0100
@@ -162,8 +162,8 @@
def check_constraint(eschema, aschema, attr, constraint, dbhelper, prefix=''):
# XXX should find a better name
- cstrname = 'cstr' + md5(eschema.type + attr + constraint.type() +
- (constraint.serialize() or '')).hexdigest()
+ cstrname = 'cstr' + md5((eschema.type + attr + constraint.type() +
+ (constraint.serialize() or '')).encode('ascii')).hexdigest()
if constraint.type() == 'BoundaryConstraint':
value = as_sql(constraint.boundary, dbhelper, prefix)
return cstrname, '%s%s %s %s' % (prefix, attr, constraint.operator, value)
--- a/server/schemaserial.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/schemaserial.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""functions for schema / permissions (de)serialization using RQL"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
@@ -23,6 +24,8 @@
import json
import sys
+from six import PY2, text_type, string_types
+
from logilab.common.shellutils import ProgressBar, DummyProgressBar
from yams import BadSchemaDefinition, schema as schemamod, buildobjs as ybo
@@ -49,11 +52,11 @@
return res
missing = [g for g in ('owners', 'managers', 'users', 'guests') if not g in res]
if missing:
- print 'some native groups are missing but the following groups have been found:'
- print '\n'.join('* %s (%s)' % (n, eid) for n, eid in res.items())
- print
- print 'enter the eid of a to group to map to each missing native group'
- print 'or just type enter to skip permissions granted to a group'
+ print('some native groups are missing but the following groups have been found:')
+ print('\n'.join('* %s (%s)' % (n, eid) for n, eid in res.items()))
+ print()
+ print('enter the eid of a to group to map to each missing native group')
+ print('or just type enter to skip permissions granted to a group')
for group in missing:
while True:
value = raw_input('eid for group %s: ' % group).strip()
@@ -62,13 +65,13 @@
try:
eid = int(value)
except ValueError:
- print 'eid should be an integer'
+ print('eid should be an integer')
continue
for eid_ in res.values():
if eid == eid_:
break
else:
- print 'eid is not a group eid'
+ print('eid is not a group eid')
continue
res[name] = eid
break
@@ -146,7 +149,7 @@
{'x': etype, 'n': netype})
cnx.commit(False)
tocleanup = [eid]
- tocleanup += (eid for eid, cached in repo._type_source_cache.iteritems()
+ tocleanup += (eid for eid, cached in repo._type_source_cache.items()
if etype == cached[0])
repo.clear_caches(tocleanup)
cnx.commit(False)
@@ -240,7 +243,7 @@
'order', 'description', 'indexed', 'fulltextindexed',
'internationalizable', 'default', 'formula'), values))
typeparams = extra_props.get(attrs['rdefeid'])
- attrs.update(json.load(typeparams) if typeparams else {})
+ attrs.update(json.loads(typeparams.getvalue().decode('ascii')) if typeparams else {})
default = attrs['default']
if default is not None:
if isinstance(default, Binary):
@@ -281,7 +284,7 @@
else:
rtype = str(rel)
relations[1].append(rtype)
- for eschema, unique_together in unique_togethers.itervalues():
+ for eschema, unique_together in unique_togethers.values():
eschema._unique_together.append(tuple(sorted(unique_together)))
schema.infer_specialization_rules()
cnx.commit()
@@ -331,7 +334,7 @@
thispermsdict = permsidx[erschema.eid]
except KeyError:
return
- for action, somethings in thispermsdict.iteritems():
+ for action, somethings in thispermsdict.items():
erschema.permissions[action] = tuple(
isinstance(p, tuple) and erschema.rql_expression(*p) or p
for p in somethings)
@@ -344,7 +347,7 @@
current schema
"""
_title = '-> storing the schema in the database '
- print _title,
+ print(_title, end=' ')
execute = cnx.execute
eschemas = schema.entities()
pb_size = (len(eschemas + schema.relations())
@@ -366,7 +369,7 @@
cstrtypemap = {}
rql = 'INSERT CWConstraintType X: X name %(ct)s'
for cstrtype in CONSTRAINTS:
- cstrtypemap[cstrtype] = execute(rql, {'ct': unicode(cstrtype)},
+ cstrtypemap[cstrtype] = execute(rql, {'ct': text_type(cstrtype)},
build_descr=False)[0][0]
pb.update()
# serialize relations
@@ -381,10 +384,10 @@
continue
execschemarql(execute, rschema, rschema2rql(rschema, addrdef=False))
if rschema.symmetric:
- rdefs = [rdef for k, rdef in rschema.rdefs.iteritems()
+ rdefs = [rdef for k, rdef in rschema.rdefs.items()
if (rdef.subject, rdef.object) == k]
else:
- rdefs = rschema.rdefs.itervalues()
+ rdefs = rschema.rdefs.values()
for rdef in rdefs:
execschemarql(execute, rdef,
rdef2rql(rdef, cstrtypemap, groupmap))
@@ -397,7 +400,7 @@
for rql, kwargs in specialize2rql(schema):
execute(rql, kwargs, build_descr=False)
pb.update()
- print
+ print()
# high level serialization functions
@@ -455,8 +458,8 @@
columnset = set()
for columns in eschema._unique_together:
if columns in columnset:
- print ('schemaserial: skipping duplicate unique together %r %r' %
- (eschema.type, columns))
+ print('schemaserial: skipping duplicate unique together %r %r' %
+ (eschema.type, columns))
continue
columnset.add(columns)
rql, args = _uniquetogether2rql(eschema, columns)
@@ -471,7 +474,7 @@
for i, name in enumerate(unique_together):
rschema = eschema.schema.rschema(name)
rtype = 'T%d' % i
- substs[rtype] = unicode(rschema.type)
+ substs[rtype] = text_type(rschema.type)
relations.append('C relations %s' % rtype)
restrictions.append('%(rtype)s name %%(%(rtype)s)s' % {'rtype': rtype})
relations = ', '.join(relations)
@@ -483,11 +486,11 @@
def _ervalues(erschema):
try:
- type_ = unicode(erschema.type)
+ type_ = text_type(erschema.type)
except UnicodeDecodeError as e:
raise Exception("can't decode %s [was %s]" % (erschema.type, e))
try:
- desc = unicode(erschema.description) or u''
+ desc = text_type(erschema.description) or u''
except UnicodeDecodeError as e:
raise Exception("can't decode %s [was %s]" % (erschema.description, e))
return {
@@ -509,7 +512,7 @@
if addrdef:
assert cstrtypemap
# sort for testing purpose
- for rdef in sorted(rschema.rdefs.itervalues(),
+ for rdef in sorted(rschema.rdefs.values(),
key=lambda x: (x.subject, x.object)):
for rql, values in rdef2rql(rdef, cstrtypemap, groupmap):
yield rql, values
@@ -519,7 +522,7 @@
values['final'] = rschema.final
values['symmetric'] = rschema.symmetric
values['inlined'] = rschema.inlined
- if isinstance(rschema.fulltext_container, str):
+ if PY2 and isinstance(rschema.fulltext_container, str):
values['fulltext_container'] = unicode(rschema.fulltext_container)
else:
values['fulltext_container'] = rschema.fulltext_container
@@ -535,7 +538,7 @@
def crschema_relations_values(crschema):
values = _ervalues(crschema)
- values['rule'] = unicode(crschema.rule)
+ values['rule'] = text_type(crschema.rule)
# XXX why oh why?
del values['final']
relations = ['X %s %%(%s)s' % (attr, attr) for attr in sorted(values)]
@@ -581,20 +584,20 @@
value = bool(value)
elif prop == 'ordernum':
value = int(value)
- elif isinstance(value, str):
+ elif PY2 and isinstance(value, str):
value = unicode(value)
if value is not None and prop == 'default':
value = Binary.zpickle(value)
values[amap.get(prop, prop)] = value
if extra:
- values['extra_props'] = Binary(json.dumps(extra))
+ values['extra_props'] = Binary(json.dumps(extra).encode('ascii'))
relations = ['X %s %%(%s)s' % (attr, attr) for attr in sorted(values)]
return relations, values
def constraints2rql(cstrtypemap, constraints, rdefeid=None):
for constraint in constraints:
values = {'ct': cstrtypemap[constraint.type()],
- 'value': unicode(constraint.serialize()),
+ 'value': text_type(constraint.serialize()),
'x': rdefeid} # when not specified, will have to be set by the caller
yield 'INSERT CWConstraint X: X value %(value)s, X cstrtype CT, EDEF constrained_by X WHERE \
CT eid %(ct)s, EDEF eid %(x)s', values
@@ -613,23 +616,23 @@
# may occurs when modifying persistent schema
continue
for group_or_rqlexpr in grantedto:
- if isinstance(group_or_rqlexpr, basestring):
+ if isinstance(group_or_rqlexpr, string_types):
# group
try:
yield ('SET X %s_permission Y WHERE Y eid %%(g)s, X eid %%(x)s' % action,
{'g': groupmap[group_or_rqlexpr]})
except KeyError:
- print ("WARNING: group %s used in permissions for %s was ignored because it doesn't exist."
- " You may want to add it into a precreate.py file" % (group_or_rqlexpr, erschema))
+ print("WARNING: group %s used in permissions for %s was ignored because it doesn't exist."
+ " You may want to add it into a precreate.py file" % (group_or_rqlexpr, erschema))
continue
else:
# rqlexpr
rqlexpr = group_or_rqlexpr
yield ('INSERT RQLExpression E: E expression %%(e)s, E exprtype %%(t)s, '
'E mainvars %%(v)s, X %s_permission E WHERE X eid %%(x)s' % action,
- {'e': unicode(rqlexpr.expression),
- 'v': unicode(','.join(sorted(rqlexpr.mainvars))),
- 't': unicode(rqlexpr.__class__.__name__)})
+ {'e': text_type(rqlexpr.expression),
+ 'v': text_type(','.join(sorted(rqlexpr.mainvars))),
+ 't': text_type(rqlexpr.__class__.__name__)})
# update functions
@@ -641,7 +644,7 @@
def updaterschema2rql(rschema, eid):
if rschema.rule:
yield ('SET X rule %(r)s WHERE X eid %(x)s',
- {'x': eid, 'r': unicode(rschema.rule)})
+ {'x': eid, 'r': text_type(rschema.rule)})
else:
relations, values = rschema_relations_values(rschema)
values['x'] = eid
--- a/server/serverconfig.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/serverconfig.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,12 +16,14 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""server.serverconfig definition"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
import sys
from os.path import join, exists
-from StringIO import StringIO
+
+from six.moves import StringIO
import logilab.common.configuration as lgconfig
from logilab.common.decorators import cached
@@ -234,18 +236,19 @@
def bootstrap_cubes(self):
from logilab.common.textutils import splitstrip
- for line in file(join(self.apphome, 'bootstrap_cubes')):
- line = line.strip()
- if not line or line.startswith('#'):
- continue
- self.init_cubes(self.expand_cubes(splitstrip(line)))
- break
- else:
- # no cubes
- self.init_cubes(())
+ with open(join(self.apphome, 'bootstrap_cubes')) as f:
+ for line in f:
+ line = line.strip()
+ if not line or line.startswith('#'):
+ continue
+ self.init_cubes(self.expand_cubes(splitstrip(line)))
+ break
+ else:
+ # no cubes
+ self.init_cubes(())
def write_bootstrap_cubes_file(self, cubes):
- stream = file(join(self.apphome, 'bootstrap_cubes'), 'w')
+ stream = open(join(self.apphome, 'bootstrap_cubes'), 'w')
stream.write('# this is a generated file only used for bootstraping\n')
stream.write('# you should not have to edit this\n')
stream.write('%s\n' % ','.join(cubes))
@@ -276,7 +279,7 @@
assert len(self.sources_mode) == 1
if source.connect_for_migration:
return True
- print 'not connecting to source', source.uri, 'during migration'
+ print('not connecting to source', source.uri, 'during migration')
return False
if 'all' in self.sources_mode:
assert len(self.sources_mode) == 1
--- a/server/serverctl.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/serverctl.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""cubicweb-ctl commands and command handlers specific to the repository"""
+from __future__ import print_function
__docformat__ = 'restructuredtext en'
@@ -28,6 +29,9 @@
import logging
import subprocess
+from six import string_types
+from six.moves import input
+
from logilab.common import nullobject
from logilab.common.configuration import Configuration, merge_options
from logilab.common.shellutils import ASK, generate_password
@@ -55,27 +59,27 @@
driver = source['db-driver']
dbhelper = get_db_helper(driver)
if interactive:
- print '-> connecting to %s database' % driver,
+ print('-> connecting to %s database' % driver, end=' ')
if dbhost:
- print '%s@%s' % (dbname, dbhost),
+ print('%s@%s' % (dbname, dbhost), end=' ')
else:
- print dbname,
+ print(dbname, end=' ')
if dbhelper.users_support:
if not interactive or (not special_privs and source.get('db-user')):
user = source.get('db-user', os.environ.get('USER', ''))
if interactive:
- print 'as', user
+ print('as', user)
password = source.get('db-password')
else:
- print
+ print()
if special_privs:
- print 'WARNING'
+ print('WARNING')
print ('the user will need the following special access rights '
'on the database:')
- print special_privs
- print
+ print(special_privs)
+ print()
default_user = source.get('db-user', os.environ.get('USER', ''))
- user = raw_input('Connect as user ? [%r]: ' % default_user)
+ user = input('Connect as user ? [%r]: ' % default_user)
user = user.strip() or default_user
if user == source.get('db-user'):
password = source.get('db-password')
@@ -146,7 +150,7 @@
cnx = repoapi.connect(repo, login, password=pwd)
return repo, cnx
except AuthenticationError:
- print '-> Error: wrong user/password.'
+ print('-> Error: wrong user/password.')
# reset cubes else we'll have an assertion error on next retry
config._cubes = None
login, pwd = manager_userpasswd()
@@ -164,9 +168,9 @@
"""
config = self.config
if not automatic:
- print underline_title('Configuring the repository')
+ print(underline_title('Configuring the repository'))
config.input_config('email', inputlevel)
- print '\n'+underline_title('Configuring the sources')
+ print('\n'+underline_title('Configuring the sources'))
sourcesfile = config.sources_file()
# hack to make Method('default_instance_id') usable in db option defs
# (in native.py)
@@ -174,12 +178,12 @@
options=SOURCE_TYPES['native'].options)
if not automatic:
sconfig.input_config(inputlevel=inputlevel)
- print
+ print()
sourcescfg = {'system': sconfig}
if automatic:
# XXX modify a copy
password = generate_password()
- print '-> set administrator account to admin / %s' % password
+ print('-> set administrator account to admin / %s' % password)
USER_OPTIONS[1][1]['default'] = password
sconfig = Configuration(options=USER_OPTIONS)
else:
@@ -197,8 +201,8 @@
CWCTL.run(['db-create', '--config-level', str(inputlevel),
self.config.appid])
else:
- print ('-> nevermind, you can do it later with '
- '"cubicweb-ctl db-create %s".' % self.config.appid)
+ print('-> nevermind, you can do it later with '
+ '"cubicweb-ctl db-create %s".' % self.config.appid)
@contextmanager
@@ -242,26 +246,26 @@
with db_transaction(source, privilege='DROP SCHEMA') as cursor:
helper = get_db_helper(source['db-driver'])
helper.drop_schema(cursor, db_namespace)
- print '-> database schema %s dropped' % db_namespace
+ print('-> database schema %s dropped' % db_namespace)
def _drop_database(self, source):
dbname = source['db-name']
if source['db-driver'] == 'sqlite':
- print 'deleting database file %(db-name)s' % source
+ print('deleting database file %(db-name)s' % source)
os.unlink(source['db-name'])
- print '-> database %(db-name)s dropped.' % source
+ print('-> database %(db-name)s dropped.' % source)
else:
helper = get_db_helper(source['db-driver'])
with db_sys_transaction(source, privilege='DROP DATABASE') as cursor:
- print 'dropping database %(db-name)s' % source
+ print('dropping database %(db-name)s' % source)
cursor.execute('DROP DATABASE "%(db-name)s"' % source)
- print '-> database %(db-name)s dropped.' % source
+ print('-> database %(db-name)s dropped.' % source)
def _drop_user(self, source):
user = source['db-user'] or None
if user is not None:
with db_sys_transaction(source, privilege='DROP USER') as cursor:
- print 'dropping user %s' % user
+ print('dropping user %s' % user)
cursor.execute('DROP USER %s' % user)
def _cleanup_steps(self, source):
@@ -288,7 +292,7 @@
try:
step(source)
except Exception as exc:
- print 'ERROR', exc
+ print('ERROR', exc)
if ASK.confirm('An error occurred. Continue anyway?',
default_is_yes=False):
continue
@@ -357,7 +361,7 @@
ASK.confirm('Database %s already exists. Drop it?' % dbname)):
os.unlink(dbname)
elif self.config.create_db:
- print '\n'+underline_title('Creating the system database')
+ print('\n'+underline_title('Creating the system database'))
# connect on the dbms system base to create our base
dbcnx = _db_sys_cnx(source, 'CREATE/DROP DATABASE and / or USER',
interactive=not automatic)
@@ -368,17 +372,17 @@
if not helper.user_exists(cursor, user) and (automatic or \
ASK.confirm('Create db user %s ?' % user, default_is_yes=False)):
helper.create_user(source['db-user'], source.get('db-password'))
- print '-> user %s created.' % user
+ print('-> user %s created.' % user)
if dbname in helper.list_databases(cursor):
if automatic or ASK.confirm('Database %s already exists -- do you want to drop it ?' % dbname):
cursor.execute('DROP DATABASE "%s"' % dbname)
else:
- print ('you may want to run "cubicweb-ctl db-init '
- '--drop %s" manually to continue.' % config.appid)
+ print('you may want to run "cubicweb-ctl db-init '
+ '--drop %s" manually to continue.' % config.appid)
return
createdb(helper, source, dbcnx, cursor)
dbcnx.commit()
- print '-> database %s created.' % dbname
+ print('-> database %s created.' % dbname)
except BaseException:
dbcnx.rollback()
raise
@@ -400,13 +404,13 @@
try:
helper.create_language(cursor, extlang)
except Exception as exc:
- print '-> ERROR:', exc
- print '-> could not create language %s, some stored procedures might be unusable' % extlang
+ print('-> ERROR:', exc)
+ print('-> could not create language %s, some stored procedures might be unusable' % extlang)
cnx.rollback()
else:
cnx.commit()
- print '-> database for instance %s created and necessary extensions installed.' % appid
- print
+ print('-> database for instance %s created and necessary extensions installed.' % appid)
+ print()
if automatic:
CWCTL.run(['db-init', '--automatic', '--config-level', '0',
config.appid])
@@ -414,8 +418,8 @@
CWCTL.run(['db-init', '--config-level',
str(self.config.config_level), config.appid])
else:
- print ('-> nevermind, you can do it later with '
- '"cubicweb-ctl db-init %s".' % config.appid)
+ print('-> nevermind, you can do it later with '
+ '"cubicweb-ctl db-init %s".' % config.appid)
class InitInstanceCommand(Command):
@@ -452,7 +456,7 @@
def run(self, args):
check_options_consistency(self.config)
- print '\n'+underline_title('Initializing the system database')
+ print('\n'+underline_title('Initializing the system database'))
from cubicweb.server import init_repository
appid = args[0]
config = ServerConfiguration.config_for(appid)
@@ -503,10 +507,10 @@
used = set(n for n, in cnx.execute('Any SN WHERE S is CWSource, S name SN'))
cubes = repo.get_cubes()
while True:
- type = raw_input('source type (%s): '
+ type = input('source type (%s): '
% ', '.join(sorted(SOURCE_TYPES)))
if type not in SOURCE_TYPES:
- print '-> unknown source type, use one of the available types.'
+ print('-> unknown source type, use one of the available types.')
continue
sourcemodule = SOURCE_TYPES[type].module
if not sourcemodule.startswith('cubicweb.'):
@@ -520,23 +524,23 @@
continue
break
while True:
- parser = raw_input('parser type (%s): '
+ parser = input('parser type (%s): '
% ', '.join(sorted(repo.vreg['parsers'])))
if parser in repo.vreg['parsers']:
break
- print '-> unknown parser identifier, use one of the available types.'
+ print('-> unknown parser identifier, use one of the available types.')
while True:
- sourceuri = raw_input('source identifier (a unique name used to '
+ sourceuri = input('source identifier (a unique name used to '
'tell sources apart): ').strip()
if not sourceuri:
- print '-> mandatory.'
+ print('-> mandatory.')
else:
sourceuri = unicode(sourceuri, sys.stdin.encoding)
if sourceuri in used:
- print '-> uri already used, choose another one.'
+ print('-> uri already used, choose another one.')
else:
break
- url = raw_input('source URL (leave empty for none): ').strip()
+ url = input('source URL (leave empty for none): ').strip()
url = unicode(url) if url else None
# XXX configurable inputlevel
sconfig = ask_source_config(config, type, inputlevel=self.config.config_level)
@@ -583,10 +587,10 @@
cnx.rollback()
import traceback
traceback.print_exc()
- print '-> an error occurred:', ex
+ print('-> an error occurred:', ex)
else:
cnx.commit()
- print '-> rights granted to %s on instance %s.' % (appid, user)
+ print('-> rights granted to %s on instance %s.' % (appid, user))
class ResetAdminPasswordCommand(Command):
@@ -617,7 +621,7 @@
try:
adminlogin = sourcescfg['admin']['login']
except KeyError:
- print '-> Error: could not get cubicweb administrator login.'
+ print('-> Error: could not get cubicweb administrator login.')
sys.exit(1)
cnx = source_cnx(sourcescfg['system'])
driver = sourcescfg['system']['db-driver']
@@ -627,9 +631,9 @@
cursor.execute("SELECT * FROM cw_CWUser WHERE cw_login=%(l)s",
{'l': adminlogin})
if not cursor.fetchall():
- print ("-> error: admin user %r specified in sources doesn't exist "
- "in the database" % adminlogin)
- print " fix your sources file before running this command"
+ print("-> error: admin user %r specified in sources doesn't exist "
+ "in the database" % adminlogin)
+ print(" fix your sources file before running this command")
cnx.close()
sys.exit(1)
if self.config.password is None:
@@ -650,10 +654,10 @@
cnx.rollback()
import traceback
traceback.print_exc()
- print '-> an error occurred:', ex
+ print('-> an error occurred:', ex)
else:
cnx.commit()
- print '-> password reset, sources file regenerated.'
+ print('-> password reset, sources file regenerated.')
cnx.close()
@@ -666,17 +670,17 @@
if sudo:
dmpcmd = 'sudo %s' % (dmpcmd)
dmpcmd = 'ssh -t %s "%s"' % (host, dmpcmd)
- print dmpcmd
+ print(dmpcmd)
if os.system(dmpcmd):
raise ExecutionError('Error while dumping the database')
if output is None:
output = filename
cmd = 'scp %s:/tmp/%s %s' % (host, filename, output)
- print cmd
+ print(cmd)
if os.system(cmd):
raise ExecutionError('Error while retrieving the dump at /tmp/%s' % filename)
rmcmd = 'ssh -t %s "rm -f /tmp/%s"' % (host, filename)
- print rmcmd
+ print(rmcmd)
if os.system(rmcmd) and not ASK.confirm(
'An error occurred while deleting remote dump at /tmp/%s. '
'Continue anyway?' % filename):
@@ -686,7 +690,7 @@
def _local_dump(appid, output, format='native'):
config = ServerConfiguration.config_for(appid)
config.quick_start = True
- mih = config.migration_handler(connect=False, verbosity=1)
+ mih = config.migration_handler(verbosity=1)
mih.backup_database(output, askconfirm=False, format=format)
mih.shutdown()
@@ -696,28 +700,28 @@
config.quick_start = True
mih = config.migration_handler(connect=False, verbosity=1)
mih.restore_database(backupfile, drop, askconfirm=False, format=format)
- repo = mih.repo_connect()
+ repo = mih.repo
# version of the database
dbversions = repo.get_versions()
mih.shutdown()
if not dbversions:
- print "bad or missing version information in the database, don't upgrade file system"
+ print("bad or missing version information in the database, don't upgrade file system")
return
# version of installed software
eversion = dbversions['cubicweb']
status = instance_status(config, eversion, dbversions)
# * database version > installed software
if status == 'needsoftupgrade':
- print "** The database of %s is more recent than the installed software!" % config.appid
- print "** Upgrade your software, then migrate the database by running the command"
- print "** 'cubicweb-ctl upgrade %s'" % config.appid
+ print("** The database of %s is more recent than the installed software!" % config.appid)
+ print("** Upgrade your software, then migrate the database by running the command")
+ print("** 'cubicweb-ctl upgrade %s'" % config.appid)
return
# * database version < installed software, an upgrade will be necessary
# anyway, just rewrite vc.conf and warn user he has to upgrade
elif status == 'needapplupgrade':
- print "** The database of %s is older than the installed software." % config.appid
- print "** Migrate the database by running the command"
- print "** 'cubicweb-ctl upgrade %s'" % config.appid
+ print("** The database of %s is older than the installed software." % config.appid)
+ print("** Migrate the database by running the command")
+ print("** 'cubicweb-ctl upgrade %s'" % config.appid)
return
# * database version = installed software, database version = instance fs version
# ok!
@@ -732,12 +736,12 @@
try:
softversion = config.cube_version(cube)
except ConfigurationError:
- print '-> Error: no cube version information for %s, please check that the cube is installed.' % cube
+ print('-> Error: no cube version information for %s, please check that the cube is installed.' % cube)
continue
try:
applversion = vcconf[cube]
except KeyError:
- print '-> Error: no cube version information for %s in version configuration.' % cube
+ print('-> Error: no cube version information for %s in version configuration.' % cube)
continue
if softversion == applversion:
continue
@@ -883,7 +887,7 @@
_local_restore(destappid, output, not self.config.no_drop,
self.config.format)
if self.config.keep_dump:
- print '-> you can get the dump file at', output
+ print('-> you can get the dump file at', output)
else:
os.remove(output)
@@ -1001,9 +1005,9 @@
stats = source.pull_data(cnx, force=True, raise_on_error=True)
finally:
repo.shutdown()
- for key, val in stats.iteritems():
+ for key, val in stats.items():
if val:
- print key, ':', val
+ print(key, ':', val)
@@ -1019,7 +1023,7 @@
for p in ('read', 'add', 'update', 'delete'):
rule = perms.get(p)
if rule:
- perms[p] = tuple(str(x) if isinstance(x, basestring) else x
+ perms[p] = tuple(str(x) if isinstance(x, string_types) else x
for x in rule)
return perms, perms in defaultrelperms or perms in defaulteperms
@@ -1079,7 +1083,7 @@
if self.config.db is not None:
appcfg = ServerConfiguration.config_for(appid)
srccfg = appcfg.read_sources_file()
- for key, value in self.config.db.iteritems():
+ for key, value in self.config.db.items():
if '.' in key:
section, key = key.split('.', 1)
else:
--- a/server/session.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/session.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,6 +16,8 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""Repository users' and internal' sessions."""
+from __future__ import print_function
+
__docformat__ = "restructuredtext en"
import sys
@@ -25,6 +27,8 @@
import functools
from contextlib import contextmanager
+from six import text_type
+
from logilab.common.deprecation import deprecated
from logilab.common.textutils import unormalize
from logilab.common.registry import objectify_predicate
@@ -556,7 +560,7 @@
else:
relations_dict[rtype] = eids
self.repo.glob_add_relations(self, relations_dict)
- for edited in edited_entities.itervalues():
+ for edited in edited_entities.values():
self.repo.glob_update_entity(self, edited)
@@ -769,7 +773,7 @@
def transaction_uuid(self, set=True):
uuid = self.transaction_data.get('tx_uuid')
if set and uuid is None:
- self.transaction_data['tx_uuid'] = uuid = unicode(uuid4().hex)
+ self.transaction_data['tx_uuid'] = uuid = text_type(uuid4().hex)
self.repo.system_source.start_undoable_transaction(self, uuid)
return uuid
@@ -874,7 +878,7 @@
processed = []
self.commit_state = 'precommit'
if debug:
- print self.commit_state, '*' * 20
+ print(self.commit_state, '*' * 20)
try:
with self.running_hooks_ops():
while self.pending_operations:
@@ -882,7 +886,7 @@
operation.processed = 'precommit'
processed.append(operation)
if debug:
- print operation
+ print(operation)
operation.handle_event('precommit_event')
self.pending_operations[:] = processed
self.debug('precommit transaction %s done', self.connectionid)
@@ -899,11 +903,11 @@
# and revertcommit, that will be enough in mont case.
operation.failed = True
if debug:
- print self.commit_state, '*' * 20
+ print(self.commit_state, '*' * 20)
with self.running_hooks_ops():
for operation in reversed(processed):
if debug:
- print operation
+ print(operation)
try:
operation.handle_event('revertprecommit_event')
except BaseException:
@@ -917,12 +921,12 @@
self.cnxset.commit()
self.commit_state = 'postcommit'
if debug:
- print self.commit_state, '*' * 20
+ print(self.commit_state, '*' * 20)
with self.running_hooks_ops():
while self.pending_operations:
operation = self.pending_operations.pop(0)
if debug:
- print operation
+ print(operation)
operation.processed = 'postcommit'
try:
operation.handle_event('postcommit_event')
@@ -1004,7 +1008,7 @@
"""
def __init__(self, user, repo, cnxprops=None, _id=None):
- self.sessionid = _id or make_uid(unormalize(user.login).encode('UTF8'))
+ self.sessionid = _id or make_uid(unormalize(user.login))
self.user = user # XXX repoapi: deprecated and store only a login.
self.repo = repo
self.vreg = repo.vreg
--- a/server/sources/__init__.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/sources/__init__.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,13 +16,18 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""cubicweb server sources support"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
from time import time
from logging import getLogger
+from base64 import b64decode
+
+from six import text_type
from logilab.common import configuration
+from logilab.common.textutils import unormalize
from logilab.common.deprecation import deprecated
from yams.schema import role_name
@@ -35,25 +40,25 @@
def dbg_st_search(uri, union, varmap, args, cachekey=None, prefix='rql for'):
if server.DEBUG & server.DBG_RQL:
global t
- print ' %s %s source: %s' % (prefix, uri, repr(union.as_string()))
+ print(' %s %s source: %s' % (prefix, uri, repr(union.as_string())))
t = time()
if varmap:
- print ' using varmap', varmap
+ print(' using varmap', varmap)
if server.DEBUG & server.DBG_MORE:
- print ' args', repr(args)
- print ' cache key', cachekey
- print ' solutions', ','.join(str(s.solutions)
- for s in union.children)
+ print(' args', repr(args))
+ print(' cache key', cachekey)
+ print(' solutions', ','.join(str(s.solutions)
+ for s in union.children))
# return true so it can be used as assertion (and so be killed by python -O)
return True
def dbg_results(results):
if server.DEBUG & server.DBG_RQL:
if len(results) > 10:
- print ' -->', results[:10], '...', len(results),
+ print(' -->', results[:10], '...', len(results), end=' ')
else:
- print ' -->', results,
- print 'time: ', time() - t
+ print(' -->', results, end=' ')
+ print('time: ', time() - t)
# return true so it can be used as assertion (and so be killed by python -O)
return True
@@ -104,7 +109,9 @@
self.public_config['use-cwuri-as-url'] = self.use_cwuri_as_url
self.remove_sensitive_information(self.public_config)
self.uri = source_config.pop('uri')
- set_log_methods(self, getLogger('cubicweb.sources.'+self.uri))
+ # unormalize to avoid non-ascii characters in logger's name, this will cause decoding error
+ # on logging
+ set_log_methods(self, getLogger('cubicweb.sources.' + unormalize(text_type(self.uri))))
source_config.pop('type')
self.update_config(None, self.check_conf_dict(eid, source_config,
fail_if_unknown=False))
@@ -140,7 +147,7 @@
pass
@classmethod
- def check_conf_dict(cls, eid, confdict, _=unicode, fail_if_unknown=True):
+ def check_conf_dict(cls, eid, confdict, _=text_type, fail_if_unknown=True):
"""check configuration of source entity. Return config dict properly
typed with defaults set.
"""
@@ -157,7 +164,7 @@
try:
value = configuration._validate(value, optdict, optname)
except Exception as ex:
- msg = unicode(ex) # XXX internationalization
+ msg = text_type(ex) # XXX internationalization
raise ValidationError(eid, {role_name('config', 'subject'): msg})
processed[optname] = value
# cw < 3.10 bw compat
@@ -199,6 +206,12 @@
else:
self.urls = []
+ @staticmethod
+ def decode_extid(extid):
+ if extid is None:
+ return extid
+ return b64decode(extid)
+
# source initialization / finalization #####################################
def set_schema(self, schema):
--- a/server/sources/datafeed.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/sources/datafeed.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,15 +19,20 @@
database
"""
-import urllib2
-import StringIO
+from io import BytesIO
from os.path import exists
from datetime import datetime, timedelta
-from base64 import b64decode
-from cookielib import CookieJar
-import urlparse
+
+from six import text_type
+from six.moves.urllib.parse import urlparse
+from six.moves.urllib.request import Request, build_opener, HTTPCookieProcessor
+from six.moves.urllib.error import HTTPError
+from six.moves.http_cookiejar import CookieJar
+
from lxml import etree
+from logilab.common.deprecation import deprecated
+
from cubicweb import RegistryNotFound, ObjectNotFound, ValidationError, UnknownEid
from cubicweb.server.repository import preprocess_inlined_relations
from cubicweb.server.sources import AbstractSource
@@ -244,6 +249,7 @@
error = True
return error
+ @deprecated('[3.21] use the new store API')
def before_entity_insertion(self, cnx, lid, etype, eid, sourceparams):
"""called by the repository when an eid has been attributed for an
entity stored here but the entity has not been inserted in the system
@@ -259,6 +265,7 @@
sourceparams['parser'].before_entity_copy(entity, sourceparams)
return entity
+ @deprecated('[3.21] use the new store API')
def after_entity_insertion(self, cnx, lid, entity, sourceparams):
"""called by the repository after an entity stored here has been
inserted in the system table.
@@ -282,7 +289,7 @@
sql = ('SELECT extid, eid, type FROM entities, cw_source_relation '
'WHERE entities.eid=cw_source_relation.eid_from '
'AND cw_source_relation.eid_to=%s' % self.eid)
- return dict((b64decode(uri), (eid, type))
+ return dict((self.decode_extid(uri), (eid, type))
for uri, eid, type in cnx.system_sql(sql).fetchall())
def init_import_log(self, cnx, **kwargs):
@@ -328,7 +335,7 @@
For http URLs, it will try to find a cwclientlib config entry
(if available) and use it as requester.
"""
- purl = urlparse.urlparse(url)
+ purl = urlparse(url)
if purl.scheme == 'file':
return URLLibResponseAdapter(open(url[7:]), url)
@@ -344,7 +351,7 @@
self.source.info('Using cwclientlib for %s' % url)
resp = cnx.get(url)
resp.raise_for_status()
- return URLLibResponseAdapter(StringIO.StringIO(resp.text), url)
+ return URLLibResponseAdapter(BytesIO(resp.text), url)
except (ImportError, ValueError, EnvironmentError) as exc:
# ImportError: not available
# ValueError: no config entry found
@@ -354,11 +361,11 @@
# no chance with cwclientlib, fall back to former implementation
if purl.scheme in ('http', 'https'):
self.source.info('GET %s', url)
- req = urllib2.Request(url)
+ req = Request(url)
return _OPENER.open(req, timeout=self.source.http_timeout)
# url is probably plain content
- return URLLibResponseAdapter(StringIO.StringIO(url), url)
+ return URLLibResponseAdapter(BytesIO(url.encode('ascii')), url)
def add_schema_config(self, schemacfg, checkonly=False):
"""added CWSourceSchemaConfig, modify mapping accordingly"""
@@ -370,6 +377,7 @@
msg = schemacfg._cw._("this parser doesn't use a mapping")
raise ValidationError(schemacfg.eid, {None: msg})
+ @deprecated('[3.21] use the new store API')
def extid2entity(self, uri, etype, **sourceparams):
"""Return an entity for the given uri. May return None if it should be
skipped.
@@ -388,11 +396,11 @@
else:
source = self.source
sourceparams['parser'] = self
- if isinstance(uri, unicode):
+ if isinstance(uri, text_type):
uri = uri.encode('utf-8')
try:
- eid = cnx.repo.extid2eid(source, str(uri), etype, cnx,
- sourceparams=sourceparams)
+ eid = cnx.repo.extid2eid(source, uri, etype, cnx,
+ sourceparams=sourceparams)
except ValidationError as ex:
if raise_on_error:
raise
@@ -419,9 +427,11 @@
"""main callback: process the url"""
raise NotImplementedError
+ @deprecated('[3.21] use the new store API')
def before_entity_copy(self, entity, sourceparams):
raise NotImplementedError
+ @deprecated('[3.21] use the new store API')
def after_entity_copy(self, entity, sourceparams):
self.stats['created'].add(entity.eid)
@@ -447,10 +457,10 @@
def handle_deletion(self, config, cnx, myuris):
if config['delete-entities'] and myuris:
byetype = {}
- for extid, (eid, etype) in myuris.iteritems():
+ for extid, (eid, etype) in myuris.items():
if self.is_deleted(extid, etype, eid):
byetype.setdefault(etype, []).append(str(eid))
- for etype, eids in byetype.iteritems():
+ for etype, eids in byetype.items():
self.warning('delete %s %s entities', len(eids), etype)
cnx.execute('DELETE %s X WHERE X eid IN (%s)'
% (etype, ','.join(eids)))
@@ -463,7 +473,7 @@
self.notify_checked(entity)
mdate = attrs.get('modification_date')
if not mdate or mdate > entity.modification_date:
- attrs = dict( (k, v) for k, v in attrs.iteritems()
+ attrs = dict( (k, v) for k, v in attrs.items()
if v != getattr(entity, k))
if attrs:
entity.cw_set(**attrs)
@@ -472,6 +482,7 @@
class DataFeedXMLParser(DataFeedParser):
+ @deprecated()
def process(self, url, raise_on_error=False):
"""IDataFeedParser main entry point"""
try:
@@ -530,10 +541,10 @@
self.source.debug(str(exc))
# no chance with cwclientlib, fall back to former implementation
- if urlparse.urlparse(url).scheme in ('http', 'https'):
+ if urlparse(url).scheme in ('http', 'https'):
try:
_OPENER.open(url, timeout=self.source.http_timeout)
- except urllib2.HTTPError as ex:
+ except HTTPError as ex:
if ex.code == 404:
return True
return False
@@ -555,15 +566,12 @@
def getcode(self):
return self.code
- def info(self):
- from mimetools import Message
- return Message(StringIO.StringIO())
# use a cookie enabled opener to use session cookie if any
-_OPENER = urllib2.build_opener()
+_OPENER = build_opener()
try:
from logilab.common import urllib2ext
_OPENER.add_handler(urllib2ext.HTTPGssapiAuthHandler())
except ImportError: # python-kerberos not available
pass
-_OPENER.add_handler(urllib2.HTTPCookieProcessor(CookieJar()))
+_OPENER.add_handler(HTTPCookieProcessor(CookieJar()))
--- a/server/sources/ldapfeed.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/sources/ldapfeed.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -17,14 +17,13 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""cubicweb ldap feed source"""
-from __future__ import division # XXX why?
+from __future__ import division # XXX why?
from datetime import datetime
-import ldap
-from ldap.ldapobject import ReconnectLDAPObject
-from ldap.filter import filter_format
-from ldapurl import LDAPUrl
+from six import PY2, string_types
+
+import ldap3
from logilab.common.configuration import merge_options
@@ -32,15 +31,15 @@
from cubicweb.server import utils
from cubicweb.server.sources import datafeed
-_ = unicode
+from cubicweb import _
# search scopes
-BASE = ldap.SCOPE_BASE
-ONELEVEL = ldap.SCOPE_ONELEVEL
-SUBTREE = ldap.SCOPE_SUBTREE
-LDAP_SCOPES = {'BASE': ldap.SCOPE_BASE,
- 'ONELEVEL': ldap.SCOPE_ONELEVEL,
- 'SUBTREE': ldap.SCOPE_SUBTREE}
+BASE = ldap3.SEARCH_SCOPE_BASE_OBJECT
+ONELEVEL = ldap3.SEARCH_SCOPE_SINGLE_LEVEL
+SUBTREE = ldap3.SEARCH_SCOPE_WHOLE_SUBTREE
+LDAP_SCOPES = {'BASE': BASE,
+ 'ONELEVEL': ONELEVEL,
+ 'SUBTREE': SUBTREE}
# map ldap protocol to their standard port
PROTO_PORT = {'ldap': 389,
@@ -49,6 +48,15 @@
}
+def replace_filter(s):
+ s = s.replace('*', '\\2A')
+ s = s.replace('(', '\\28')
+ s = s.replace(')', '\\29')
+ s = s.replace('\\', '\\5c')
+ s = s.replace('\0', '\\00')
+ return s
+
+
class LDAPFeedSource(datafeed.DataFeedSource):
"""LDAP feed source: unlike ldapuser source, this source is copy based and
will import ldap content (beside passwords for authentication) into the
@@ -61,7 +69,7 @@
('auth-mode',
{'type' : 'choice',
'default': 'simple',
- 'choices': ('simple', 'cram_md5', 'digest_md5', 'gssapi'),
+ 'choices': ('simple', 'digest_md5', 'gssapi'),
'help': 'authentication mode used to authenticate user to the ldap.',
'group': 'ldap-source', 'level': 3,
}),
@@ -183,8 +191,8 @@
self.user_default_groups = typedconfig['user-default-group']
self.user_attrs = {'dn': 'eid', 'modifyTimestamp': 'modification_date'}
self.user_attrs.update(typedconfig['user-attrs-map'])
- self.user_rev_attrs = dict((v, k) for k, v in self.user_attrs.iteritems())
- self.base_filters = [filter_format('(%s=%s)', ('objectClass', o))
+ self.user_rev_attrs = dict((v, k) for k, v in self.user_attrs.items())
+ self.base_filters = ['(objectclass=%s)' % replace_filter(o)
for o in typedconfig['user-classes']]
if typedconfig['user-filter']:
self.base_filters.append(typedconfig['user-filter'])
@@ -193,8 +201,8 @@
self.group_attrs = typedconfig['group-attrs-map']
self.group_attrs = {'dn': 'eid', 'modifyTimestamp': 'modification_date'}
self.group_attrs.update(typedconfig['group-attrs-map'])
- self.group_rev_attrs = dict((v, k) for k, v in self.group_attrs.iteritems())
- self.group_base_filters = [filter_format('(%s=%s)', ('objectClass', o))
+ self.group_rev_attrs = dict((v, k) for k, v in self.group_attrs.items())
+ self.group_base_filters = ['(objectClass=%s)' % replace_filter(o)
for o in typedconfig['group-classes']]
if typedconfig['group-filter']:
self.group_base_filters.append(typedconfig['group-filter'])
@@ -215,9 +223,11 @@
def connection_info(self):
assert len(self.urls) == 1, self.urls
protocol, hostport = self.urls[0].split('://')
- if protocol != 'ldapi' and not ':' in hostport:
- hostport = '%s:%s' % (hostport, PROTO_PORT[protocol])
- return protocol, hostport
+ if protocol != 'ldapi' and ':' in hostport:
+ host, port = hostport.rsplit(':', 1)
+ else:
+ host, port = hostport, PROTO_PORT[protocol]
+ return protocol, host, port
def authenticate(self, cnx, login, password=None, **kwargs):
"""return CWUser eid for the given login/password if this account is
@@ -232,59 +242,43 @@
# You get Authenticated as: 'NT AUTHORITY\ANONYMOUS LOGON'.
# we really really don't want that
raise AuthenticationError()
- searchfilter = [filter_format('(%s=%s)', (self.user_login_attr, login))]
+ searchfilter = ['(%s=%s)' % (replace_filter(self.user_login_attr), replace_filter(login))]
searchfilter.extend(self.base_filters)
searchstr = '(&%s)' % ''.join(searchfilter)
# first search the user
try:
user = self._search(cnx, self.user_base_dn,
self.user_base_scope, searchstr)[0]
- except (IndexError, ldap.SERVER_DOWN):
+ except IndexError:
# no such user
raise AuthenticationError()
# check password by establishing a (unused) connection
try:
self._connect(user, password)
- except ldap.LDAPError as ex:
+ except ldap3.LDAPException as ex:
# Something went wrong, most likely bad credentials
self.info('while trying to authenticate %s: %s', user, ex)
raise AuthenticationError()
except Exception:
self.error('while trying to authenticate %s', user, exc_info=True)
raise AuthenticationError()
- eid = self.repo.extid2eid(self, user['dn'], 'CWUser', cnx, insert=False)
- if eid < 0:
- # user has been moved away from this source
+ eid = self.repo.system_source.extid2eid(cnx, user['dn'].encode('ascii'))
+ if eid is None or eid < 0:
+ # user is not known or has been moved away from this source
raise AuthenticationError()
return eid
def _connect(self, user=None, userpwd=None):
- protocol, hostport = self.connection_info()
- self.info('connecting %s://%s as %s', protocol, hostport,
+ protocol, host, port = self.connection_info()
+ self.info('connecting %s://%s:%s as %s', protocol, host, port,
user and user['dn'] or 'anonymous')
- # don't require server certificate when using ldaps (will
- # enable self signed certs)
- ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
- url = LDAPUrl(urlscheme=protocol, hostport=hostport)
- conn = ReconnectLDAPObject(url.initializeUrl())
- # Set the protocol version - version 3 is preferred
- try:
- conn.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3)
- except ldap.LDAPError: # Invalid protocol version, fall back safely
- conn.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION2)
- # Deny auto-chasing of referrals to be safe, we handle them instead
- # Required for AD
- try:
- conn.set_option(ldap.OPT_REFERRALS, 0)
- except ldap.LDAPError: # Cannot set referrals, so do nothing
- pass
- #conn.set_option(ldap.OPT_NETWORK_TIMEOUT, conn_timeout)
- #conn.timeout = op_timeout
+ server = ldap3.Server(host, port=int(port))
+ conn = ldap3.Connection(server, user=user and user['dn'], client_strategy=ldap3.STRATEGY_SYNC_RESTARTABLE, auto_referrals=False)
# Now bind with the credentials given. Let exceptions propagate out.
if user is None:
# XXX always use simple bind for data connection
if not self.cnx_dn:
- conn.simple_bind_s(self.cnx_dn, self.cnx_pwd)
+ conn.bind()
else:
self._authenticate(conn, {'dn': self.cnx_dn}, self.cnx_pwd)
else:
@@ -294,25 +288,22 @@
return conn
def _auth_simple(self, conn, user, userpwd):
- conn.simple_bind_s(user['dn'], userpwd)
-
- def _auth_cram_md5(self, conn, user, userpwd):
- from ldap import sasl
- auth_token = sasl.cram_md5(user['dn'], userpwd)
- conn.sasl_interactive_bind_s('', auth_token)
+ conn.authentication = ldap3.AUTH_SIMPLE
+ conn.user = user['dn']
+ conn.password = userpwd
+ conn.bind()
def _auth_digest_md5(self, conn, user, userpwd):
- from ldap import sasl
- auth_token = sasl.digest_md5(user['dn'], userpwd)
- conn.sasl_interactive_bind_s('', auth_token)
+ conn.authentication = ldap3.AUTH_SASL
+ conn.sasl_mechanism = 'DIGEST-MD5'
+ # realm, user, password, authz-id
+ conn.sasl_credentials = (None, user['dn'], userpwd, None)
+ conn.bind()
def _auth_gssapi(self, conn, user, userpwd):
- # print XXX not proper sasl/gssapi
- import kerberos
- if not kerberos.checkPassword(user[self.user_login_attr], userpwd):
- raise Exception('BAD login / mdp')
- #from ldap import sasl
- #conn.sasl_interactive_bind_s('', sasl.gssapi())
+ conn.authentication = ldap3.AUTH_SASL
+ conn.sasl_mechanism = 'GSSAPI'
+ conn.bind()
def _search(self, cnx, base, scope,
searchstr='(objectClass=*)', attrs=()):
@@ -322,37 +313,15 @@
if self._conn is None:
self._conn = self._connect()
ldapcnx = self._conn
- try:
- res = ldapcnx.search_s(base, scope, searchstr, attrs)
- except ldap.PARTIAL_RESULTS:
- res = ldapcnx.result(all=0)[1]
- except ldap.NO_SUCH_OBJECT:
- self.info('ldap NO SUCH OBJECT %s %s %s', base, scope, searchstr)
- self._process_no_such_object(cnx, base)
+ if not ldapcnx.search(base, searchstr, search_scope=scope, attributes=attrs):
return []
- # except ldap.REFERRAL as e:
- # ldapcnx = self.handle_referral(e)
- # try:
- # res = ldapcnx.search_s(base, scope, searchstr, attrs)
- # except ldap.PARTIAL_RESULTS:
- # res_type, res = ldapcnx.result(all=0)
result = []
- for rec_dn, rec_dict in res:
- # When used against Active Directory, "rec_dict" may not be
- # be a dictionary in some cases (instead, it can be a list)
- #
- # An example of a useless "res" entry that can be ignored
- # from AD is
- # (None, ['ldap://ForestDnsZones.PORTAL.LOCAL/DC=ForestDnsZones,DC=PORTAL,DC=LOCAL'])
- # This appears to be some sort of internal referral, but
- # we can't handle it, so we need to skip over it.
- try:
- items = rec_dict.iteritems()
- except AttributeError:
+ for rec in ldapcnx.response:
+ if rec['type'] != 'searchResEntry':
continue
- else:
- itemdict = self._process_ldap_item(rec_dn, items)
- result.append(itemdict)
+ items = rec['attributes'].items()
+ itemdict = self._process_ldap_item(rec['dn'], items)
+ result.append(itemdict)
self.debug('ldap built results %s', len(result))
return result
@@ -363,20 +332,21 @@
if self.user_attrs.get(key) == 'upassword': # XXx better password detection
value = value[0].encode('utf-8')
# we only support ldap_salted_sha1 for ldap sources, see: server/utils.py
- if not value.startswith('{SSHA}'):
+ if not value.startswith(b'{SSHA}'):
value = utils.crypt_password(value)
itemdict[key] = Binary(value)
elif self.user_attrs.get(key) == 'modification_date':
itemdict[key] = datetime.strptime(value[0], '%Y%m%d%H%M%SZ')
else:
- value = [unicode(val, 'utf-8', 'replace') for val in value]
+ if PY2 and value and isinstance(value[0], str):
+ value = [unicode(val, 'utf-8', 'replace') for val in value]
if len(value) == 1:
itemdict[key] = value = value[0]
else:
itemdict[key] = value
# we expect memberUid to be a list of user ids, make sure of it
member = self.group_rev_attrs['member']
- if isinstance(itemdict.get(member), basestring):
+ if isinstance(itemdict.get(member), string_types):
itemdict[member] = [itemdict[member]]
return itemdict
--- a/server/sources/native.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/sources/native.py Thu Dec 10 12:34:15 2015 +0100
@@ -23,13 +23,13 @@
string. This is because it should actually be Bytes but we want an index on
it for fast querying.
"""
+from __future__ import print_function
+
__docformat__ = "restructuredtext en"
-from cPickle import loads, dumps
-import cPickle as pickle
from threading import Lock
from datetime import datetime
-from base64 import b64decode, b64encode
+from base64 import b64encode
from contextlib import contextmanager
from os.path import basename
import re
@@ -38,6 +38,9 @@
import logging
import sys
+from six import PY2, text_type, binary_type, string_types
+from six.moves import range, cPickle as pickle
+
from logilab.common.decorators import cached, clear_cache
from logilab.common.configuration import Method
from logilab.common.shellutils import getlogin
@@ -76,12 +79,12 @@
it's a function just so that it shows up in profiling
"""
if server.DEBUG & server.DBG_SQL:
- print 'exec', query, args
+ print('exec', query, args)
try:
self.cu.execute(str(query), args)
except Exception as ex:
- print "sql: %r\n args: %s\ndbms message: %r" % (
- query, args, ex.args[0])
+ print("sql: %r\n args: %s\ndbms message: %r" % (
+ query, args, ex.args[0]))
raise
def fetchall(self):
@@ -134,7 +137,7 @@
Type of _UndoException message must be `unicode` by design in CubicWeb.
"""
- assert isinstance(self.args[0], unicode)
+ assert isinstance(self.args[0], text_type)
return self.args[0]
@@ -556,7 +559,7 @@
sql, qargs, cbs = self._rql_sqlgen.generate(union, args, varmap)
self._cache[cachekey] = sql, qargs, cbs
args = self.merge_args(args, qargs)
- assert isinstance(sql, basestring), repr(sql)
+ assert isinstance(sql, string_types), repr(sql)
cursor = self.doexec(cnx, sql, args)
results = self.process_result(cursor, cnx, cbs)
assert dbg_results(results)
@@ -611,7 +614,7 @@
self.doexec(cnx, sql, attrs)
if cnx.ertype_supports_undo(entity.cw_etype):
self._record_tx_action(cnx, 'tx_entity_actions', u'C',
- etype=unicode(entity.cw_etype), eid=entity.eid)
+ etype=text_type(entity.cw_etype), eid=entity.eid)
def update_entity(self, cnx, entity):
"""replace an entity in the source"""
@@ -620,8 +623,8 @@
if cnx.ertype_supports_undo(entity.cw_etype):
changes = self._save_attrs(cnx, entity, attrs)
self._record_tx_action(cnx, 'tx_entity_actions', u'U',
- etype=unicode(entity.cw_etype), eid=entity.eid,
- changes=self._binary(dumps(changes)))
+ etype=text_type(entity.cw_etype), eid=entity.eid,
+ changes=self._binary(pickle.dumps(changes)))
sql = self.sqlgen.update(SQL_PREFIX + entity.cw_etype, attrs,
['cw_eid'])
self.doexec(cnx, sql, attrs)
@@ -635,8 +638,8 @@
if (r.final or r.inlined) and not r in VIRTUAL_RTYPES]
changes = self._save_attrs(cnx, entity, attrs)
self._record_tx_action(cnx, 'tx_entity_actions', u'D',
- etype=unicode(entity.cw_etype), eid=entity.eid,
- changes=self._binary(dumps(changes)))
+ etype=text_type(entity.cw_etype), eid=entity.eid,
+ changes=self._binary(pickle.dumps(changes)))
attrs = {'cw_eid': entity.eid}
sql = self.sqlgen.delete(SQL_PREFIX + entity.cw_etype, attrs)
self.doexec(cnx, sql, attrs)
@@ -646,7 +649,7 @@
self._add_relations(cnx, rtype, [(subject, object)], inlined)
if cnx.ertype_supports_undo(rtype):
self._record_tx_action(cnx, 'tx_relation_actions', u'A',
- eid_from=subject, rtype=unicode(rtype), eid_to=object)
+ eid_from=subject, rtype=text_type(rtype), eid_to=object)
def add_relations(self, cnx, rtype, subj_obj_list, inlined=False):
"""add a relations to the source"""
@@ -654,7 +657,7 @@
if cnx.ertype_supports_undo(rtype):
for subject, object in subj_obj_list:
self._record_tx_action(cnx, 'tx_relation_actions', u'A',
- eid_from=subject, rtype=unicode(rtype), eid_to=object)
+ eid_from=subject, rtype=text_type(rtype), eid_to=object)
def _add_relations(self, cnx, rtype, subj_obj_list, inlined=False):
"""add a relation to the source"""
@@ -671,7 +674,7 @@
etypes[etype].append((subject, object))
else:
etypes[etype] = [(subject, object)]
- for subj_etype, subj_obj_list in etypes.iteritems():
+ for subj_etype, subj_obj_list in etypes.items():
attrs = [{'cw_eid': subject, SQL_PREFIX + rtype: object}
for subject, object in subj_obj_list]
sql.append((self.sqlgen.update(SQL_PREFIX + etype, attrs[0],
@@ -686,7 +689,7 @@
self._delete_relation(cnx, subject, rtype, object, rschema.inlined)
if cnx.ertype_supports_undo(rtype):
self._record_tx_action(cnx, 'tx_relation_actions', u'R',
- eid_from=subject, rtype=unicode(rtype), eid_to=object)
+ eid_from=subject, rtype=text_type(rtype), eid_to=object)
def _delete_relation(self, cnx, subject, rtype, object, inlined=False):
"""delete a relation from the source"""
@@ -708,7 +711,7 @@
"""
cursor = cnx.cnxset.cu
if server.DEBUG & server.DBG_SQL:
- print 'exec', query, args, cnx.cnxset.cnx
+ print('exec', query, args, cnx.cnxset.cnx)
try:
# str(query) to avoid error if it's a unicode string
cursor.execute(str(query), args)
@@ -767,7 +770,7 @@
it's a function just so that it shows up in profiling
"""
if server.DEBUG & server.DBG_SQL:
- print 'execmany', query, 'with', len(args), 'arguments', cnx.cnxset.cnx
+ print('execmany', query, 'with', len(args), 'arguments', cnx.cnxset.cnx)
cursor = cnx.cnxset.cu
try:
# str(query) to avoid error if it's a unicode string
@@ -852,10 +855,9 @@
"""return a tuple (type, extid, source) for the entity with id <eid>"""
sql = 'SELECT type, extid, asource FROM entities WHERE eid=%s' % eid
res = self._eid_type_source(cnx, eid, sql)
- if res[-2] is not None:
- if not isinstance(res, list):
- res = list(res)
- res[-2] = b64decode(res[-2])
+ if not isinstance(res, list):
+ res = list(res)
+ res[-2] = self.decode_extid(res[-2])
return res
def eid_type_source_pre_131(self, cnx, eid):
@@ -864,15 +866,14 @@
res = self._eid_type_source(cnx, eid, sql)
if not isinstance(res, list):
res = list(res)
- if res[-1] is not None:
- res[-1] = b64decode(res[-1])
+ res[-1] = self.decode_extid(res[-1])
res.append("system")
return res
def extid2eid(self, cnx, extid):
"""get eid from an external id. Return None if no record found."""
- assert isinstance(extid, str)
- args = {'x': b64encode(extid)}
+ assert isinstance(extid, binary_type)
+ args = {'x': b64encode(extid).decode('ascii')}
cursor = self.doexec(cnx,
'SELECT eid FROM entities WHERE extid=%(x)s',
args)
@@ -911,10 +912,10 @@
assert cnx.cnxset is not None
# begin by inserting eid/type/source/extid into the entities table
if extid is not None:
- assert isinstance(extid, str)
- extid = b64encode(extid)
- attrs = {'type': unicode(entity.cw_etype), 'eid': entity.eid, 'extid': extid and unicode(extid),
- 'asource': unicode(source.uri)}
+ assert isinstance(extid, binary_type)
+ extid = b64encode(extid).decode('ascii')
+ attrs = {'type': text_type(entity.cw_etype), 'eid': entity.eid, 'extid': extid,
+ 'asource': text_type(source.uri)}
self._handle_insert_entity_sql(cnx, self.sqlgen.insert('entities', attrs), attrs)
# insert core relations: is, is_instance_of and cw_source
try:
@@ -975,13 +976,13 @@
if actionfilters.pop('public', True):
genrestr['txa_public'] = True
# put additional filters in trarestr and/or tearestr
- for key, val in actionfilters.iteritems():
+ for key, val in actionfilters.items():
if key == 'etype':
# filtering on etype implies filtering on entity actions
# only, and with no eid specified
assert actionfilters.get('action', 'C') in 'CUD'
assert not 'eid' in actionfilters
- tearestr['etype'] = unicode(val)
+ tearestr['etype'] = text_type(val)
elif key == 'eid':
# eid filter may apply to 'eid' of tx_entity_actions or to
# 'eid_from' OR 'eid_to' of tx_relation_actions
@@ -992,10 +993,10 @@
trarestr['eid_to'] = val
elif key == 'action':
if val in 'CUD':
- tearestr['txa_action'] = unicode(val)
+ tearestr['txa_action'] = text_type(val)
else:
assert val in 'AR'
- trarestr['txa_action'] = unicode(val)
+ trarestr['txa_action'] = text_type(val)
else:
raise AssertionError('unknow filter %s' % key)
assert trarestr or tearestr, "can't only filter on 'public'"
@@ -1029,11 +1030,11 @@
def tx_info(self, cnx, txuuid):
"""See :class:`cubicweb.repoapi.Connection.transaction_info`"""
- return tx.Transaction(cnx, txuuid, *self._tx_info(cnx, unicode(txuuid)))
+ return tx.Transaction(cnx, txuuid, *self._tx_info(cnx, text_type(txuuid)))
def tx_actions(self, cnx, txuuid, public):
"""See :class:`cubicweb.repoapi.Connection.transaction_actions`"""
- txuuid = unicode(txuuid)
+ txuuid = text_type(txuuid)
self._tx_info(cnx, txuuid)
restr = {'tx_uuid': txuuid}
if public:
@@ -1044,7 +1045,7 @@
'etype', 'eid', 'changes'))
with cnx.ensure_cnx_set:
cu = self.doexec(cnx, sql, restr)
- actions = [tx.EntityAction(a,p,o,et,e,c and loads(self.binary_to_str(c)))
+ actions = [tx.EntityAction(a,p,o,et,e,c and pickle.loads(self.binary_to_str(c)))
for a,p,o,et,e,c in cu.fetchall()]
sql = self.sqlgen.select('tx_relation_actions', restr,
('txa_action', 'txa_public', 'txa_order',
@@ -1168,8 +1169,8 @@
elif eschema.destination(rtype) in ('Bytes', 'Password'):
changes[column] = self._binary(value)
edited[rtype] = Binary(value)
- elif isinstance(value, str):
- edited[rtype] = unicode(value, cnx.encoding, 'replace')
+ elif PY2 and isinstance(value, str):
+ edited[rtype] = text_type(value, cnx.encoding, 'replace')
else:
edited[rtype] = value
# This must only be done after init_entitiy_caches : defered in calling functions
@@ -1210,14 +1211,14 @@
try:
sentity, oentity, rdef = _undo_rel_info(cnx, subj, rtype, obj)
except _UndoException as ex:
- errors.append(unicode(ex))
+ errors.append(text_type(ex))
else:
for role, entity in (('subject', sentity),
('object', oentity)):
try:
_undo_check_relation_target(entity, rdef, role)
except _UndoException as ex:
- errors.append(unicode(ex))
+ errors.append(text_type(ex))
continue
if not errors:
self.repo.hm.call_hooks('before_add_relation', cnx,
@@ -1293,7 +1294,7 @@
try:
sentity, oentity, rdef = _undo_rel_info(cnx, subj, rtype, obj)
except _UndoException as ex:
- errors.append(unicode(ex))
+ errors.append(text_type(ex))
else:
rschema = rdef.rtype
if rschema.inlined:
@@ -1544,7 +1545,7 @@
SQL_PREFIX + 'CWUser',
SQL_PREFIX + 'upassword',
SQL_PREFIX + 'login'),
- {'newhash': self.source._binary(newhash),
+ {'newhash': self.source._binary(newhash.encode('ascii')),
'login': login})
cnx.commit()
return user
@@ -1692,7 +1693,7 @@
self.logger.info('number of rows: %d', rowcount)
blocksize = self.blocksize
if rowcount > 0:
- for i, start in enumerate(xrange(0, rowcount, blocksize)):
+ for i, start in enumerate(range(0, rowcount, blocksize)):
rows = list(itertools.islice(rows_iterator, blocksize))
serialized = self._serialize(table, columns, rows)
archive.writestr('tables/%s.%04d' % (table, i), serialized)
@@ -1713,7 +1714,7 @@
return tuple(columns), rows
def _serialize(self, name, columns, rows):
- return dumps((name, columns, rows), pickle.HIGHEST_PROTOCOL)
+ return pickle.dumps((name, columns, rows), pickle.HIGHEST_PROTOCOL)
def restore(self, backupfile):
archive = zipfile.ZipFile(backupfile, 'r', allowZip64=True)
@@ -1761,7 +1762,7 @@
return sequences, numranges, tables, table_chunks
def read_sequence(self, archive, seq):
- seqname, columns, rows = loads(archive.read('sequences/%s' % seq))
+ seqname, columns, rows = pickle.loads(archive.read('sequences/%s' % seq))
assert seqname == seq
assert len(rows) == 1
assert len(rows[0]) == 1
@@ -1771,7 +1772,7 @@
self.cnx.commit()
def read_numrange(self, archive, numrange):
- rangename, columns, rows = loads(archive.read('numrange/%s' % numrange))
+ rangename, columns, rows = pickle.loads(archive.read('numrange/%s' % numrange))
assert rangename == numrange
assert len(rows) == 1
assert len(rows[0]) == 1
@@ -1786,7 +1787,7 @@
self.cnx.commit()
row_count = 0
for filename in filenames:
- tablename, columns, rows = loads(archive.read(filename))
+ tablename, columns, rows = pickle.loads(archive.read(filename))
assert tablename == table
if not rows:
continue
--- a/server/sources/rql2sql.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/sources/rql2sql.py Thu Dec 10 12:34:15 2015 +0100
@@ -51,6 +51,9 @@
import threading
+from six import PY2
+from six.moves import range
+
from logilab.database import FunctionDescr, SQL_FUNCTIONS_REGISTRY
from rql import BadRQLQuery, CoercionError
@@ -172,7 +175,7 @@
existssols = {}
unstable = set()
invariants = {}
- for vname, var in rqlst.defined_vars.iteritems():
+ for vname, var in rqlst.defined_vars.items():
vtype = newsols[0][vname]
if var._q_invariant or vname in varmap:
# remove invariant variable from solutions to remove duplicates
@@ -187,13 +190,13 @@
thisexistssols = [newsols[0]]
thisexistsvars = set()
existssols[var.scope] = thisexistssols, thisexistsvars
- for i in xrange(len(newsols)-1, 0, -1):
+ for i in range(len(newsols)-1, 0, -1):
if vtype != newsols[i][vname]:
thisexistssols.append(newsols.pop(i))
thisexistsvars.add(vname)
else:
# remember unstable variables
- for i in xrange(1, len(newsols)):
+ for i in range(1, len(newsols)):
if vtype != newsols[i][vname]:
unstable.add(vname)
if invariants:
@@ -205,11 +208,11 @@
newsols = newsols_
# reinsert solutions for invariants
for sol in newsols:
- for invvar, vartype in invariants[id(sol)].iteritems():
+ for invvar, vartype in invariants[id(sol)].items():
sol[invvar] = vartype
for sol in existssols:
try:
- for invvar, vartype in invariants[id(sol)].iteritems():
+ for invvar, vartype in invariants[id(sol)].items():
sol[invvar] = vartype
except KeyError:
continue
@@ -257,7 +260,7 @@
append(term)
if groups:
for vref in term.iget_nodes(VariableRef):
- if not vref in groups:
+ if not any(vref.is_equivalent(g) for g in groups):
groups.append(vref)
def fix_selection_and_group(rqlst, needwrap, selectsortterms,
@@ -273,7 +276,7 @@
(isinstance(term, Function) and
get_func_descr(term.name).aggregat)):
for vref in term.iget_nodes(VariableRef):
- if not vref in groupvrefs:
+ if not any(vref.is_equivalent(group) for group in groupvrefs):
groups.append(vref)
groupvrefs.append(vref)
if needwrap and (groups or having):
@@ -364,7 +367,7 @@
self.done = set()
self.tables = self.subtables.copy()
self.actual_tables = [[]]
- for _, tsql in self.tables.itervalues():
+ for _, tsql in self.tables.values():
self.actual_tables[-1].append(tsql)
self.outer_chains = []
self.outer_tables = {}
@@ -398,7 +401,7 @@
notdone_outside_vars = set()
# when iterating other solutions inner to an EXISTS subquery, we should
# reset variables which have this exists node as scope at each iteration
- for var in exists.stmt.defined_vars.itervalues():
+ for var in exists.stmt.defined_vars.values():
if var.scope is exists:
thisexistsvars.add(var.name)
elif var.name not in self.done:
@@ -600,7 +603,7 @@
self.outer_chains.remove(lchain)
rchain += lchain
self.mark_as_used_in_outer_join(leftalias)
- for alias, (aouter, aconditions, achain) in outer_tables.iteritems():
+ for alias, (aouter, aconditions, achain) in outer_tables.items():
if achain is lchain:
outer_tables[alias] = (aouter, aconditions, rchain)
else:
@@ -1475,7 +1478,7 @@
"""generate SQL name for a function"""
if func.name == 'FTIRANK':
try:
- rel = iter(func.children[0].variable.stinfo['ftirels']).next()
+ rel = next(iter(func.children[0].variable.stinfo['ftirels']))
except KeyError:
raise BadRQLQuery("can't use FTIRANK on variable not used in an"
" 'has_text' relation (eg full-text search)")
@@ -1512,7 +1515,7 @@
return self._mapped_term(constant, '%%(%s)s' % value)[0]
except KeyError:
_id = value
- if isinstance(_id, unicode):
+ if PY2 and isinstance(_id, unicode):
_id = _id.encode()
else:
_id = str(id(constant)).replace('-', '', 1)
@@ -1561,7 +1564,7 @@
# add additional restriction on entities.type column
pts = variable.stinfo['possibletypes']
if len(pts) == 1:
- etype = iter(variable.stinfo['possibletypes']).next()
+ etype = next(iter(variable.stinfo['possibletypes']))
restr = "%s.type='%s'" % (vtablename, etype)
else:
etypes = ','.join("'%s'" % et for et in pts)
@@ -1609,7 +1612,7 @@
def _temp_table_scope(self, select, table):
scope = 9999
- for var, sql in self._varmap.iteritems():
+ for var, sql in self._varmap.items():
# skip "attribute variable" in varmap (such 'T.login')
if not '.' in var and table == sql.split('.', 1)[0]:
try:
@@ -1668,7 +1671,7 @@
except KeyError:
pass
rel = (variable.stinfo.get('principal') or
- iter(variable.stinfo['rhsrelations']).next())
+ next(iter(variable.stinfo['rhsrelations'])))
linkedvar = rel.children[0].variable
if rel.r_type == 'eid':
return linkedvar.accept(self)
--- a/server/sources/storages.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/sources/storages.py Thu Dec 10 12:34:15 2015 +0100
@@ -23,6 +23,10 @@
from contextlib import contextmanager
import tempfile
+from six import PY2, PY3, text_type, binary_type
+
+from logilab.common import nullobject
+
from yams.schema import role_name
from cubicweb import Binary, ValidationError
@@ -44,7 +48,7 @@
query result process of fetched attribute's value and should have the
following prototype::
- callback(self, source, session, value)
+ callback(self, source, cnx, value)
where `value` is the value actually stored in the backend. None values
will be skipped (eg callback won't be called).
@@ -92,24 +96,33 @@
return tempfile.mkstemp(prefix=base, suffix=ext, dir=dirpath)
@contextmanager
-def fsimport(session):
- present = 'fs_importing' in session.transaction_data
- old_value = session.transaction_data.get('fs_importing')
- session.transaction_data['fs_importing'] = True
+def fsimport(cnx):
+ present = 'fs_importing' in cnx.transaction_data
+ old_value = cnx.transaction_data.get('fs_importing')
+ cnx.transaction_data['fs_importing'] = True
yield
if present:
- session.transaction_data['fs_importing'] = old_value
+ cnx.transaction_data['fs_importing'] = old_value
else:
- del session.transaction_data['fs_importing']
+ del cnx.transaction_data['fs_importing']
+
+
+_marker = nullobject()
class BytesFileSystemStorage(Storage):
"""store Bytes attribute value on the file system"""
- def __init__(self, defaultdir, fsencoding='utf-8', wmode=0444):
- if type(defaultdir) is unicode:
- defaultdir = defaultdir.encode(fsencoding)
+ def __init__(self, defaultdir, fsencoding=_marker, wmode=0o444):
+ if PY3:
+ if not isinstance(defaultdir, text_type):
+ raise TypeError('defaultdir must be a unicode object in python 3')
+ if fsencoding is not _marker:
+ raise ValueError('fsencoding is no longer supported in python 3')
+ else:
+ self.fsencoding = fsencoding or 'utf-8'
+ if isinstance(defaultdir, text_type):
+ defaultdir = defaultdir.encode(fsencoding)
self.default_directory = defaultdir
- self.fsencoding = fsencoding
# extra umask to use when creating file
# 0444 as in "only allow read bit in permission"
self._wmode = wmode
@@ -126,7 +139,7 @@
fileobj.close()
- def callback(self, source, session, value):
+ def callback(self, source, cnx, value):
"""sql generator callback when some attribute with a custom storage is
accessed
"""
@@ -145,7 +158,8 @@
binary = entity.cw_edited.pop(attr)
fd, fpath = self.new_fs_path(entity, attr)
# bytes storage used to store file's path
- entity.cw_edited.edited_attribute(attr, Binary(fpath))
+ binary_obj = Binary(fpath if PY2 else fpath.encode('utf-8'))
+ entity.cw_edited.edited_attribute(attr, binary_obj)
self._writecontent(fd, binary)
AddFileOp.get_instance(entity._cw).add_data(fpath)
return binary
@@ -187,7 +201,8 @@
entity.cw_edited.edited_attribute(attr, None)
else:
# register the new location for the file.
- entity.cw_edited.edited_attribute(attr, Binary(fpath))
+ binary_obj = Binary(fpath if PY2 else fpath.encode('utf-8'))
+ entity.cw_edited.edited_attribute(attr, binary_obj)
if oldpath is not None and oldpath != fpath:
# Mark the old file as useless so the file will be removed at
# commit.
@@ -206,16 +221,19 @@
# available. Keeping the extension is useful for example in the case of
# PIL processing that use filename extension to detect content-type, as
# well as providing more understandable file names on the fs.
+ if PY2:
+ attr = attr.encode('ascii')
basename = [str(entity.eid), attr]
name = entity.cw_attr_metadata(attr, 'name')
if name is not None:
- basename.append(name.encode(self.fsencoding))
+ basename.append(name.encode(self.fsencoding) if PY2 else name)
fd, fspath = uniquify_path(self.default_directory,
'_'.join(basename))
if fspath is None:
msg = entity._cw._('failed to uniquify path (%s, %s)') % (
self.default_directory, '_'.join(basename))
raise ValidationError(entity.eid, {role_name(attr, 'subject'): msg})
+ assert isinstance(fspath, str) # bytes on py2, unicode on py3
return fd, fspath
def current_fs_path(self, entity, attr):
@@ -229,34 +247,40 @@
rawvalue = cu.fetchone()[0]
if rawvalue is None: # no previous value
return None
- return sysource._process_value(rawvalue, cu.description[0],
- binarywrap=str)
+ fspath = sysource._process_value(rawvalue, cu.description[0],
+ binarywrap=binary_type)
+ if PY3:
+ fspath = fspath.decode('utf-8')
+ assert isinstance(fspath, str) # bytes on py2, unicode on py3
+ return fspath
def migrate_entity(self, entity, attribute):
"""migrate an entity attribute to the storage"""
entity.cw_edited = EditedEntity(entity, **entity.cw_attr_cache)
self.entity_added(entity, attribute)
- session = entity._cw
- source = session.repo.system_source
+ cnx = entity._cw
+ source = cnx.repo.system_source
attrs = source.preprocess_entity(entity)
sql = source.sqlgen.update('cw_' + entity.cw_etype, attrs,
['cw_eid'])
- source.doexec(session, sql, attrs)
+ source.doexec(cnx, sql, attrs)
entity.cw_edited = None
class AddFileOp(hook.DataOperationMixIn, hook.Operation):
def rollback_event(self):
for filepath in self.get_data():
+ assert isinstance(filepath, str) # bytes on py2, unicode on py3
try:
unlink(filepath)
except Exception as ex:
- self.error('cant remove %s: %s' % (filepath, ex))
+ self.error("can't remove %s: %s" % (filepath, ex))
class DeleteFileOp(hook.DataOperationMixIn, hook.Operation):
def postcommit_event(self):
for filepath in self.get_data():
+ assert isinstance(filepath, str) # bytes on py2, unicode on py3
try:
unlink(filepath)
except Exception as ex:
- self.error('cant remove %s: %s' % (filepath, ex))
+ self.error("can't remove %s: %s" % (filepath, ex))
--- a/server/sqlutils.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/sqlutils.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""SQL utilities functions and classes."""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
@@ -23,10 +24,12 @@
import re
import subprocess
from os.path import abspath
-from itertools import ifilter
from logging import getLogger
from datetime import time, datetime
+from six import string_types, text_type
+from six.moves import filter
+
from logilab import database as db, common as lgc
from logilab.common.shellutils import ProgressBar, DummyProgressBar
from logilab.common.deprecation import deprecated
@@ -44,8 +47,12 @@
SQL_PREFIX = 'cw_'
def _run_command(cmd):
- print ' '.join(cmd)
- return subprocess.call(cmd)
+ if isinstance(cmd, string_types):
+ print(cmd)
+ return subprocess.call(cmd, shell=True)
+ else:
+ print(' '.join(cmd))
+ return subprocess.call(cmd)
def sqlexec(sqlstmts, cursor_or_execute, withpb=True,
@@ -69,7 +76,7 @@
else:
execute = cursor_or_execute
sqlstmts_as_string = False
- if isinstance(sqlstmts, basestring):
+ if isinstance(sqlstmts, string_types):
sqlstmts_as_string = True
sqlstmts = sqlstmts.split(delimiter)
if withpb:
@@ -87,7 +94,7 @@
try:
# some dbapi modules doesn't accept unicode for sql string
execute(str(sql))
- except Exception, err:
+ except Exception as err:
if cnx:
cnx.rollback()
failed.append(sql)
@@ -95,7 +102,7 @@
if cnx:
cnx.commit()
if withpb:
- print
+ print()
if sqlstmts_as_string:
failed = delimiter.join(failed)
return failed
@@ -178,9 +185,9 @@
# for mssql, we need to drop views before tables
if hasattr(dbhelper, 'list_views'):
cmds += ['DROP VIEW %s;' % name
- for name in ifilter(_SQL_DROP_ALL_USER_TABLES_FILTER_FUNCTION, dbhelper.list_views(sqlcursor))]
+ for name in filter(_SQL_DROP_ALL_USER_TABLES_FILTER_FUNCTION, dbhelper.list_views(sqlcursor))]
cmds += ['DROP TABLE %s;' % name
- for name in ifilter(_SQL_DROP_ALL_USER_TABLES_FILTER_FUNCTION, dbhelper.list_tables(sqlcursor))]
+ for name in filter(_SQL_DROP_ALL_USER_TABLES_FILTER_FUNCTION, dbhelper.list_tables(sqlcursor))]
return '\n'.join(cmds)
@@ -370,7 +377,7 @@
def merge_args(self, args, query_args):
if args is not None:
newargs = {}
- for key, val in args.iteritems():
+ for key, val in args.items():
# convert cubicweb binary into db binary
if isinstance(val, Binary):
val = self._binary(val.getvalue())
@@ -441,7 +448,7 @@
attrs = {}
eschema = entity.e_schema
converters = getattr(self.dbhelper, 'TYPE_CONVERTERS', {})
- for attr, value in entity.cw_edited.iteritems():
+ for attr, value in entity.cw_edited.items():
if value is not None and eschema.subjrels[attr].final:
atype = str(entity.e_schema.destination(attr))
if atype in converters:
@@ -481,7 +488,7 @@
if value is not None:
self.values.add(value)
def finalize(self):
- return ', '.join(unicode(v) for v in self.values)
+ return ', '.join(text_type(v) for v in self.values)
cnx.create_aggregate("GROUP_CONCAT", 1, group_concat)
--- a/server/ssplanner.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/ssplanner.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,6 +19,8 @@
__docformat__ = "restructuredtext en"
+from six import text_type
+
from rql.stmts import Union, Select
from rql.nodes import Constant, Relation
@@ -54,7 +56,7 @@
value = rhs.eval(plan.args)
eschema = edef.entity.e_schema
attrtype = eschema.subjrels[rtype].objects(eschema)[0]
- if attrtype == 'Password' and isinstance(value, unicode):
+ if attrtype == 'Password' and isinstance(value, text_type):
value = value.encode('UTF8')
edef.edited_attribute(rtype, value)
elif str(rhs) in to_build:
@@ -306,7 +308,7 @@
if varmap is None:
return varmap
maprepr = {}
- for var, sql in varmap.iteritems():
+ for var, sql in varmap.items():
table, col = sql.split('.')
maprepr[var] = '%s.%s' % (tablesinorder[table], col)
return maprepr
@@ -527,7 +529,7 @@
result[i] = newrow
# update entities
repo.glob_add_relations(cnx, relations)
- for eid, edited in edefs.iteritems():
+ for eid, edited in edefs.items():
repo.glob_update_entity(cnx, edited)
return result
--- a/server/test/data-cwep002/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/data-cwep002/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -33,4 +33,3 @@
class has_employee(ComputedRelation):
rule = 'O works_for S'
__permissions__ = {'read': ('managers',)}
-
--- a/server/test/data-migractions/cubes/fakeemail/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/data-migractions/cubes/fakeemail/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -5,7 +5,7 @@
:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
# pylint: disable-msg=E0611,F0401
from yams.buildobjs import (SubjectRelation, RelationType, EntityType,
@@ -84,5 +84,3 @@
subject = 'Comment'
name = 'generated_by'
object = 'Email'
-
-
--- a/server/test/data-migractions/migratedapp/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/data-migractions/migratedapp/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -21,6 +21,7 @@
SubjectRelation, Bytes,
RichString, String, Int, Boolean, Datetime, Date, Float)
from yams.constraints import SizeConstraint, UniqueConstraint
+from cubicweb import _
from cubicweb.schema import (WorkflowableEntityType, RQLConstraint,
RQLVocabularyConstraint,
ERQLExpression, RRQLExpression)
--- a/server/test/data-migractions/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/data-migractions/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -24,6 +24,8 @@
RQLConstraint, RQLUniqueConstraint,
RQLVocabularyConstraint,
ERQLExpression, RRQLExpression)
+from cubicweb import _
+
class Affaire(WorkflowableEntityType):
__permissions__ = {
@@ -85,7 +87,7 @@
object = 'SubDivision'
from cubicweb.schemas.base import CWUser
-CWUser.get_relations('login').next().fulltextindexed = True
+next(CWUser.get_relations('login')).fulltextindexed = True
class Note(WorkflowableEntityType):
date = String(maxsize=10)
@@ -223,13 +225,13 @@
class ecrit_par_1(RelationDefinition):
name = 'ecrit_par'
subject = 'Note'
- object ='Personne'
+ object = 'Personne'
cardinality = '?*'
class ecrit_par_2(RelationDefinition):
name = 'ecrit_par'
subject = 'Note'
- object ='CWUser'
+ object = 'CWUser'
cardinality='?*'
--- a/server/test/data-schema2sql/schema/Dates.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/data-schema2sql/schema/Dates.py Thu Dec 10 12:34:15 2015 +0100
@@ -26,4 +26,3 @@
d2 = Date(default=date(2007, 12, 11))
t1 = Time(default=time(8, 40))
t2 = Time(default=time(9, 45))
-
--- a/server/test/data-schema2sql/schema/State.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/data-schema2sql/schema/State.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,7 +19,7 @@
SubjectRelation, Int, String, Boolean)
from yams.constraints import SizeConstraint, UniqueConstraint
-from __init__ import RESTRICTED_RTYPE_PERMS
+from . import RESTRICTED_RTYPE_PERMS
class State(EntityType):
"""used to associate simple states to an entity
--- a/server/test/data-schema2sql/schema/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/data-schema2sql/schema/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -110,4 +110,3 @@
'add': ('managers',),
'delete': ('managers',),
}
-
--- a/server/test/data-schemaserial/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/data-schemaserial/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -29,4 +29,3 @@
inline2 = SubjectRelation('Affaire', inlined=True, cardinality='?*')
custom_field_of_jungle = BabarTestType(jungle_speed=42)
-
--- a/server/test/data-schemaserial/site_cubicweb.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/data-schemaserial/site_cubicweb.py Thu Dec 10 12:34:15 2015 +0100
@@ -27,4 +27,3 @@
def dumb_sort(something):
return something
register_sqlite_pyfunc(dumb_sort)
-
--- a/server/test/data/migration/postcreate.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/data/migration/postcreate.py Thu Dec 10 12:34:15 2015 +0100
@@ -35,4 +35,3 @@
wf.add_transition(u'start', pitetre, encours)
wf.add_transition(u'end', encours, finie)
commit()
-
--- a/server/test/data/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/data/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -24,6 +24,7 @@
RQLConstraint, RQLUniqueConstraint,
RQLVocabularyConstraint,
ERQLExpression, RRQLExpression)
+from cubicweb import _
class Affaire(WorkflowableEntityType):
__permissions__ = {
@@ -85,7 +86,7 @@
object = 'SubDivision'
from cubicweb.schemas.base import CWUser
-CWUser.get_relations('login').next().fulltextindexed = True
+next(CWUser.get_relations('login')).fulltextindexed = True
class Note(WorkflowableEntityType):
date = String(maxsize=10)
--- a/server/test/datacomputed/migratedapp/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/datacomputed/migratedapp/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -59,3 +59,8 @@
class renamed(ComputedRelation):
rule = 'S employees E, O concerns E'
+
+
+class perm_changes(ComputedRelation):
+ __permissions__ = {'read': ('managers',)}
+ rule = 'S employees E, O concerns E'
--- a/server/test/datacomputed/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/datacomputed/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -58,3 +58,8 @@
class to_be_renamed(ComputedRelation):
rule = 'S employees E, O concerns E'
+
+
+class perm_changes(ComputedRelation):
+ __permissions__ = {'read': ('managers', 'users')}
+ rule = 'S employees E, O concerns E'
--- a/server/test/requirements.txt Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/requirements.txt Thu Dec 10 12:34:15 2015 +0100
@@ -1,4 +1,5 @@
psycopg2
+ldap3
cubicweb-basket
cubicweb-card
cubicweb-comment
--- a/server/test/unittest_checkintegrity.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/unittest_checkintegrity.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,7 +17,13 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
import sys
-from StringIO import StringIO
+
+from six import PY2
+if PY2:
+ from StringIO import StringIO
+else:
+ from io import StringIO
+
from logilab.common.testlib import TestCase, unittest_main
from cubicweb.devtools import get_test_db_handler, TestServerConfiguration
--- a/server/test/unittest_datafeed.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/unittest_datafeed.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,3 +1,4 @@
+# coding: utf-8
# copyright 2011-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
@@ -16,7 +17,6 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-import mimetools
from datetime import timedelta
from contextlib import contextmanager
@@ -28,7 +28,7 @@
def setup_database(self):
with self.admin_access.repo_cnx() as cnx:
with self.base_parser(cnx):
- cnx.create_entity('CWSource', name=u'myfeed', type=u'datafeed',
+ cnx.create_entity('CWSource', name=u'ô myfeed', type=u'datafeed',
parser=u'testparser', url=u'ignored',
config=u'synchronization-interval=1min')
cnx.commit()
@@ -48,21 +48,23 @@
entity.cw_edited.update(sourceparams['item'])
with self.temporary_appobjects(AParser):
- if 'myfeed' in self.repo.sources_by_uri:
- yield self.repo.sources_by_uri['myfeed']._get_parser(session)
+ if u'ô myfeed' in self.repo.sources_by_uri:
+ yield self.repo.sources_by_uri[u'ô myfeed']._get_parser(session)
else:
yield
def test(self):
- self.assertIn('myfeed', self.repo.sources_by_uri)
- dfsource = self.repo.sources_by_uri['myfeed']
+ self.assertIn(u'ô myfeed', self.repo.sources_by_uri)
+ dfsource = self.repo.sources_by_uri[u'ô myfeed']
self.assertNotIn('use_cwuri_as_url', dfsource.__dict__)
- self.assertEqual({'type': u'datafeed', 'uri': u'myfeed', 'use-cwuri-as-url': True},
+ self.assertEqual({'type': u'datafeed', 'uri': u'ô myfeed', 'use-cwuri-as-url': True},
dfsource.public_config)
self.assertEqual(dfsource.use_cwuri_as_url, True)
self.assertEqual(dfsource.latest_retrieval, None)
self.assertEqual(dfsource.synchro_interval, timedelta(seconds=60))
self.assertFalse(dfsource.fresh())
+ # ensure source's logger name has been unormalized
+ self.assertEqual(dfsource.info.__self__.name, 'cubicweb.sources.o myfeed')
with self.repo.internal_cnx() as cnx:
with self.base_parser(cnx):
@@ -78,17 +80,17 @@
self.assertEqual(entity.title, 'cubicweb.org')
self.assertEqual(entity.content, 'the cw web site')
self.assertEqual(entity.cwuri, 'http://www.cubicweb.org/')
- self.assertEqual(entity.cw_source[0].name, 'myfeed')
+ self.assertEqual(entity.cw_source[0].name, u'ô myfeed')
self.assertEqual(entity.cw_metainformation(),
{'type': 'Card',
- 'source': {'uri': 'myfeed', 'type': 'datafeed', 'use-cwuri-as-url': True},
- 'extid': 'http://www.cubicweb.org/'}
+ 'source': {'uri': u'ô myfeed', 'type': 'datafeed', 'use-cwuri-as-url': True},
+ 'extid': b'http://www.cubicweb.org/'}
)
self.assertEqual(entity.absolute_url(), 'http://www.cubicweb.org/')
# test repo cache keys
self.assertEqual(self.repo._type_source_cache[entity.eid],
- ('Card', 'http://www.cubicweb.org/', 'myfeed'))
- self.assertEqual(self.repo._extid_cache['http://www.cubicweb.org/'],
+ ('Card', b'http://www.cubicweb.org/', u'ô myfeed'))
+ self.assertEqual(self.repo._extid_cache[b'http://www.cubicweb.org/'],
entity.eid)
# test repull
stats = dfsource.pull_data(cnx, force=True)
@@ -101,19 +103,18 @@
self.assertEqual(stats['created'], set())
self.assertEqual(stats['updated'], set((entity.eid,)))
self.assertEqual(self.repo._type_source_cache[entity.eid],
- ('Card', 'http://www.cubicweb.org/', 'myfeed'))
- self.assertEqual(self.repo._extid_cache['http://www.cubicweb.org/'],
+ ('Card', b'http://www.cubicweb.org/', u'ô myfeed'))
+ self.assertEqual(self.repo._extid_cache[b'http://www.cubicweb.org/'],
entity.eid)
self.assertEqual(dfsource.source_cwuris(cnx),
- {'http://www.cubicweb.org/': (entity.eid, 'Card')}
- )
+ {b'http://www.cubicweb.org/': (entity.eid, 'Card')})
self.assertTrue(dfsource.latest_retrieval)
self.assertTrue(dfsource.fresh())
# test_rename_source
with self.admin_access.repo_cnx() as cnx:
- cnx.execute('SET S name "myrenamedfeed" WHERE S is CWSource, S name "myfeed"')
+ cnx.entity_from_eid(dfsource.eid).cw_set(name=u"myrenamedfeed")
cnx.commit()
entity = cnx.execute('Card X').get_entity(0, 0)
self.assertEqual(entity.cwuri, 'http://www.cubicweb.org/')
@@ -121,11 +122,11 @@
self.assertEqual(entity.cw_metainformation(),
{'type': 'Card',
'source': {'uri': 'myrenamedfeed', 'type': 'datafeed', 'use-cwuri-as-url': True},
- 'extid': 'http://www.cubicweb.org/'}
+ 'extid': b'http://www.cubicweb.org/'}
)
self.assertEqual(self.repo._type_source_cache[entity.eid],
- ('Card', 'http://www.cubicweb.org/', 'myrenamedfeed'))
- self.assertEqual(self.repo._extid_cache['http://www.cubicweb.org/'],
+ ('Card', b'http://www.cubicweb.org/', 'myrenamedfeed'))
+ self.assertEqual(self.repo._extid_cache[b'http://www.cubicweb.org/'],
entity.eid)
# test_delete_source
@@ -140,7 +141,14 @@
value = parser.retrieve_url('a string')
self.assertEqual(200, value.getcode())
self.assertEqual('a string', value.geturl())
- self.assertIsInstance(value.info(), mimetools.Message)
+
+ def test_update_url(self):
+ dfsource = self.repo.sources_by_uri[u'ô myfeed']
+ with self.admin_access.repo_cnx() as cnx:
+ cnx.entity_from_eid(dfsource.eid).cw_set(url=u"http://pouet.com\nhttp://pouet.org")
+ self.assertEqual(dfsource.urls, [u'ignored'])
+ cnx.commit()
+ self.assertEqual(dfsource.urls, [u"http://pouet.com", u"http://pouet.org"])
class DataFeedConfigTC(CubicWebTC):
--- a/server/test/unittest_ldapsource.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/unittest_ldapsource.py Thu Dec 10 12:34:15 2015 +0100
@@ -15,19 +15,26 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
-"""cubicweb.server.sources.ldapusers unit and functional tests"""
+"""cubicweb.server.sources.ldapfeed unit and functional tests
+
+Those tests expect to have slapd, python-ldap3 and ldapscripts packages installed.
+"""
+from __future__ import print_function
import os
import sys
import shutil
import time
-from os.path import join, exists
import subprocess
import tempfile
+import unittest
+from os.path import join
+
+from six import string_types
+from six.moves import range
from cubicweb import AuthenticationError
from cubicweb.devtools.testlib import CubicWebTC
-from cubicweb.devtools.repotest import RQLGeneratorTC
from cubicweb.devtools.httptest import get_available_port
@@ -44,13 +51,14 @@
URL = None
+
def create_slapd_configuration(cls):
global URL
slapddir = tempfile.mkdtemp('cw-unittest-ldap')
config = cls.config
slapdconf = join(config.apphome, "slapd.conf")
- confin = file(join(config.apphome, "slapd.conf.in")).read()
- confstream = file(slapdconf, 'w')
+ confin = open(join(config.apphome, "slapd.conf.in")).read()
+ confstream = open(slapdconf, 'w')
confstream.write(confin % {'apphome': config.apphome, 'testdir': slapddir})
confstream.close()
# fill ldap server with some data
@@ -61,16 +69,16 @@
slapproc = subprocess.Popen(cmdline, stdout=PIPE, stderr=PIPE)
stdout, stderr = slapproc.communicate()
if slapproc.returncode:
- print >> sys.stderr, ('slapadd returned with status: %s'
- % slapproc.returncode)
+ print('slapadd returned with status: %s'
+ % slapproc.returncode, file=sys.stderr)
sys.stdout.write(stdout)
sys.stderr.write(stderr)
- #ldapuri = 'ldapi://' + join(basedir, "ldapi").replace('/', '%2f')
- port = get_available_port(xrange(9000, 9100))
+ # ldapuri = 'ldapi://' + join(basedir, "ldapi").replace('/', '%2f')
+ port = get_available_port(range(9000, 9100))
host = 'localhost:%s' % port
ldapuri = 'ldap://%s' % host
- cmdline = ["/usr/sbin/slapd", "-f", slapdconf, "-h", ldapuri, "-d", "0"]
+ cmdline = ["/usr/sbin/slapd", "-f", slapdconf, "-h", ldapuri, "-d", "0"]
config.info('Starting slapd:', ' '.join(cmdline))
PIPE = subprocess.PIPE
cls.slapd_process = subprocess.Popen(cmdline, stdout=PIPE, stderr=PIPE)
@@ -83,6 +91,7 @@
URL = u'ldap://%s' % host
return slapddir
+
def terminate_slapd(cls):
config = cls.config
if cls.slapd_process and cls.slapd_process.returncode is None:
@@ -90,12 +99,12 @@
if hasattr(cls.slapd_process, 'terminate'):
cls.slapd_process.terminate()
else:
- import os, signal
+ import signal
os.kill(cls.slapd_process.pid, signal.SIGTERM)
stdout, stderr = cls.slapd_process.communicate()
if cls.slapd_process.returncode:
- print >> sys.stderr, ('slapd returned with status: %s'
- % cls.slapd_process.returncode)
+ print('slapd returned with status: %s'
+ % cls.slapd_process.returncode, file=sys.stderr)
sys.stdout.write(stdout)
sys.stderr.write(stderr)
config.info('DONE')
@@ -107,6 +116,8 @@
@classmethod
def setUpClass(cls):
+ if not os.path.exists('/usr/sbin/slapd'):
+ raise unittest.SkipTest('slapd not found')
from cubicweb.cwctl import init_cmdline_log_threshold
init_cmdline_log_threshold(cls.config, cls.loglevel)
cls._tmpdir = create_slapd_configuration(cls)
@@ -139,7 +150,7 @@
cnx.execute('DELETE Any E WHERE E cw_source S, S name "ldap"')
cnx.execute('SET S config %(conf)s, S url %(url)s '
'WHERE S is CWSource, S name "ldap"',
- {"conf": CONFIG_LDAPFEED, 'url': URL} )
+ {"conf": CONFIG_LDAPFEED, 'url': URL})
cnx.commit()
with self.repo.internal_cnx() as cnx:
self.pull(cnx)
@@ -148,32 +159,32 @@
"""
add an LDAP entity
"""
- modcmd = ['dn: %s'%dn, 'changetype: add']
- for key, values in mods.iteritems():
- if isinstance(values, basestring):
+ modcmd = ['dn: %s' % dn, 'changetype: add']
+ for key, values in mods.items():
+ if isinstance(values, string_types):
values = [values]
for value in values:
- modcmd.append('%s: %s'%(key, value))
+ modcmd.append('%s: %s' % (key, value))
self._ldapmodify(modcmd)
def delete_ldap_entry(self, dn):
"""
delete an LDAP entity
"""
- modcmd = ['dn: %s'%dn, 'changetype: delete']
+ modcmd = ['dn: %s' % dn, 'changetype: delete']
self._ldapmodify(modcmd)
def update_ldap_entry(self, dn, mods):
"""
modify one or more attributes of an LDAP entity
"""
- modcmd = ['dn: %s'%dn, 'changetype: modify']
- for (kind, key), values in mods.iteritems():
+ modcmd = ['dn: %s' % dn, 'changetype: modify']
+ for (kind, key), values in mods.items():
modcmd.append('%s: %s' % (kind, key))
- if isinstance(values, basestring):
+ if isinstance(values, string_types):
values = [values]
for value in values:
- modcmd.append('%s: %s'%(key, value))
+ modcmd.append('%s: %s' % (key, value))
modcmd.append('-')
self._ldapmodify(modcmd)
@@ -183,10 +194,11 @@
'cn=admin,dc=cubicweb,dc=test', '-w', 'cw']
PIPE = subprocess.PIPE
p = subprocess.Popen(updatecmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
- p.stdin.write('\n'.join(modcmd))
+ p.stdin.write('\n'.join(modcmd).encode('ascii'))
p.stdin.close()
if p.wait():
- raise RuntimeError("ldap update failed: %s"%('\n'.join(p.stderr.readlines())))
+ raise RuntimeError("ldap update failed: %s" % ('\n'.join(p.stderr.readlines())))
+
class CheckWrongGroup(LDAPFeedTestBase):
"""
@@ -196,18 +208,17 @@
def test_wrong_group(self):
with self.admin_access.repo_cnx() as cnx:
- source = cnx.execute('CWSource S WHERE S type="ldapfeed"').get_entity(0,0)
+ source = cnx.execute('CWSource S WHERE S type="ldapfeed"').get_entity(0, 0)
config = source.repo_source.check_config(source)
# inject a bogus group here, along with at least a valid one
- config['user-default-group'] = ('thisgroupdoesnotexists','users')
+ config['user-default-group'] = ('thisgroupdoesnotexists', 'users')
source.repo_source.update_config(source, config)
cnx.commit()
# here we emitted an error log entry
- stats = source.repo_source.pull_data(cnx, force=True, raise_on_error=True)
+ source.repo_source.pull_data(cnx, force=True, raise_on_error=True)
cnx.commit()
-
class LDAPFeedUserTC(LDAPFeedTestBase):
"""
A testcase for CWUser support in ldapfeed (basic tests and authentication).
@@ -284,12 +295,12 @@
# and that the password stored in the system source is not empty or so
user = cnx.execute('CWUser U WHERE U login "syt"').get_entity(0, 0)
user.cw_clear_all_caches()
- pwd = cnx.system_sql("SELECT cw_upassword FROM cw_cwuser WHERE cw_login='syt';").fetchall()[0][0]
+ cu = cnx.system_sql("SELECT cw_upassword FROM cw_cwuser WHERE cw_login='syt';")
+ pwd = cu.fetchall()[0][0]
self.assertIsNotNone(pwd)
self.assertTrue(str(pwd))
-
class LDAPFeedUserDeletionTC(LDAPFeedTestBase):
"""
A testcase for situations where users are deleted from or
@@ -299,7 +310,7 @@
def test_a_filter_inactivate(self):
""" filtered out people should be deactivated, unable to authenticate """
with self.admin_access.repo_cnx() as cnx:
- source = cnx.execute('CWSource S WHERE S type="ldapfeed"').get_entity(0,0)
+ source = cnx.execute('CWSource S WHERE S type="ldapfeed"').get_entity(0, 0)
config = source.repo_source.check_config(source)
# filter with adim's phone number
config['user-filter'] = u'(%s=%s)' % ('telephoneNumber', '109')
@@ -346,21 +357,22 @@
self.pull(cnx)
# reinsert syt
self.add_ldap_entry('uid=syt,ou=People,dc=cubicweb,dc=test',
- { 'objectClass': ['OpenLDAPperson','posixAccount','top','shadowAccount'],
- 'cn': 'Sylvain Thenault',
- 'sn': 'Thenault',
- 'gidNumber': '1004',
- 'uid': 'syt',
- 'homeDirectory': '/home/syt',
- 'shadowFlag': '134538764',
- 'uidNumber': '1004',
- 'givenName': 'Sylvain',
- 'telephoneNumber': '106',
- 'displayName': 'sthenault',
- 'gecos': 'Sylvain Thenault',
- 'mail': ['sylvain.thenault@logilab.fr','syt@logilab.fr'],
- 'userPassword': 'syt',
- })
+ {'objectClass': ['OpenLDAPperson', 'posixAccount', 'top',
+ 'shadowAccount'],
+ 'cn': 'Sylvain Thenault',
+ 'sn': 'Thenault',
+ 'gidNumber': '1004',
+ 'uid': 'syt',
+ 'homeDirectory': '/home/syt',
+ 'shadowFlag': '134538764',
+ 'uidNumber': '1004',
+ 'givenName': 'Sylvain',
+ 'telephoneNumber': '106',
+ 'displayName': 'sthenault',
+ 'gecos': 'Sylvain Thenault',
+ 'mail': ['sylvain.thenault@logilab.fr', 'syt@logilab.fr'],
+ 'userPassword': 'syt',
+ })
with self.repo.internal_cnx() as cnx:
self.pull(cnx)
with self.admin_access.repo_cnx() as cnx:
@@ -433,8 +445,7 @@
try:
self.update_ldap_entry('cn=logilab,ou=Group,dc=cubicweb,dc=test',
- {('add', 'memberUid'): ['syt']})
- time.sleep(1.1) # timestamps precision is 1s
+ {('add', 'memberUid'): ['syt']})
with self.repo.internal_cnx() as cnx:
self.pull(cnx)
@@ -452,7 +463,7 @@
def test_group_member_deleted(self):
with self.repo.internal_cnx() as cnx:
- self.pull(cnx) # ensure we are sync'ed
+ self.pull(cnx) # ensure we are sync'ed
with self.admin_access.repo_cnx() as cnx:
rset = cnx.execute('Any L WHERE U in_group G, G name %(name)s, U login L',
{'name': 'logilab'})
@@ -462,21 +473,19 @@
try:
self.update_ldap_entry('cn=logilab,ou=Group,dc=cubicweb,dc=test',
{('delete', 'memberUid'): ['adim']})
- time.sleep(1.1) # timestamps precision is 1s
with self.repo.internal_cnx() as cnx:
self.pull(cnx)
with self.admin_access.repo_cnx() as cnx:
rset = cnx.execute('Any L WHERE U in_group G, G name %(name)s, U login L',
{'name': 'logilab'})
- self.assertEqual(len(rset), 0)
+ self.assertEqual(len(rset), 0, rset.rows)
finally:
# back to normal ldap setup
self.tearDownClass()
self.setUpClass()
-
if __name__ == '__main__':
from logilab.common.testlib import unittest_main
unittest_main()
--- a/server/test/unittest_migractions.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/unittest_migractions.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,6 +22,7 @@
from contextlib import contextmanager
from logilab.common.testlib import unittest_main, Tags, tag
+from logilab.common import tempattr
from yams.constraints import UniqueConstraint
@@ -54,7 +55,8 @@
class MigrationConfig(cubicweb.devtools.TestServerConfiguration):
default_sources = cubicweb.devtools.DEFAULT_PSQL_SOURCES
- CUBES_PATH = [osp.join(HERE, 'data-migractions', 'cubes')]
+ CUBES_PATH = cubicweb.devtools.TestServerConfiguration.CUBES_PATH + [
+ osp.join(HERE, 'data-migractions', 'cubes')]
class MigrationTC(CubicWebTC):
@@ -151,7 +153,7 @@
orderdict2 = dict(mh.rqlexec('Any RTN, O WHERE X name "Note", RDEF from_entity X, '
'RDEF relation_type RT, RDEF ordernum O, RT name RTN'))
whateverorder = migrschema['whatever'].rdef('Note', 'Int').order
- for k, v in orderdict.iteritems():
+ for k, v in orderdict.items():
if v >= whateverorder:
orderdict[k] = v+1
orderdict['whatever'] = whateverorder
@@ -524,12 +526,12 @@
# remaining orphan rql expr which should be deleted at commit (composite relation)
# unattached expressions -> pending deletion on commit
self.assertEqual(cnx.execute('Any COUNT(X) WHERE X is RQLExpression, X exprtype "ERQLExpression",'
- 'NOT ET1 read_permission X, NOT ET2 add_permission X, '
- 'NOT ET3 delete_permission X, NOT ET4 update_permission X')[0][0],
+ 'NOT ET1 read_permission X, NOT ET2 add_permission X, '
+ 'NOT ET3 delete_permission X, NOT ET4 update_permission X')[0][0],
7)
self.assertEqual(cnx.execute('Any COUNT(X) WHERE X is RQLExpression, X exprtype "RRQLExpression",'
- 'NOT ET1 read_permission X, NOT ET2 add_permission X, '
- 'NOT ET3 delete_permission X, NOT ET4 update_permission X')[0][0],
+ 'NOT ET1 read_permission X, NOT ET2 add_permission X, '
+ 'NOT ET3 delete_permission X, NOT ET4 update_permission X')[0][0],
2)
# finally
self.assertEqual(cnx.execute('Any COUNT(X) WHERE X is RQLExpression')[0][0],
@@ -579,7 +581,7 @@
def test_add_drop_cube_and_deps(self):
with self.mh() as (cnx, mh):
schema = self.repo.schema
- self.assertEqual(sorted((str(s), str(o)) for s, o in schema['see_also'].rdefs.iterkeys()),
+ self.assertEqual(sorted((str(s), str(o)) for s, o in schema['see_also'].rdefs),
sorted([('EmailThread', 'EmailThread'), ('Folder', 'Folder'),
('Bookmark', 'Bookmark'), ('Bookmark', 'Note'),
('Note', 'Note'), ('Note', 'Bookmark')]))
@@ -593,7 +595,7 @@
for ertype in ('Email', 'EmailThread', 'EmailPart', 'File',
'sender', 'in_thread', 'reply_to', 'data_format'):
self.assertNotIn(ertype, schema)
- self.assertEqual(sorted(schema['see_also'].rdefs.iterkeys()),
+ self.assertEqual(sorted(schema['see_also'].rdefs),
sorted([('Folder', 'Folder'),
('Bookmark', 'Bookmark'),
('Bookmark', 'Note'),
@@ -612,12 +614,12 @@
for ertype in ('Email', 'EmailThread', 'EmailPart', 'File',
'sender', 'in_thread', 'reply_to', 'data_format'):
self.assertIn(ertype, schema)
- self.assertEqual(sorted(schema['see_also'].rdefs.iterkeys()),
- sorted([('EmailThread', 'EmailThread'), ('Folder', 'Folder'),
- ('Bookmark', 'Bookmark'),
- ('Bookmark', 'Note'),
- ('Note', 'Note'),
- ('Note', 'Bookmark')]))
+ self.assertEqual(sorted(schema['see_also'].rdefs),
+ sorted([('EmailThread', 'EmailThread'), ('Folder', 'Folder'),
+ ('Bookmark', 'Bookmark'),
+ ('Bookmark', 'Note'),
+ ('Note', 'Note'),
+ ('Note', 'Bookmark')]))
self.assertEqual(sorted(schema['see_also'].subjects()), ['Bookmark', 'EmailThread', 'Folder', 'Note'])
self.assertEqual(sorted(schema['see_also'].objects()), ['Bookmark', 'EmailThread', 'Folder', 'Note'])
from cubes.fakeemail.__pkginfo__ import version as email_version
@@ -719,6 +721,24 @@
self.assertEqual(tel, 1.0)
self.assertIsInstance(tel, float)
+ def test_drop_required_inlined_relation(self):
+ with self.mh() as (cnx, mh):
+ bob = mh.cmd_create_entity('Personne', nom=u'bob')
+ note = mh.cmd_create_entity('Note', ecrit_par=bob)
+ mh.commit()
+ rdef = mh.fs_schema.rschema('ecrit_par').rdefs[('Note', 'Personne')]
+ with tempattr(rdef, 'cardinality', '1*'):
+ mh.sync_schema_props_perms('ecrit_par', syncperms=False)
+ mh.cmd_drop_relation_type('ecrit_par')
+ self.assertNotIn('%secrit_par' % SQL_PREFIX,
+ self.table_schema(mh, '%sPersonne' % SQL_PREFIX))
+
+ def test_drop_inlined_rdef_delete_data(self):
+ with self.mh() as (cnx, mh):
+ note = mh.cmd_create_entity('Note', ecrit_par=cnx.user.eid)
+ mh.commit()
+ mh.drop_relation_definition('Note', 'ecrit_par', 'CWUser')
+ self.assertFalse(mh.sqlexec('SELECT * FROM cw_Note WHERE cw_ecrit_par IS NOT NULL'))
class MigrationCommandsComputedTC(MigrationTC):
""" Unit tests for computed relations and attributes
@@ -784,6 +804,20 @@
self.assertEqual(self.schema['whatever'].subjects(), ('Company',))
self.assertFalse(self.table_sql(mh, 'whatever_relation'))
+ def test_computed_relation_sync_schema_props_perms_security(self):
+ with self.mh() as (cnx, mh):
+ rdef = next(iter(self.schema['perm_changes'].rdefs.values()))
+ self.assertEqual(rdef.permissions,
+ {'add': (), 'delete': (),
+ 'read': ('managers', 'users')})
+ mh.cmd_sync_schema_props_perms('perm_changes')
+ self.assertEqual(self.schema['perm_changes'].permissions,
+ {'read': ('managers',)})
+ rdef = next(iter(self.schema['perm_changes'].rdefs.values()))
+ self.assertEqual(rdef.permissions,
+ {'add': (), 'delete': (),
+ 'read': ('managers',)})
+
def test_computed_relation_sync_schema_props_perms_on_rdef(self):
self.assertIn('whatever', self.schema)
with self.mh() as (cnx, mh):
--- a/server/test/unittest_postgres.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/unittest_postgres.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,8 +19,11 @@
from datetime import datetime
from threading import Thread
+from six.moves import range
+
from logilab.common.testlib import SkipTest
+import logilab.database as lgdb
from cubicweb import ValidationError
from cubicweb.devtools import PostgresApptestConfiguration, startpgcluster, stoppgcluster
from cubicweb.devtools.testlib import CubicWebTC
@@ -49,13 +52,21 @@
class PostgresFTITC(CubicWebTC):
configcls = PostgresTimeoutConfiguration
+ @classmethod
+ def setUpClass(cls):
+ cls.orig_connect_hooks = lgdb.SQL_CONNECT_HOOKS['postgres'][:]
+
+ @classmethod
+ def tearDownClass(cls):
+ lgdb.SQL_CONNECT_HOOKS['postgres'] = cls.orig_connect_hooks
+
def test_eid_range(self):
# concurrent allocation of eid ranges
source = self.session.repo.sources_by_uri['system']
range1 = []
range2 = []
def allocate_eid_ranges(session, target):
- for x in xrange(1, 10):
+ for x in range(1, 10):
eid = source.create_eid(session, count=x)
target.extend(range(eid-x, eid))
--- a/server/test/unittest_querier.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/unittest_querier.py Thu Dec 10 12:34:15 2015 +0100
@@ -21,6 +21,7 @@
from datetime import date, datetime, timedelta, tzinfo
+from six import PY2, integer_types, binary_type, text_type
from logilab.common.testlib import TestCase, unittest_main
from rql import BadRQLQuery, RQLSyntaxError
@@ -129,8 +130,8 @@
def assertRQLEqual(self, expected, got):
from rql import parse
- self.assertMultiLineEqual(unicode(parse(expected)),
- unicode(parse(got)))
+ self.assertMultiLineEqual(text_type(parse(expected)),
+ text_type(parse(got)))
def test_preprocess_security(self):
s = self.user_groups_session('users')
@@ -178,46 +179,46 @@
' Comment, Division, Email, EmailPart, EmailThread, ExternalUri, File, Folder, '
' Frozable, Note, Old, Personne, RQLExpression, Societe, State, SubDivision, '
' SubWorkflowExitPoint, Tag, TrInfo, Transition, Workflow, WorkflowTransition)')
- self.assertListEqual(sorted(solutions),
- sorted([{'X': 'BaseTransition', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'Bookmark', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'Card', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'Comment', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'Division', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'CWCache', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'CWComputedRType', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'CWConstraint', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'CWConstraintType', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'CWEType', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'CWAttribute', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'CWGroup', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'CWRelation', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'CWPermission', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'CWProperty', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'CWRType', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'CWSource', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'CWUniqueTogetherConstraint', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'CWUser', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'Email', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'EmailPart', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'EmailThread', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'ExternalUri', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'File', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'Folder', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'Frozable', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'Note', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'Old', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'Personne', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'RQLExpression', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'Societe', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'State', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'SubDivision', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'SubWorkflowExitPoint', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'Tag', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'Transition', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'TrInfo', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'Workflow', 'ETN': 'String', 'ET': 'CWEType'},
- {'X': 'WorkflowTransition', 'ETN': 'String', 'ET': 'CWEType'}]))
+ self.assertCountEqual(solutions,
+ [{'X': 'BaseTransition', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'Bookmark', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'Card', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'Comment', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'Division', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'CWCache', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'CWComputedRType', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'CWConstraint', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'CWConstraintType', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'CWEType', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'CWAttribute', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'CWGroup', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'CWRelation', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'CWPermission', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'CWProperty', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'CWRType', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'CWSource', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'CWUniqueTogetherConstraint', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'CWUser', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'Email', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'EmailPart', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'EmailThread', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'ExternalUri', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'File', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'Folder', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'Frozable', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'Note', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'Old', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'Personne', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'RQLExpression', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'Societe', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'State', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'SubDivision', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'SubWorkflowExitPoint', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'Tag', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'Transition', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'TrInfo', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'Workflow', 'ETN': 'String', 'ET': 'CWEType'},
+ {'X': 'WorkflowTransition', 'ETN': 'String', 'ET': 'CWEType'}])
rql, solutions = partrqls[2]
self.assertEqual(rql,
'Any ETN,X WHERE X is ET, ET name ETN, EXISTS(%(D)s use_email X), '
@@ -263,8 +264,9 @@
self.assertEqual(rset.description[0][0], 'Datetime')
rset = self.qexecute('Any %(x)s', {'x': 1})
self.assertEqual(rset.description[0][0], 'Int')
- rset = self.qexecute('Any %(x)s', {'x': 1L})
- self.assertEqual(rset.description[0][0], 'Int')
+ if PY2:
+ rset = self.qexecute('Any %(x)s', {'x': long(1)})
+ self.assertEqual(rset.description[0][0], 'Int')
rset = self.qexecute('Any %(x)s', {'x': True})
self.assertEqual(rset.description[0][0], 'Boolean')
rset = self.qexecute('Any %(x)s', {'x': 1.0})
@@ -307,10 +309,6 @@
setUpClass = classmethod(setUpClass)
tearDownClass = classmethod(tearDownClass)
- def test_encoding_pb(self):
- self.assertRaises(RQLSyntaxError, self.qexecute,
- 'Any X WHERE X is CWRType, X name "öwned_by"')
-
def test_unknown_eid(self):
# should return an empty result set
self.assertFalse(self.qexecute('Any X WHERE X eid 99999999'))
@@ -318,15 +316,15 @@
def test_typed_eid(self):
# should return an empty result set
rset = self.qexecute('Any X WHERE X eid %(x)s', {'x': '1'})
- self.assertIsInstance(rset[0][0], (int, long))
+ self.assertIsInstance(rset[0][0], integer_types)
def test_bytes_storage(self):
feid = self.qexecute('INSERT File X: X data_name "foo.pdf", '
'X data_format "text/plain", X data %(data)s',
- {'data': Binary("xxx")})[0][0]
+ {'data': Binary(b"xxx")})[0][0]
fdata = self.qexecute('Any D WHERE X data D, X eid %(x)s', {'x': feid})[0][0]
self.assertIsInstance(fdata, Binary)
- self.assertEqual(fdata.getvalue(), 'xxx')
+ self.assertEqual(fdata.getvalue(), b'xxx')
# selection queries tests #################################################
@@ -886,18 +884,18 @@
def test_select_constant(self):
rset = self.qexecute('Any X, "toto" ORDERBY X WHERE X is CWGroup')
self.assertEqual(rset.rows,
- map(list, zip((2,3,4,5), ('toto','toto','toto','toto',))))
- self.assertIsInstance(rset[0][1], unicode)
+ [list(x) for x in zip((2,3,4,5), ('toto','toto','toto','toto',))])
+ self.assertIsInstance(rset[0][1], text_type)
self.assertEqual(rset.description,
- zip(('CWGroup', 'CWGroup', 'CWGroup', 'CWGroup'),
- ('String', 'String', 'String', 'String',)))
+ list(zip(('CWGroup', 'CWGroup', 'CWGroup', 'CWGroup'),
+ ('String', 'String', 'String', 'String',))))
rset = self.qexecute('Any X, %(value)s ORDERBY X WHERE X is CWGroup', {'value': 'toto'})
self.assertEqual(rset.rows,
- map(list, zip((2,3,4,5), ('toto','toto','toto','toto',))))
- self.assertIsInstance(rset[0][1], unicode)
+ list(map(list, zip((2,3,4,5), ('toto','toto','toto','toto',)))))
+ self.assertIsInstance(rset[0][1], text_type)
self.assertEqual(rset.description,
- zip(('CWGroup', 'CWGroup', 'CWGroup', 'CWGroup'),
- ('String', 'String', 'String', 'String',)))
+ list(zip(('CWGroup', 'CWGroup', 'CWGroup', 'CWGroup'),
+ ('String', 'String', 'String', 'String',))))
rset = self.qexecute('Any X,GN WHERE X is CWUser, G is CWGroup, X login "syt", '
'X in_group G, G name GN')
@@ -1015,7 +1013,7 @@
self.assertEqual(len(rset.rows), 1)
self.assertEqual(rset.description, [('Personne',)])
rset = self.qexecute('Personne X WHERE X nom "bidule"')
- self.assert_(rset.rows)
+ self.assertTrue(rset.rows)
self.assertEqual(rset.description, [('Personne',)])
def test_insert_1_multiple(self):
@@ -1029,20 +1027,20 @@
rset = self.qexecute("INSERT Personne X, Personne Y: X nom 'bidule', Y nom 'tutu'")
self.assertEqual(rset.description, [('Personne', 'Personne')])
rset = self.qexecute('Personne X WHERE X nom "bidule" or X nom "tutu"')
- self.assert_(rset.rows)
+ self.assertTrue(rset.rows)
self.assertEqual(rset.description, [('Personne',), ('Personne',)])
def test_insert_3(self):
self.qexecute("INSERT Personne X: X nom Y WHERE U login 'admin', U login Y")
rset = self.qexecute('Personne X WHERE X nom "admin"')
- self.assert_(rset.rows)
+ self.assertTrue(rset.rows)
self.assertEqual(rset.description, [('Personne',)])
def test_insert_4(self):
self.qexecute("INSERT Societe Y: Y nom 'toto'")
self.qexecute("INSERT Personne X: X nom 'bidule', X travaille Y WHERE Y nom 'toto'")
rset = self.qexecute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y')
- self.assert_(rset.rows)
+ self.assertTrue(rset.rows)
self.assertEqual(rset.description, [('Personne', 'Societe',)])
def test_insert_4bis(self):
@@ -1057,17 +1055,17 @@
def test_insert_4ter(self):
peid = self.qexecute("INSERT Personne X: X nom 'bidule'")[0][0]
seid = self.qexecute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s",
- {'x': unicode(peid)})[0][0]
+ {'x': text_type(peid)})[0][0]
self.assertEqual(len(self.qexecute('Any X, Y WHERE X travaille Y')), 1)
self.qexecute("INSERT Personne X: X nom 'chouette', X travaille Y WHERE Y eid %(x)s",
- {'x': unicode(seid)})
+ {'x': text_type(seid)})
self.assertEqual(len(self.qexecute('Any X, Y WHERE X travaille Y')), 2)
def test_insert_5(self):
self.qexecute("INSERT Personne X: X nom 'bidule'")
self.qexecute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X nom 'bidule'")
rset = self.qexecute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y')
- self.assert_(rset.rows)
+ self.assertTrue(rset.rows)
self.assertEqual(rset.description, [('Personne', 'Societe',)])
def test_insert_5bis(self):
@@ -1075,20 +1073,20 @@
self.qexecute("INSERT Societe Y: Y nom 'toto', X travaille Y WHERE X eid %(x)s",
{'x': peid})
rset = self.qexecute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y')
- self.assert_(rset.rows)
+ self.assertTrue(rset.rows)
self.assertEqual(rset.description, [('Personne', 'Societe',)])
def test_insert_6(self):
self.qexecute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto', X travaille Y")
rset = self.qexecute('Any X, Y WHERE X nom "bidule", Y nom "toto", X travaille Y')
- self.assert_(rset.rows)
+ self.assertTrue(rset.rows)
self.assertEqual(rset.description, [('Personne', 'Societe',)])
def test_insert_7(self):
self.qexecute("INSERT Personne X, Societe Y: X nom N, Y nom 'toto', "
"X travaille Y WHERE U login 'admin', U login N")
rset = self.qexecute('Any X, Y WHERE X nom "admin", Y nom "toto", X travaille Y')
- self.assert_(rset.rows)
+ self.assertTrue(rset.rows)
self.assertEqual(rset.description, [('Personne', 'Societe',)])
def test_insert_7_2(self):
@@ -1103,7 +1101,7 @@
self.qexecute("INSERT Societe Y, Personne X: Y nom N, X nom 'toto', X travaille Y "
"WHERE U login 'admin', U login N")
rset = self.qexecute('Any X, Y WHERE X nom "toto", Y nom "admin", X travaille Y')
- self.assert_(rset.rows)
+ self.assertTrue(rset.rows)
self.assertEqual(rset.description, [('Personne', 'Societe',)])
def test_insert_9(self):
@@ -1267,7 +1265,7 @@
rset = self.qexecute("INSERT Personne X, Societe Y: X nom 'bidule', Y nom 'toto'")
eid1, eid2 = rset[0][0], rset[0][1]
self.qexecute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s",
- {'x': unicode(eid1), 'y': unicode(eid2)})
+ {'x': text_type(eid1), 'y': text_type(eid2)})
rset = self.qexecute('Any X, Y WHERE X travaille Y')
self.assertEqual(len(rset.rows), 1)
@@ -1317,7 +1315,7 @@
eid1, eid2 = rset[0][0], rset[0][1]
rset = self.qexecute("SET X travaille Y WHERE X eid %(x)s, Y eid %(y)s, "
"NOT EXISTS(Z ecrit_par X)",
- {'x': unicode(eid1), 'y': unicode(eid2)})
+ {'x': text_type(eid1), 'y': text_type(eid2)})
self.assertEqual(tuplify(rset.rows), [(eid1, eid2)])
def test_update_query_error(self):
@@ -1364,7 +1362,7 @@
cursor = cnx.cnxset.cu
cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'"
% (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX))
- passwd = str(cursor.fetchone()[0])
+ passwd = binary_type(cursor.fetchone()[0])
self.assertEqual(passwd, crypt_password('toto', passwd))
rset = self.qexecute("Any X WHERE X is CWUser, X login 'bob', X upassword %(pwd)s",
{'pwd': Binary(passwd)})
@@ -1377,11 +1375,11 @@
{'pwd': 'toto'})
self.assertEqual(rset.description[0][0], 'CWUser')
rset = cnx.execute("SET X upassword %(pwd)s WHERE X is CWUser, X login 'bob'",
- {'pwd': 'tutu'})
+ {'pwd': b'tutu'})
cursor = cnx.cnxset.cu
cursor.execute("SELECT %supassword from %sCWUser WHERE %slogin='bob'"
% (SQL_PREFIX, SQL_PREFIX, SQL_PREFIX))
- passwd = str(cursor.fetchone()[0])
+ passwd = binary_type(cursor.fetchone()[0])
self.assertEqual(passwd, crypt_password('tutu', passwd))
rset = cnx.execute("Any X WHERE X is CWUser, X login 'bob', X upassword %(pwd)s",
{'pwd': Binary(passwd)})
--- a/server/test/unittest_repository.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/unittest_repository.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,6 +22,8 @@
import time
import logging
+from six.moves import range
+
from yams.constraints import UniqueConstraint
from yams import register_base_type, unregister_base_type
@@ -77,7 +79,7 @@
def test_connect(self):
cnxid = self.repo.connect(self.admlogin, password=self.admpassword)
- self.assert_(cnxid)
+ self.assertTrue(cnxid)
self.repo.close(cnxid)
self.assertRaises(AuthenticationError,
self.repo.connect, self.admlogin, password='nimportnawak')
@@ -100,7 +102,7 @@
cnx.commit()
repo = self.repo
cnxid = repo.connect(u"barnabé", password=u"héhéhé".encode('UTF8'))
- self.assert_(cnxid)
+ self.assertTrue(cnxid)
repo.close(cnxid)
def test_rollback_on_execute_validation_error(self):
@@ -145,7 +147,7 @@
def test_close(self):
repo = self.repo
cnxid = repo.connect(self.admlogin, password=self.admpassword)
- self.assert_(cnxid)
+ self.assertTrue(cnxid)
repo.close(cnxid)
def test_check_session(self):
@@ -192,7 +194,7 @@
constraints = schema.rschema('relation_type').rdef('CWAttribute', 'CWRType').constraints
self.assertEqual(len(constraints), 1)
cstr = constraints[0]
- self.assert_(isinstance(cstr, RQLConstraint))
+ self.assertIsInstance(cstr, RQLConstraint)
self.assertEqual(cstr.expression, 'O final TRUE')
ownedby = schema.rschema('owned_by')
@@ -589,11 +591,11 @@
with self.admin_access.repo_cnx() as cnx:
personnes = []
t0 = time.time()
- for i in xrange(2000):
+ for i in range(2000):
p = cnx.create_entity('Personne', nom=u'Doe%03d'%i, prenom=u'John', sexe=u'M')
personnes.append(p)
abraham = cnx.create_entity('Personne', nom=u'Abraham', prenom=u'John', sexe=u'M')
- for j in xrange(0, 2000, 100):
+ for j in range(0, 2000, 100):
abraham.cw_set(personne_composite=personnes[j:j+100])
t1 = time.time()
self.info('creation: %.2gs', (t1 - t0))
@@ -610,7 +612,7 @@
def test_add_relation_non_inlined(self):
with self.admin_access.repo_cnx() as cnx:
personnes = []
- for i in xrange(2000):
+ for i in range(2000):
p = cnx.create_entity('Personne', nom=u'Doe%03d'%i, prenom=u'John', sexe=u'M')
personnes.append(p)
cnx.commit()
@@ -619,7 +621,7 @@
personne_composite=personnes[:100])
t1 = time.time()
self.info('creation: %.2gs', (t1 - t0))
- for j in xrange(100, 2000, 100):
+ for j in range(100, 2000, 100):
abraham.cw_set(personne_composite=personnes[j:j+100])
t2 = time.time()
self.info('more relations: %.2gs', (t2-t1))
@@ -630,7 +632,7 @@
def test_add_relation_inlined(self):
with self.admin_access.repo_cnx() as cnx:
personnes = []
- for i in xrange(2000):
+ for i in range(2000):
p = cnx.create_entity('Personne', nom=u'Doe%03d'%i, prenom=u'John', sexe=u'M')
personnes.append(p)
cnx.commit()
@@ -639,7 +641,7 @@
personne_inlined=personnes[:100])
t1 = time.time()
self.info('creation: %.2gs', (t1 - t0))
- for j in xrange(100, 2000, 100):
+ for j in range(100, 2000, 100):
abraham.cw_set(personne_inlined=personnes[j:j+100])
t2 = time.time()
self.info('more relations: %.2gs', (t2-t1))
@@ -652,7 +654,7 @@
""" to be compared with test_session_add_relations"""
with self.admin_access.repo_cnx() as cnx:
personnes = []
- for i in xrange(2000):
+ for i in range(2000):
p = cnx.create_entity('Personne', nom=u'Doe%03d'%i, prenom=u'John', sexe=u'M')
personnes.append(p)
abraham = cnx.create_entity('Personne', nom=u'Abraham', prenom=u'John', sexe=u'M')
@@ -669,7 +671,7 @@
""" to be compared with test_session_add_relation"""
with self.admin_access.repo_cnx() as cnx:
personnes = []
- for i in xrange(2000):
+ for i in range(2000):
p = cnx.create_entity('Personne', nom=u'Doe%03d'%i, prenom=u'John', sexe=u'M')
personnes.append(p)
abraham = cnx.create_entity('Personne', nom=u'Abraham', prenom=u'John', sexe=u'M')
@@ -686,7 +688,7 @@
""" to be compared with test_session_add_relations"""
with self.admin_access.repo_cnx() as cnx:
personnes = []
- for i in xrange(2000):
+ for i in range(2000):
p = cnx.create_entity('Personne', nom=u'Doe%03d'%i, prenom=u'John', sexe=u'M')
personnes.append(p)
abraham = cnx.create_entity('Personne', nom=u'Abraham', prenom=u'John', sexe=u'M')
@@ -703,7 +705,7 @@
""" to be compared with test_session_add_relation"""
with self.admin_access.repo_cnx() as cnx:
personnes = []
- for i in xrange(2000):
+ for i in range(2000):
p = cnx.create_entity('Personne', nom=u'Doe%03d'%i, prenom=u'John', sexe=u'M')
personnes.append(p)
abraham = cnx.create_entity('Personne', nom=u'Abraham', prenom=u'John', sexe=u'M')
--- a/server/test/unittest_rql2sql.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/unittest_rql2sql.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""unit tests for module cubicweb.server.sources.rql2sql"""
+from __future__ import print_function
import sys
import os
@@ -1246,13 +1247,13 @@
except Exception as ex:
if 'r' in locals():
try:
- print (r%args).strip()
+ print((r%args).strip())
except KeyError:
- print 'strange, missing substitution'
- print r, nargs
- print '!='
- print sql.strip()
- print 'RQL:', rql
+ print('strange, missing substitution')
+ print(r, nargs)
+ print('!=')
+ print(sql.strip())
+ print('RQL:', rql)
raise
def _parse(self, rqls):
@@ -1269,11 +1270,11 @@
r, args, cbs = self.o.generate(rqlst, args)
self.assertEqual((r.strip(), args), sql)
except Exception as ex:
- print rql
+ print(rql)
if 'r' in locals():
- print r.strip()
- print '!='
- print sql[0].strip()
+ print(r.strip())
+ print('!=')
+ print(sql[0].strip())
raise
return
--- a/server/test/unittest_rqlannotation.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/unittest_rqlannotation.py Thu Dec 10 12:34:15 2015 +0100
@@ -64,7 +64,7 @@
rqlst = self._prepare(cnx, 'Any A,B,C WHERE A eid 12,A comment B, '
'A ?wf_info_for C')
self.assertEqual(rqlst.defined_vars['A']._q_invariant, False)
- self.assert_(rqlst.defined_vars['B'].stinfo['attrvar'])
+ self.assertTrue(rqlst.defined_vars['B'].stinfo['attrvar'])
self.assertEqual(rqlst.defined_vars['C']._q_invariant, False)
self.assertEqual(rqlst.solutions, [{'A': 'TrInfo', 'B': 'String', 'C': 'Affaire'},
{'A': 'TrInfo', 'B': 'String', 'C': 'CWUser'},
@@ -87,7 +87,7 @@
'Y nom NX, X eid XE, not Y eid XE')
self.assertEqual(rqlst.defined_vars['X']._q_invariant, False)
self.assertEqual(rqlst.defined_vars['Y']._q_invariant, False)
- self.assert_(rqlst.defined_vars['XE'].stinfo['attrvar'])
+ self.assertTrue(rqlst.defined_vars['XE'].stinfo['attrvar'])
def test_0_8(self):
with self.session.new_cnx() as cnx:
--- a/server/test/unittest_schemaserial.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/unittest_schemaserial.py Thu Dec 10 12:34:15 2015 +0100
@@ -292,7 +292,7 @@
{'cardinality': u'?1',
'defaultval': None,
'description': u'',
- 'extra_props': '{"jungle_speed": 42}',
+ 'extra_props': b'{"jungle_speed": 42}',
'formula': None,
'indexed': False,
'oe': None,
--- a/server/test/unittest_security.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/unittest_security.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,6 +17,8 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""functional tests for server'security"""
+from six.moves import range
+
from logilab.common.testlib import unittest_main
from cubicweb.devtools.testlib import CubicWebTC
@@ -33,7 +35,7 @@
with self.admin_access.client_cnx() as cnx:
self.create_user(cnx, u'iaminusersgrouponly')
hash = _CRYPTO_CTX.encrypt('oldpassword', scheme='des_crypt')
- self.create_user(cnx, u'oldpassword', password=Binary(hash))
+ self.create_user(cnx, u'oldpassword', password=Binary(hash.encode('ascii')))
class LowLevelSecurityFunctionTC(BaseSecurityTC):
@@ -79,17 +81,20 @@
it will be updated on next login
"""
with self.repo.internal_cnx() as cnx:
- oldhash = str(cnx.system_sql("SELECT cw_upassword FROM cw_CWUser "
- "WHERE cw_login = 'oldpassword'").fetchone()[0])
+ oldhash = cnx.system_sql("SELECT cw_upassword FROM cw_CWUser "
+ "WHERE cw_login = 'oldpassword'").fetchone()[0]
+ oldhash = self.repo.system_source.binary_to_str(oldhash)
self.repo.close(self.repo.connect('oldpassword', password='oldpassword'))
- newhash = str(cnx.system_sql("SELECT cw_upassword FROM cw_CWUser "
- "WHERE cw_login = 'oldpassword'").fetchone()[0])
+ newhash = cnx.system_sql("SELECT cw_upassword FROM cw_CWUser "
+ "WHERE cw_login = 'oldpassword'").fetchone()[0]
+ newhash = self.repo.system_source.binary_to_str(newhash)
self.assertNotEqual(oldhash, newhash)
- self.assertTrue(newhash.startswith('$6$'))
+ self.assertTrue(newhash.startswith(b'$6$'))
self.repo.close(self.repo.connect('oldpassword', password='oldpassword'))
- self.assertEqual(newhash,
- str(cnx.system_sql("SELECT cw_upassword FROM cw_CWUser WHERE "
- "cw_login = 'oldpassword'").fetchone()[0]))
+ newnewhash = cnx.system_sql("SELECT cw_upassword FROM cw_CWUser WHERE "
+ "cw_login = 'oldpassword'").fetchone()[0]
+ newnewhash = self.repo.system_source.binary_to_str(newnewhash)
+ self.assertEqual(newhash, newnewhash)
class SecurityRewritingTC(BaseSecurityTC):
@@ -293,7 +298,7 @@
ueid = self.create_user(cnx, u'user').eid
with self.new_access(u'user').repo_cnx() as cnx:
cnx.execute('SET X upassword %(passwd)s WHERE X eid %(x)s',
- {'x': ueid, 'passwd': 'newpwd'})
+ {'x': ueid, 'passwd': b'newpwd'})
cnx.commit()
self.repo.close(self.repo.connect('user', password='newpwd'))
@@ -302,7 +307,7 @@
ueid = self.create_user(cnx, u'otheruser').eid
with self.new_access(u'iaminusersgrouponly').repo_cnx() as cnx:
cnx.execute('SET X upassword %(passwd)s WHERE X eid %(x)s',
- {'x': ueid, 'passwd': 'newpwd'})
+ {'x': ueid, 'passwd': b'newpwd'})
self.assertRaises(Unauthorized, cnx.commit)
# read security test
@@ -559,7 +564,7 @@
rset = cnx.execute('CWUser X')
self.assertEqual([[anon.eid]], rset.rows)
# anonymous user can read groups (necessary to check allowed transitions for instance)
- self.assert_(cnx.execute('CWGroup X'))
+ self.assertTrue(cnx.execute('CWGroup X'))
# should only be able to read the anonymous user, not another one
self.assertRaises(Unauthorized,
cnx.execute, 'CWUser X WHERE X eid %(x)s', {'x': admineid})
@@ -666,7 +671,7 @@
rset = cnx.execute('Any X, U WHERE X is EmailAddress, U use_email X')
msg = ['Preexisting email readable by anon found!']
tmpl = ' - "%s" used by user "%s"'
- for i in xrange(len(rset)):
+ for i in range(len(rset)):
email, user = rset.get_entity(i, 0), rset.get_entity(i, 1)
msg.append(tmpl % (email.dc_title(), user.dc_title()))
raise RuntimeError('\n'.join(msg))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/server/test/unittest_serverctl.py Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,26 @@
+import os.path as osp
+import shutil
+
+from cubicweb.devtools import testlib, ApptestConfiguration
+from cubicweb.server.serverctl import _local_dump, DBDumpCommand
+from cubicweb.server.serverconfig import ServerConfiguration
+
+class ServerCTLTC(testlib.CubicWebTC):
+ def setUp(self):
+ super(ServerCTLTC, self).setUp()
+ self.orig_config_for = ServerConfiguration.config_for
+ config_for = lambda appid: ApptestConfiguration(appid, apphome=self.datadir)
+ ServerConfiguration.config_for = staticmethod(config_for)
+
+ def tearDown(self):
+ ServerConfiguration.config_for = self.orig_config_for
+ super(ServerCTLTC, self).tearDown()
+
+ def test_dump(self):
+ DBDumpCommand(None).run([self.appid])
+ shutil.rmtree(osp.join(self.config.apphome, 'backup'))
+
+
+if __name__ == '__main__':
+ from unittest import main
+ main()
--- a/server/test/unittest_storage.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/unittest_storage.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,12 +17,15 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""unit tests for module cubicweb.server.sources.storages"""
+from six import PY2
+
from logilab.common.testlib import unittest_main, tag, Tags
from cubicweb.devtools.testlib import CubicWebTC
from glob import glob
import os
import os.path as osp
+import sys
import shutil
import tempfile
@@ -57,24 +60,26 @@
def setup_database(self):
self.tempdir = tempfile.mkdtemp()
bfs_storage = storages.BytesFileSystemStorage(self.tempdir)
+ self.bfs_storage = bfs_storage
storages.set_attribute_storage(self.repo, 'File', 'data', bfs_storage)
storages.set_attribute_storage(self.repo, 'BFSSTestable', 'opt_attr', bfs_storage)
def tearDown(self):
super(StorageTC, self).tearDown()
storages.unset_attribute_storage(self.repo, 'File', 'data')
+ del self.bfs_storage
shutil.rmtree(self.tempdir)
- def create_file(self, cnx, content='the-data'):
+ def create_file(self, cnx, content=b'the-data'):
return cnx.create_entity('File', data=Binary(content),
data_format=u'text/plain',
data_name=u'foo.pdf')
def fspath(self, cnx, entity):
fspath = cnx.execute('Any fspath(D) WHERE F eid %(f)s, F data D',
- {'f': entity.eid})[0][0]
- return fspath.getvalue()
+ {'f': entity.eid})[0][0].getvalue()
+ return fspath if PY2 else fspath.decode('utf-8')
def test_bfss_wrong_fspath_usage(self):
with self.admin_access.repo_cnx() as cnx:
@@ -109,7 +114,7 @@
# add f1 back to the entity cache with req as _cw
f1 = req.entity_from_eid(f1.eid)
- f1.cw_set(data=Binary('the new data'))
+ f1.cw_set(data=Binary(b'the new data'))
cnx.rollback()
self.assertEqual(open(expected_filepath).read(), 'the-data')
f1.cw_delete()
@@ -132,7 +137,7 @@
with self.admin_access.repo_cnx() as cnx:
cnx.transaction_data['fs_importing'] = True
filepath = osp.abspath(__file__)
- f1 = cnx.create_entity('File', data=Binary(filepath),
+ f1 = cnx.create_entity('File', data=Binary(filepath.encode(sys.getfilesystemencoding())),
data_format=u'text/plain', data_name=u'foo')
self.assertEqual(self.fspath(cnx, f1), filepath)
@@ -185,8 +190,8 @@
self.assertEqual(len(rset), 2)
self.assertEqual(rset[0][0], f1.eid)
self.assertEqual(rset[1][0], f1.eid)
- self.assertEqual(rset[0][1].getvalue(), 'the-data')
- self.assertEqual(rset[1][1].getvalue(), 'the-data')
+ self.assertEqual(rset[0][1].getvalue(), b'the-data')
+ self.assertEqual(rset[1][1].getvalue(), b'the-data')
rset = cnx.execute('Any X,LENGTH(D) WHERE X eid %(x)s, X data D',
{'x': f1.eid})
self.assertEqual(len(rset), 1)
@@ -212,31 +217,31 @@
with self.admin_access.repo_cnx() as cnx:
cnx.transaction_data['fs_importing'] = True
filepath = osp.abspath(__file__)
- f1 = cnx.create_entity('File', data=Binary(filepath),
+ f1 = cnx.create_entity('File', data=Binary(filepath.encode(sys.getfilesystemencoding())),
data_format=u'text/plain', data_name=u'foo')
cw_value = f1.data.getvalue()
- fs_value = file(filepath).read()
+ fs_value = open(filepath, 'rb').read()
if cw_value != fs_value:
self.fail('cw value %r is different from file content' % cw_value)
@tag('update')
def test_bfss_update_with_existing_data(self):
with self.admin_access.repo_cnx() as cnx:
- f1 = cnx.create_entity('File', data=Binary('some data'),
+ f1 = cnx.create_entity('File', data=Binary(b'some data'),
data_format=u'text/plain', data_name=u'foo')
# NOTE: do not use cw_set() which would automatically
# update f1's local dict. We want the pure rql version to work
cnx.execute('SET F data %(d)s WHERE F eid %(f)s',
- {'d': Binary('some other data'), 'f': f1.eid})
- self.assertEqual(f1.data.getvalue(), 'some other data')
+ {'d': Binary(b'some other data'), 'f': f1.eid})
+ self.assertEqual(f1.data.getvalue(), b'some other data')
cnx.commit()
f2 = cnx.execute('Any F WHERE F eid %(f)s, F is File', {'f': f1.eid}).get_entity(0, 0)
- self.assertEqual(f2.data.getvalue(), 'some other data')
+ self.assertEqual(f2.data.getvalue(), b'some other data')
@tag('update', 'extension', 'commit')
def test_bfss_update_with_different_extension_commited(self):
with self.admin_access.repo_cnx() as cnx:
- f1 = cnx.create_entity('File', data=Binary('some data'),
+ f1 = cnx.create_entity('File', data=Binary(b'some data'),
data_format=u'text/plain', data_name=u'foo.txt')
# NOTE: do not use cw_set() which would automatically
# update f1's local dict. We want the pure rql version to work
@@ -246,7 +251,7 @@
self.assertEqual(osp.splitext(old_path)[1], '.txt')
cnx.execute('SET F data %(d)s, F data_name %(dn)s, '
'F data_format %(df)s WHERE F eid %(f)s',
- {'d': Binary('some other data'), 'f': f1.eid,
+ {'d': Binary(b'some other data'), 'f': f1.eid,
'dn': u'bar.jpg', 'df': u'image/jpeg'})
cnx.commit()
# the new file exists with correct extension
@@ -260,7 +265,7 @@
@tag('update', 'extension', 'rollback')
def test_bfss_update_with_different_extension_rolled_back(self):
with self.admin_access.repo_cnx() as cnx:
- f1 = cnx.create_entity('File', data=Binary('some data'),
+ f1 = cnx.create_entity('File', data=Binary(b'some data'),
data_format=u'text/plain', data_name=u'foo.txt')
# NOTE: do not use cw_set() which would automatically
# update f1's local dict. We want the pure rql version to work
@@ -271,7 +276,7 @@
self.assertEqual(osp.splitext(old_path)[1], '.txt')
cnx.execute('SET F data %(d)s, F data_name %(dn)s, '
'F data_format %(df)s WHERE F eid %(f)s',
- {'d': Binary('some other data'),
+ {'d': Binary(b'some other data'),
'f': f1.eid,
'dn': u'bar.jpg',
'df': u'image/jpeg'})
@@ -290,7 +295,7 @@
@tag('update', 'NULL')
def test_bfss_update_to_None(self):
with self.admin_access.repo_cnx() as cnx:
- f = cnx.create_entity('Affaire', opt_attr=Binary('toto'))
+ f = cnx.create_entity('Affaire', opt_attr=Binary(b'toto'))
cnx.commit()
f.cw_set(opt_attr=None)
cnx.commit()
@@ -298,17 +303,17 @@
@tag('fs_importing', 'update')
def test_bfss_update_with_fs_importing(self):
with self.admin_access.repo_cnx() as cnx:
- f1 = cnx.create_entity('File', data=Binary('some data'),
+ f1 = cnx.create_entity('File', data=Binary(b'some data'),
data_format=u'text/plain',
data_name=u'foo')
old_fspath = self.fspath(cnx, f1)
cnx.transaction_data['fs_importing'] = True
new_fspath = osp.join(self.tempdir, 'newfile.txt')
- file(new_fspath, 'w').write('the new data')
+ open(new_fspath, 'w').write('the new data')
cnx.execute('SET F data %(d)s WHERE F eid %(f)s',
- {'d': Binary(new_fspath), 'f': f1.eid})
+ {'d': Binary(new_fspath.encode(sys.getfilesystemencoding())), 'f': f1.eid})
cnx.commit()
- self.assertEqual(f1.data.getvalue(), 'the new data')
+ self.assertEqual(f1.data.getvalue(), b'the new data')
self.assertEqual(self.fspath(cnx, f1), new_fspath)
self.assertFalse(osp.isfile(old_fspath))
--- a/server/test/unittest_undo.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/unittest_undo.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,6 +17,8 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+from six import text_type
+
from cubicweb import ValidationError
from cubicweb.devtools.testlib import CubicWebTC
import cubicweb.server.session
@@ -255,7 +257,7 @@
"%s doesn't exist anymore." % g.eid])
with self.assertRaises(ValidationError) as cm:
cnx.commit()
- cm.exception.translate(unicode)
+ cm.exception.translate(text_type)
self.assertEqual(cm.exception.entity, self.totoeid)
self.assertEqual(cm.exception.errors,
{'in_group-subject': u'at least one relation in_group is '
@@ -461,7 +463,7 @@
# problem occurs in string manipulation for python < 2.6
def test___unicode__method(self):
u = _UndoException(u"voilà ")
- self.assertIsInstance(unicode(u), unicode)
+ self.assertIsInstance(text_type(u), text_type)
if __name__ == '__main__':
--- a/server/test/unittest_utils.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/test/unittest_utils.py Thu Dec 10 12:34:15 2015 +0100
@@ -26,13 +26,13 @@
def test_crypt(self):
for hash in (
utils.crypt_password('xxx'), # default sha512
- 'ab$5UsKFxRKKN.d8iBIFBnQ80', # custom md5
- 'ab4Vlm81ZUHlg', # DES
+ b'ab$5UsKFxRKKN.d8iBIFBnQ80', # custom md5
+ b'ab4Vlm81ZUHlg', # DES
):
self.assertEqual(utils.crypt_password('xxx', hash), hash)
self.assertEqual(utils.crypt_password(u'xxx', hash), hash)
- self.assertEqual(utils.crypt_password(u'xxx', unicode(hash)), hash)
- self.assertEqual(utils.crypt_password('yyy', hash), '')
+ self.assertEqual(utils.crypt_password(u'xxx', hash.decode('ascii')), hash.decode('ascii'))
+ self.assertEqual(utils.crypt_password('yyy', hash), b'')
# accept any password for empty hashes (is it a good idea?)
self.assertEqual(utils.crypt_password('xxx', ''), '')
--- a/server/utils.py Wed Dec 09 18:42:13 2015 +0100
+++ b/server/utils.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""Some utilities for the CubicWeb server."""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
@@ -24,6 +25,9 @@
from threading import Timer, Thread
from getpass import getpass
+from six import PY2, text_type
+from six.moves import input
+
from passlib.utils import handlers as uh, to_hash_str
from passlib.context import CryptContext
@@ -60,7 +64,7 @@
"""return the encrypted password using the given salt or a generated one
"""
if salt is None:
- return _CRYPTO_CTX.encrypt(passwd)
+ return _CRYPTO_CTX.encrypt(passwd).encode('ascii')
# empty hash, accept any password for backwards compat
if salt == '':
return salt
@@ -70,7 +74,7 @@
except ValueError: # e.g. couldn't identify hash
pass
# wrong password
- return ''
+ return b''
def eschema_eid(cnx, eschema):
@@ -81,7 +85,7 @@
if eschema.eid is None:
eschema.eid = cnx.execute(
'Any X WHERE X is CWEType, X name %(name)s',
- {'name': unicode(eschema)})[0][0]
+ {'name': text_type(eschema)})[0][0]
return eschema.eid
@@ -92,17 +96,18 @@
passwdmsg='password'):
if not user:
if msg:
- print msg
+ print(msg)
while not user:
- user = raw_input('login: ')
- user = unicode(user, sys.stdin.encoding)
+ user = input('login: ')
+ if PY2:
+ user = unicode(user, sys.stdin.encoding)
passwd = getpass('%s: ' % passwdmsg)
if confirm:
while True:
passwd2 = getpass('confirm password: ')
if passwd == passwd2:
break
- print 'password doesn\'t match'
+ print('password doesn\'t match')
passwd = getpass('password: ')
# XXX decode password using stdin encoding then encode it using appl'encoding
return user, passwd
@@ -236,4 +241,3 @@
from logging import getLogger
from cubicweb import set_log_methods
set_log_methods(TasksManager, getLogger('cubicweb.repository'))
-
--- a/setup.py Wed Dec 09 18:42:13 2015 +0100
+++ b/setup.py Thu Dec 10 12:34:15 2015 +0100
@@ -42,7 +42,7 @@
from __pkginfo__ import modname, version, license, description, web, \
author, author_email
-long_description = file('README').read()
+long_description = open('README').read()
# import optional features
import __pkginfo__
@@ -51,7 +51,7 @@
for entry in ("__depends__",): # "__recommends__"):
requires.update(getattr(__pkginfo__, entry, {}))
install_requires = [("%s %s" % (d, v and v or "")).strip()
- for d, v in requires.iteritems()]
+ for d, v in requires.items()]
else:
install_requires = []
--- a/skeleton/DISTNAME.spec.tmpl Wed Dec 09 18:42:13 2015 +0100
+++ b/skeleton/DISTNAME.spec.tmpl Thu Dec 10 12:34:15 2015 +0100
@@ -21,6 +21,7 @@
BuildRequires: %%{python} %%{python}-setuptools
Requires: cubicweb >= %(version)s
+Requires: %{python}-six >= 1.4.0
%%description
%(longdesc)s
--- a/skeleton/debian/control.tmpl Wed Dec 09 18:42:13 2015 +0100
+++ b/skeleton/debian/control.tmpl Thu Dec 10 12:34:15 2015 +0100
@@ -12,6 +12,7 @@
Architecture: all
Depends:
cubicweb-common (>= %(version)s),
+ python-six (>= 1.4.0),
${python:Depends},
${misc:Depends},
Description: %(shortdesc)s
--- a/skeleton/debian/rules Wed Dec 09 18:42:13 2015 +0100
+++ b/skeleton/debian/rules Thu Dec 10 12:34:15 2015 +0100
@@ -5,10 +5,5 @@
%:
dh $@ --with python2
-override_dh_auto_install:
- dh_auto_install
- # remove generated .egg-info file
- rm -rf debian/*/usr/lib/python*
-
override_dh_python2:
dh_python2 -i /usr/share/cubicweb
--- a/skeleton/setup.py Wed Dec 09 18:42:13 2015 +0100
+++ b/skeleton/setup.py Thu Dec 10 12:34:15 2015 +0100
@@ -4,7 +4,7 @@
# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
-# This file is part of CubicWeb tag cube.
+# This file is part of CubicWeb.
#
# CubicWeb is free software: you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free
@@ -44,7 +44,7 @@
author, author_email, classifiers
if exists('README'):
- long_description = file('README').read()
+ long_description = open('README').read()
else:
long_description = ''
@@ -55,7 +55,7 @@
for entry in ("__depends__",): # "__recommends__"):
requires.update(getattr(__pkginfo__, entry, {}))
install_requires = [("%s %s" % (d, v and v or "")).strip()
- for d, v in requires.iteritems()]
+ for d, v in requires.items()]
else:
install_requires = []
--- a/sobjects/__init__.py Wed Dec 09 18:42:13 2015 +0100
+++ b/sobjects/__init__.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,11 +20,11 @@
import os.path as osp
def registration_callback(vreg):
- vreg.register_all(globals().itervalues(), __name__)
+ vreg.register_all(globals().values(), __name__)
global URL_MAPPING
URL_MAPPING = {}
if vreg.config.apphome:
url_mapping_file = osp.join(vreg.config.apphome, 'urlmapping.py')
if osp.exists(url_mapping_file):
- URL_MAPPING = eval(file(url_mapping_file).read())
+ URL_MAPPING = eval(open(url_mapping_file).read())
vreg.info('using url mapping %s from %s', URL_MAPPING, url_mapping_file)
--- a/sobjects/cwxmlparser.py Wed Dec 09 18:42:13 2015 +0100
+++ b/sobjects/cwxmlparser.py Thu Dec 10 12:34:15 2015 +0100
@@ -32,9 +32,11 @@
"""
from datetime import datetime, time
-import urlparse
import urllib
+from six import text_type
+from six.moves.urllib.parse import urlparse, urlunparse, parse_qs, urlencode
+
from logilab.common.date import todate, totime
from logilab.common.textutils import splitstrip, text_to_dict
from logilab.common.decorators import classproperty
@@ -50,7 +52,7 @@
# XXX see cubicweb.cwvreg.YAMS_TO_PY
# XXX see cubicweb.web.views.xmlrss.SERIALIZERS
DEFAULT_CONVERTERS = BASE_CONVERTERS.copy()
-DEFAULT_CONVERTERS['String'] = unicode
+DEFAULT_CONVERTERS['String'] = text_type
DEFAULT_CONVERTERS['Password'] = lambda x: x.encode('utf8')
def convert_date(ustr):
return todate(datetime.strptime(ustr, '%Y-%m-%d'))
@@ -124,7 +126,7 @@
def list_actions(self):
reg = self._cw.vreg['components']
- return sorted(clss[0].action for rid, clss in reg.iteritems()
+ return sorted(clss[0].action for rid, clss in reg.items()
if rid.startswith('cw.entityxml.action.'))
# mapping handling #########################################################
@@ -204,7 +206,7 @@
* `rels` is for relations and structured as
{role: {relation: [(related item, related rels)...]}
"""
- entity = self.extid2entity(str(item['cwuri']), item['cwtype'],
+ entity = self.extid2entity(item['cwuri'].encode('ascii'), item['cwtype'],
cwsource=item['cwsource'], item=item,
raise_on_error=raise_on_error)
if entity is None:
@@ -220,7 +222,7 @@
def process_relations(self, entity, rels):
etype = entity.cw_etype
- for (rtype, role, action), rules in self.source.mapping.get(etype, {}).iteritems():
+ for (rtype, role, action), rules in self.source.mapping.get(etype, {}).items():
try:
related_items = rels[role][rtype]
except KeyError:
@@ -242,14 +244,14 @@
def normalize_url(self, url):
"""overridden to add vid=xml if vid is not set in the qs"""
url = super(CWEntityXMLParser, self).normalize_url(url)
- purl = urlparse.urlparse(url)
+ purl = urlparse(url)
if purl.scheme in ('http', 'https'):
- params = urlparse.parse_qs(purl.query)
+ params = parse_qs(purl.query)
if 'vid' not in params:
params['vid'] = ['xml']
purl = list(purl)
- purl[4] = urllib.urlencode(params, doseq=True)
- return urlparse.urlunparse(purl)
+ purl[4] = urlencode(params, doseq=True)
+ return urlunparse(purl)
return url
def complete_url(self, url, etype=None, known_relations=None):
@@ -263,8 +265,8 @@
If `known_relations` is given, it should be a dictionary of already
known relations, so they don't get queried again.
"""
- purl = urlparse.urlparse(url)
- params = urlparse.parse_qs(purl.query)
+ purl = urlparse(url)
+ params = parse_qs(purl.query)
if etype is None:
etype = purl.path.split('/')[-1]
try:
@@ -277,8 +279,8 @@
continue
relations.add('%s-%s' % (rtype, role))
purl = list(purl)
- purl[4] = urllib.urlencode(params, doseq=True)
- return urlparse.urlunparse(purl)
+ purl[4] = urlencode(params, doseq=True)
+ return urlunparse(purl)
def complete_item(self, item, rels):
try:
@@ -314,7 +316,7 @@
"""
node = self.node
item = dict(node.attrib.items())
- item['cwtype'] = unicode(node.tag)
+ item['cwtype'] = text_type(node.tag)
item.setdefault('cwsource', None)
try:
item['eid'] = int(item['eid'])
@@ -331,7 +333,7 @@
related += self.parser.parse_etree(child)
elif child.text:
# attribute
- item[child.tag] = unicode(child.text)
+ item[child.tag] = text_type(child.text)
else:
# None attribute (empty tag)
item[child.tag] = None
--- a/sobjects/ldapparser.py Wed Dec 09 18:42:13 2015 +0100
+++ b/sobjects/ldapparser.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,4 +1,4 @@
-# copyright 2011-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2011-2015 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -20,12 +20,28 @@
unlike ldapuser source, this source is copy based and will import ldap content
(beside passwords for authentication) into the system source.
"""
+from six.moves import map, filter
+
from logilab.common.decorators import cached, cachedproperty
from logilab.common.shellutils import generate_password
from cubicweb import Binary, ConfigurationError
from cubicweb.server.utils import crypt_password
from cubicweb.server.sources import datafeed
+from cubicweb.dataimport import stores, importer
+
+
+class UserMetaGenerator(stores.MetaGenerator):
+ """Specific metadata generator, used to see newly created user into their initial state.
+ """
+ @cached
+ def base_etype_dicts(self, entity):
+ entity, rels = super(UserMetaGenerator, self).base_etype_dicts(entity)
+ if entity.cw_etype == 'CWUser':
+ wf_state = self._cnx.execute('Any S WHERE ET default_workflow WF, ET name %(etype)s, '
+ 'WF initial_state S', {'etype': entity.cw_etype}).one()
+ rels['in_state'] = wf_state.eid
+ return entity, rels
class DataFeedLDAPAdapter(datafeed.DataFeedParser):
@@ -48,8 +64,8 @@
def user_source_entities_by_extid(self):
source = self.source
if source.user_base_dn.strip():
- attrs = map(str, source.user_attrs.keys())
- return dict((userdict['dn'], userdict)
+ attrs = list(map(str, source.user_attrs.keys()))
+ return dict((userdict['dn'].encode('ascii'), userdict)
for userdict in source._search(self._cw,
source.user_base_dn,
source.user_base_scope,
@@ -61,7 +77,7 @@
def group_source_entities_by_extid(self):
source = self.source
if source.group_base_dn.strip():
- attrs = map(str, ['modifyTimestamp'] + source.group_attrs.keys())
+ attrs = list(map(str, ['modifyTimestamp'] + list(source.group_attrs.keys())))
return dict((groupdict['dn'], groupdict)
for groupdict in source._search(self._cw,
source.group_base_dn,
@@ -70,171 +86,170 @@
attrs))
return {}
- def _process(self, etype, sdict, raise_on_error=False):
- self.debug('fetched %s %s', etype, sdict)
- extid = sdict['dn']
- entity = self.extid2entity(extid, etype,
- raise_on_error=raise_on_error, **sdict)
- if entity is not None and not self.created_during_pull(entity):
- self.notify_updated(entity)
- attrs = self.ldap2cwattrs(sdict, etype)
- self.update_if_necessary(entity, attrs)
- if etype == 'CWUser':
- self._process_email(entity, sdict)
- if etype == 'CWGroup':
- self._process_membership(entity, sdict)
-
def process(self, url, raise_on_error=False):
"""IDataFeedParser main entry point"""
self.debug('processing ldapfeed source %s %s', self.source, self.searchfilterstr)
- for userdict in self.user_source_entities_by_extid.itervalues():
- self._process('CWUser', userdict)
+ self._group_members = {}
+ eeimporter = self.build_importer(raise_on_error)
+ for name in self.source.user_default_groups:
+ geid = self._get_group(name)
+ eeimporter.extid2eid[geid] = geid
+ entities = self.extentities_generator()
+ set_cwuri = importer.use_extid_as_cwuri(eeimporter.extid2eid)
+ eeimporter.import_entities(set_cwuri(entities))
+ self.stats['created'] = eeimporter.created
+ self.stats['updated'] = eeimporter.updated
+ # handle in_group relation
+ for group, members in self._group_members.items():
+ self._cw.execute('DELETE U in_group G WHERE G name %(g)s', {'g': group})
+ if members:
+ members = ["'%s'" % e for e in members]
+ rql = 'SET U in_group G WHERE G name %%(g)s, U login IN (%s)' % ','.join(members)
+ self._cw.execute(rql, {'g': group})
+ # ensure updated users are activated
+ for eid in eeimporter.updated:
+ entity = self._cw.entity_from_eid(eid)
+ if entity.cw_etype == 'CWUser':
+ self.ensure_activated(entity)
+ # manually set primary email if necessary, it's not handled automatically since hooks are
+ # deactivated
+ self._cw.execute('SET X primary_email E WHERE NOT X primary_email E, X use_email E, '
+ 'X cw_source S, S eid %(s)s, X in_state ST, TS name "activated"',
+ {'s': self.source.eid})
+
+ def build_importer(self, raise_on_error):
+ """Instantiate and configure an importer"""
+ etypes = ('CWUser', 'EmailAddress', 'CWGroup')
+ extid2eid = importer.cwuri2eid(self._cw, etypes, source_eid=self.source.eid)
+ existing_relations = {}
+ for rtype in ('in_group', 'use_email', 'owned_by'):
+ rql = 'Any S,O WHERE S {} O, S cw_source SO, SO eid %(s)s'.format(rtype)
+ rset = self._cw.execute(rql, {'s': self.source.eid})
+ existing_relations[rtype] = set(tuple(x) for x in rset)
+ return importer.ExtEntitiesImporter(self._cw.vreg.schema, self.build_store(),
+ extid2eid=extid2eid,
+ existing_relations=existing_relations,
+ etypes_order_hint=etypes,
+ import_log=self.import_log,
+ raise_on_error=raise_on_error)
+
+ def build_store(self):
+ """Instantiate and configure a store"""
+ metagenerator = UserMetaGenerator(self._cw, source=self.source)
+ return stores.NoHookRQLObjectStore(self._cw, metagenerator)
+
+ def extentities_generator(self):
self.debug('processing ldapfeed source %s %s', self.source, self.searchgroupfilterstr)
- for groupdict in self.group_source_entities_by_extid.itervalues():
- self._process('CWGroup', groupdict, raise_on_error=raise_on_error)
+ # generate users and email addresses
+ for userdict in self.user_source_entities_by_extid.values():
+ attrs = self.ldap2cwattrs(userdict, 'CWUser')
+ pwd = attrs.get('upassword')
+ if not pwd:
+ # generate a dumb password if not fetched from ldap (see
+ # userPassword)
+ pwd = crypt_password(generate_password())
+ attrs['upassword'] = set([Binary(pwd)])
+ extuser = importer.ExtEntity('CWUser', userdict['dn'], attrs)
+ extuser.values['owned_by'] = set([extuser.extid])
+ for extemail in self._process_email(extuser, userdict):
+ yield extemail
+ groups = list(filter(None, [self._get_group(name)
+ for name in self.source.user_default_groups]))
+ if groups:
+ extuser.values['in_group'] = groups
+ yield extuser
+ # generate groups
+ for groupdict in self.group_source_entities_by_extid.values():
+ attrs = self.ldap2cwattrs(groupdict, 'CWGroup')
+ extgroup = importer.ExtEntity('CWGroup', groupdict['dn'], attrs)
+ yield extgroup
+ # record group membership for later insertion
+ members = groupdict.get(self.source.group_rev_attrs['member'], ())
+ self._group_members[attrs['name']] = members
+
+ def _process_email(self, extuser, userdict):
+ try:
+ emailaddrs = userdict.pop(self.source.user_rev_attrs['email'])
+ except KeyError:
+ return # no email for that user, nothing to do
+ if not isinstance(emailaddrs, list):
+ emailaddrs = [emailaddrs]
+ for emailaddr in emailaddrs:
+ # search for existing email first, may be coming from another source
+ rset = self._cw.execute('EmailAddress X WHERE X address %(addr)s',
+ {'addr': emailaddr})
+ if not rset:
+ # not found, create it. first forge an external id
+ emailextid = userdict['dn'] + '@@' + emailaddr
+ extuser.values.setdefault('use_email', []).append(emailextid)
+ yield importer.ExtEntity('EmailAddress', emailextid, dict(address=[emailaddr]))
+ elif self.sourceuris:
+ # pop from sourceuris anyway, else email may be removed by the
+ # source once import is finished
+ emailextid = userdict['dn'] + '@@' + emailaddr
+ self.sourceuris.pop(emailextid, None)
+ # XXX else check use_email relation?
def handle_deletion(self, config, cnx, myuris):
if config['delete-entities']:
super(DataFeedLDAPAdapter, self).handle_deletion(config, cnx, myuris)
return
if myuris:
- byetype = {}
- for extid, (eid, etype) in myuris.iteritems():
- if self.is_deleted(extid, etype, eid):
- byetype.setdefault(etype, []).append(str(eid))
-
- for etype, eids in byetype.iteritems():
- if etype != 'CWUser':
+ for extid, (eid, etype) in myuris.items():
+ if etype != 'CWUser' or not self.is_deleted(extid, etype, eid):
continue
- self.info('deactivate %s %s entities', len(eids), etype)
- for eid in eids:
- wf = cnx.entity_from_eid(eid).cw_adapt_to('IWorkflowable')
- wf.fire_transition_if_possible('deactivate')
+ self.info('deactivate user %s', eid)
+ wf = cnx.entity_from_eid(eid).cw_adapt_to('IWorkflowable')
+ wf.fire_transition_if_possible('deactivate')
cnx.commit()
- def update_if_necessary(self, entity, attrs):
- # disable read security to allow password selection
- with entity._cw.security_enabled(read=False):
- entity.complete(tuple(attrs))
+ def ensure_activated(self, entity):
if entity.cw_etype == 'CWUser':
wf = entity.cw_adapt_to('IWorkflowable')
if wf.state == 'deactivated':
wf.fire_transition('activate')
self.info('user %s reactivated', entity.login)
- mdate = attrs.get('modification_date')
- if not mdate or mdate > entity.modification_date:
- attrs = dict( (k, v) for k, v in attrs.iteritems()
- if v != getattr(entity, k))
- if attrs:
- entity.cw_set(**attrs)
- self.notify_updated(entity)
+
+ def ldap2cwattrs(self, sdict, etype):
+ """Transform dictionary of LDAP attributes to CW.
- def ldap2cwattrs(self, sdict, etype, tdict=None):
- """ Transform dictionary of LDAP attributes to CW
- etype must be CWUser or CWGroup """
- if tdict is None:
- tdict = {}
+ etype must be CWUser or CWGroup
+ """
+ assert etype in ('CWUser', 'CWGroup'), etype
+ tdict = {}
if etype == 'CWUser':
- items = self.source.user_attrs.iteritems()
+ items = self.source.user_attrs.items()
elif etype == 'CWGroup':
- items = self.source.group_attrs.iteritems()
+ items = self.source.group_attrs.items()
for sattr, tattr in items:
if tattr not in self.non_attribute_keys:
try:
- tdict[tattr] = sdict[sattr]
+ value = sdict[sattr]
except KeyError:
- raise ConfigurationError('source attribute %s has not '
- 'been found in the source, '
- 'please check the %s-attrs-map '
- 'field and the permissions of '
- 'the LDAP binding user' %
- (sattr, etype[2:].lower()))
+ raise ConfigurationError(
+ 'source attribute %s has not been found in the source, '
+ 'please check the %s-attrs-map field and the permissions of '
+ 'the LDAP binding user' % (sattr, etype[2:].lower()))
+ if not isinstance(value, list):
+ value = [value]
+ tdict[tattr] = value
return tdict
- def before_entity_copy(self, entity, sourceparams):
- etype = entity.cw_etype
- if etype == 'EmailAddress':
- entity.cw_edited['address'] = sourceparams['address']
- else:
- self.ldap2cwattrs(sourceparams, etype, tdict=entity.cw_edited)
- if etype == 'CWUser':
- pwd = entity.cw_edited.get('upassword')
- if not pwd:
- # generate a dumb password if not fetched from ldap (see
- # userPassword)
- pwd = crypt_password(generate_password())
- entity.cw_edited['upassword'] = Binary(pwd)
- return entity
-
- def after_entity_copy(self, entity, sourceparams):
- super(DataFeedLDAPAdapter, self).after_entity_copy(entity, sourceparams)
- etype = entity.cw_etype
- if etype == 'EmailAddress':
- return
- # all CWUsers must be treated before CWGroups to have the in_group relation
- # set correctly in _associate_ldapusers
- elif etype == 'CWUser':
- groups = filter(None, [self._get_group(name)
- for name in self.source.user_default_groups])
- if groups:
- entity.cw_set(in_group=groups)
- self._process_email(entity, sourceparams)
- elif etype == 'CWGroup':
- self._process_membership(entity, sourceparams)
-
def is_deleted(self, extidplus, etype, eid):
try:
- extid, _ = extidplus.rsplit('@@', 1)
+ extid = extidplus.rsplit(b'@@', 1)[0]
except ValueError:
# for some reason extids here tend to come in both forms, e.g:
# dn, dn@@Babar
extid = extidplus
return extid not in self.user_source_entities_by_extid
- def _process_email(self, entity, userdict):
- try:
- emailaddrs = userdict[self.source.user_rev_attrs['email']]
- except KeyError:
- return # no email for that user, nothing to do
- if not isinstance(emailaddrs, list):
- emailaddrs = [emailaddrs]
- for emailaddr in emailaddrs:
- # search for existing email first, may be coming from another source
- rset = self._cw.execute('EmailAddress X WHERE X address %(addr)s',
- {'addr': emailaddr})
- if not rset:
- # not found, create it. first forge an external id
- emailextid = userdict['dn'] + '@@' + emailaddr.encode('utf-8')
- email = self.extid2entity(emailextid, 'EmailAddress',
- address=emailaddr)
- entity.cw_set(use_email=email)
- elif self.sourceuris:
- # pop from sourceuris anyway, else email may be removed by the
- # source once import is finished
- uri = userdict['dn'] + '@@' + emailaddr.encode('utf-8')
- self.sourceuris.pop(uri, None)
- # XXX else check use_email relation?
-
- def _process_membership(self, entity, sourceparams):
- """ Find existing CWUsers with the same login as the memberUids in the
- CWGroup entity and create the in_group relationship """
- mdate = sourceparams.get('modification_date')
- if (not mdate or mdate > entity.modification_date):
- self._cw.execute('DELETE U in_group G WHERE G eid %(g)s',
- {'g':entity.eid})
- members = sourceparams.get(self.source.group_rev_attrs['member'])
- if members:
- members = ["'%s'" % e for e in members]
- rql = 'SET U in_group G WHERE G eid %%(g)s, U login IN (%s)' % ','.join(members)
- self._cw.execute(rql, {'g':entity.eid, })
-
@cached
def _get_group(self, name):
try:
return self._cw.execute('Any X WHERE X is CWGroup, X name %(name)s',
- {'name': name}).get_entity(0, 0)
+ {'name': name})[0][0]
except IndexError:
self.error('group %r referenced by source configuration %r does not exist',
name, self.source.uri)
return None
-
--- a/sobjects/notification.py Wed Dec 09 18:42:13 2015 +0100
+++ b/sobjects/notification.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,10 +18,12 @@
"""some views to handle notification on data changes"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from itertools import repeat
+from six import text_type
+
from logilab.common.textutils import normalize_text
from logilab.common.deprecation import class_renamed, class_moved, deprecated
from logilab.common.registry import yes
@@ -181,8 +183,8 @@
def context(self, **kwargs):
entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0)
- for key, val in kwargs.iteritems():
- if val and isinstance(val, unicode) and val.strip():
+ for key, val in kwargs.items():
+ if val and isinstance(val, text_type) and val.strip():
kwargs[key] = self._cw._(val)
kwargs.update({'user': self.user_data['login'],
'eid': entity.eid,
@@ -255,7 +257,7 @@
def format_value(value):
- if isinstance(value, unicode):
+ if isinstance(value, text_type):
return u'"%s"' % value
return value
--- a/sobjects/services.py Wed Dec 09 18:42:13 2015 +0100
+++ b/sobjects/services.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,7 +19,10 @@
import threading
+from six import text_type
+
from yams.schema import role_name
+
from cubicweb import ValidationError
from cubicweb.server import Service
from cubicweb.predicates import match_user_groups, match_kwargs
@@ -58,6 +61,7 @@
results['threads'] = [t.name for t in threading.enumerate()]
return results
+
class GcStatsService(Service):
"""Return a dictionary containing some statistics about the repository
resources usage.
@@ -94,9 +98,9 @@
results = {}
counters, ocounters, garbage = gc_info(lookupclasses,
viewreferrersclasses=())
- values = sorted(counters.iteritems(), key=lambda x: x[1], reverse=True)
+ values = sorted(counters.items(), key=lambda x: x[1], reverse=True)
results['lookupclasses'] = values
- values = sorted(ocounters.iteritems(), key=lambda x: x[1], reverse=True)[:nmax]
+ values = sorted(ocounters.items(), key=lambda x: x[1], reverse=True)[:nmax]
results['referenced'] = values
results['unreachable'] = garbage
return results
@@ -129,7 +133,7 @@
qname = role_name('login', 'subject')
raise ValidationError(None, {qname: errmsg % login})
- if isinstance(password, unicode):
+ if isinstance(password, text_type):
# password should *always* be utf8 encoded
password = password.encode('UTF8')
cwuserkwargs['login'] = login
@@ -154,3 +158,17 @@
'WHERE U login %(login)s', d, build_descr=False)
return user
+
+
+class SourceSynchronizationService(Service):
+ """Force synchronization of a datafeed source"""
+ __regid__ = 'source-sync'
+ __select__ = Service.__select__ & match_user_groups('managers')
+
+ def call(self, source_eid):
+ source_entity = self._cw.entity_from_eid(source_eid)
+ repo = self._cw.repo # Service are repo side only.
+ with repo.internal_cnx() as cnx:
+ source = repo.sources_by_uri[source_entity.name]
+ source.pull_data(cnx)
+
--- a/sobjects/supervising.py Wed Dec 09 18:42:13 2015 +0100
+++ b/sobjects/supervising.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""some hooks and views to handle supervising of any data changes"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from cubicweb import UnknownEid
from cubicweb.predicates import none_rset
@@ -128,13 +128,15 @@
# XXX print changes
self.w(u' %s' % changedescr.entity.absolute_url())
- def delete_entity(self, (eid, etype, title)):
+ def delete_entity(self, args):
+ eid, etype, title = args
msg = self._cw._('deleted %(etype)s #%(eid)s (%(title)s)')
etype = display_name(self._cw, etype).lower()
self.w(msg % locals())
- def change_state(self, (entity, fromstate, tostate)):
+ def change_state(self, args):
_ = self._cw._
+ entity, fromstate, tostate = args
msg = _('changed state of %(etype)s #%(eid)s (%(title)s)')
self.w(u'%s\n' % (msg % self._entity_context(entity)))
self.w(_(' from state %(fromstate)s to state %(tostate)s\n' %
--- a/sobjects/test/unittest_cwxmlparser.py Wed Dec 09 18:42:13 2015 +0100
+++ b/sobjects/test/unittest_cwxmlparser.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,7 +17,8 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
from datetime import datetime
-from urlparse import urlsplit, parse_qsl
+
+from six.moves.urllib.parse import urlsplit, parse_qsl
from cubicweb.devtools.testlib import CubicWebTC
from cubicweb.sobjects.cwxmlparser import CWEntityXMLParser
@@ -214,8 +215,8 @@
with self.admin_access.web_request() as req:
user = req.execute('CWUser X WHERE X login "sthenault"').get_entity(0, 0)
- self.assertEqual(user.creation_date, datetime(2010, 01, 22, 10, 27, 59))
- self.assertEqual(user.modification_date, datetime(2011, 01, 25, 14, 14, 06))
+ self.assertEqual(user.creation_date, datetime(2010, 1, 22, 10, 27, 59))
+ self.assertEqual(user.modification_date, datetime(2011, 1, 25, 14, 14, 6))
self.assertEqual(user.cwuri, 'http://pouet.org/5')
self.assertEqual(user.cw_source[0].name, 'myfeed')
self.assertEqual(user.absolute_url(), 'http://pouet.org/5')
@@ -299,8 +300,8 @@
with self.repo.internal_cnx() as cnx:
stats = dfsource.pull_data(cnx, force=True, raise_on_error=True)
user = cnx.execute('CWUser X WHERE X login "sthenault"').get_entity(0, 0)
- self.assertEqual(user.creation_date, datetime(2010, 01, 22, 10, 27, 59))
- self.assertEqual(user.modification_date, datetime(2011, 01, 25, 14, 14, 06))
+ self.assertEqual(user.creation_date, datetime(2010, 1, 22, 10, 27, 59))
+ self.assertEqual(user.modification_date, datetime(2011, 1, 25, 14, 14, 6))
self.assertEqual(user.cwuri, 'http://pouet.org/5')
self.assertEqual(user.cw_source[0].name, 'myfeed')
--- a/sobjects/test/unittest_supervising.py Wed Dec 09 18:42:13 2015 +0100
+++ b/sobjects/test/unittest_supervising.py Thu Dec 10 12:34:15 2015 +0100
@@ -77,7 +77,7 @@
# check prepared email
op._prepare_email()
self.assertEqual(len(op.to_send), 1)
- self.assert_(op.to_send[0][0])
+ self.assertTrue(op.to_send[0][0])
self.assertEqual(op.to_send[0][1], ['test@logilab.fr'])
cnx.commit()
# some other changes #######
--- a/spa2rql.py Wed Dec 09 18:42:13 2015 +0100
+++ b/spa2rql.py Thu Dec 10 12:34:15 2015 +0100
@@ -146,9 +146,9 @@
def finalize(self):
"""return corresponding rql query (string) / args (dict)"""
- for varname, ptypes in self.possible_types.iteritems():
+ for varname, ptypes in self.possible_types.items():
if len(ptypes) == 1:
- self.restrictions.append('%s is %s' % (varname, iter(ptypes).next()))
+ self.restrictions.append('%s is %s' % (varname, next(iter(ptypes))))
unions = []
for releq, subjvar, obj in self.union_params:
thisunions = []
--- a/tags.py Wed Dec 09 18:42:13 2015 +0100
+++ b/tags.py Thu Dec 10 12:34:15 2015 +0100
@@ -59,4 +59,3 @@
html += options
html.append(u'</select>')
return u'\n'.join(html)
-
--- a/test/data/cubes/file/__pkginfo__.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/data/cubes/file/__pkginfo__.py Thu Dec 10 12:34:15 2015 +0100
@@ -23,4 +23,3 @@
numversion = (1, 4, 3)
version = '.'.join(str(num) for num in numversion)
-
--- a/test/data/rqlexpr_on_computedrel.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/data/rqlexpr_on_computedrel.py Thu Dec 10 12:34:15 2015 +0100
@@ -14,5 +14,3 @@
class computed(ComputedRelation):
rule = 'S relation O'
__permissions__ = {'read': (RRQLExpression('S is ET'),)}
-
-
--- a/test/data/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/data/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -23,7 +23,7 @@
RQLConstraint, RQLVocabularyConstraint)
-_ = unicode
+from cubicweb import _
class Personne(EntityType):
--- a/test/data_schemareader/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/data_schemareader/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -7,5 +7,3 @@
cw_for_source.__permissions__ = {'read': ('managers', 'users'),
'add': ('managers',),
'delete': ('managers',)}
-
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/unittest_binary.py Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,54 @@
+from six import PY2
+
+from unittest import TestCase
+from tempfile import NamedTemporaryFile
+import os.path as osp
+
+from logilab.common.shellutils import tempdir
+from cubicweb import Binary
+
+
+class BinaryTC(TestCase):
+ def test_init(self):
+ Binary()
+ Binary(b'toto')
+ Binary(bytearray(b'toto'))
+ if PY2:
+ Binary(buffer('toto'))
+ else:
+ Binary(memoryview(b'toto'))
+ with self.assertRaises((AssertionError, TypeError)):
+ # TypeError is raised by BytesIO if python runs with -O
+ Binary(u'toto')
+
+ def test_write(self):
+ b = Binary()
+ b.write(b'toto')
+ b.write(bytearray(b'toto'))
+ if PY2:
+ b.write(buffer('toto'))
+ else:
+ b.write(memoryview(b'toto'))
+ with self.assertRaises((AssertionError, TypeError)):
+ # TypeError is raised by BytesIO if python runs with -O
+ b.write(u'toto')
+
+ def test_gzpickle_roundtrip(self):
+ old = (u'foo', b'bar', 42, {})
+ new = Binary.zpickle(old).unzpickle()
+ self.assertEqual(old, new)
+ self.assertIsNot(old, new)
+
+ def test_from_file_to_file(self):
+ with tempdir() as dpath:
+ fpath = osp.join(dpath, 'binary.bin')
+ with open(fpath, 'wb') as fobj:
+ Binary(b'binaryblob').to_file(fobj)
+
+ bobj = Binary.from_file(fpath)
+ self.assertEqual(bobj.getvalue(), b'binaryblob')
+
+
+if __name__ == '__main__':
+ from unittest import main
+ main()
--- a/test/unittest_cwconfig.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/unittest_cwconfig.py Thu Dec 10 12:34:15 2015 +0100
@@ -86,15 +86,6 @@
finally:
comment_pkginfo.__recommends_cubes__ = {}
-
-# def test_vc_config(self):
-# vcconf = self.config.vc_config()
-# self.assertIsInstance(vcconf['EEMAIL'], Version)
-# self.assertEqual(vcconf['EEMAIL'], (0, 3, 1))
-# self.assertEqual(vcconf['CW'], (2, 31, 2))
-# self.assertRaises(KeyError, vcconf.__getitem__, 'CW_VERSION')
-# self.assertRaises(KeyError, vcconf.__getitem__, 'CRM')
-
def test_expand_cubes(self):
self.config.__class__.CUBES_PATH = [CUSTOM_CUBES_DIR]
self.config.adjust_sys_path()
--- a/test/unittest_cwctl.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/unittest_cwctl.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,10 @@
import sys
import os
from os.path import join
-from cStringIO import StringIO
+from io import StringIO, BytesIO
+
+from six import PY2
+
from logilab.common.testlib import TestCase, unittest_main
from cubicweb.cwconfig import CubicWebConfiguration
@@ -30,7 +33,7 @@
class CubicWebCtlTC(TestCase):
def setUp(self):
- self.stream = StringIO()
+ self.stream = BytesIO() if PY2 else StringIO()
sys.stdout = self.stream
def tearDown(self):
sys.stdout = sys.__stdout__
@@ -57,7 +60,7 @@
funcname=None)
for script, args in scripts.items():
scriptname = os.path.join(self.datadir, 'scripts', script)
- self.assert_(os.path.exists(scriptname))
+ self.assertTrue(os.path.exists(scriptname))
mih.cmd_process_script(scriptname, None, scriptargs=args)
--- a/test/unittest_entity.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/unittest_entity.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,6 +20,8 @@
from datetime import datetime
+from six import text_type
+
from logilab.common import tempattr
from logilab.common.decorators import clear_cache
@@ -644,7 +646,7 @@
def test_printable_value_bytes(self):
with self.admin_access.web_request() as req:
- e = req.create_entity('FakeFile', data=Binary('lambda x: 1'), data_format=u'text/x-python',
+ e = req.create_entity('FakeFile', data=Binary(b'lambda x: 1'), data_format=u'text/x-python',
data_encoding=u'ascii', data_name=u'toto.py')
from cubicweb import mttransforms
if mttransforms.HAS_PYGMENTS_TRANSFORMS:
@@ -663,8 +665,10 @@
<span style="color: #C00000;">lambda</span> <span style="color: #000000;">x</span><span style="color: #0000C0;">:</span> <span style="color: #0080C0;">1</span>
</pre>''')
- e = req.create_entity('FakeFile', data=Binary('*héhéhé*'), data_format=u'text/rest',
- data_encoding=u'utf-8', data_name=u'toto.txt')
+ e = req.create_entity('FakeFile',
+ data=Binary(u'*héhéhé*'.encode('utf-8')),
+ data_format=u'text/rest',
+ data_encoding=u'utf-8', data_name=u'toto.txt')
self.assertEqual(e.printable_value('data'),
u'<p><em>héhéhé</em></p>')
@@ -717,7 +721,7 @@
e = self.vreg['etypes'].etype_class('FakeFile')(req)
e.cw_attr_cache['description'] = 'du <em>html</em>'
e.cw_attr_cache['description_format'] = 'text/html'
- e.cw_attr_cache['data'] = Binary('some <em>data</em>')
+ e.cw_attr_cache['data'] = Binary(b'some <em>data</em>')
e.cw_attr_cache['data_name'] = 'an html file'
e.cw_attr_cache['data_format'] = 'text/html'
e.cw_attr_cache['data_encoding'] = 'ascii'
@@ -769,11 +773,11 @@
# ambiguity test
person2 = req.create_entity('Personne', prenom=u'remi', nom=u'doe')
person.cw_clear_all_caches()
- self.assertEqual(person.rest_path(), unicode(person.eid))
- self.assertEqual(person2.rest_path(), unicode(person2.eid))
+ self.assertEqual(person.rest_path(), text_type(person.eid))
+ self.assertEqual(person2.rest_path(), text_type(person2.eid))
# unique attr with None value (nom in this case)
friend = req.create_entity('Ami', prenom=u'bob')
- self.assertEqual(friend.rest_path(), unicode(friend.eid))
+ self.assertEqual(friend.rest_path(), text_type(friend.eid))
# 'ref' below is created without the unique but not required
# attribute, make sur that the unique _and_ required 'ean' is used
# as the rest attribute
@@ -853,4 +857,3 @@
if __name__ == '__main__':
from logilab.common.testlib import unittest_main
unittest_main()
-
--- a/test/unittest_mail.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/unittest_mail.py Thu Dec 10 12:34:15 2015 +0100
@@ -149,4 +149,3 @@
if __name__ == '__main__':
unittest_main()
-
--- a/test/unittest_migration.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/unittest_migration.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,4 +1,4 @@
-# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2014 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -22,7 +22,7 @@
from cubicweb.devtools import TestServerConfiguration
from cubicweb.cwconfig import CubicWebConfiguration
-from cubicweb.migration import MigrationHelper, filter_scripts
+from cubicweb.migration import MigrationHelper, filter_scripts, version_strictly_lower
from cubicweb.server.migractions import ServerMigrationHelper
@@ -76,8 +76,6 @@
def test_filter_scripts_for_mode(self):
config = CubicWebConfiguration('data')
config.verbosity = 0
- self.assertNotIsInstance(config.migration_handler(), ServerMigrationHelper)
- self.assertIsInstance(config.migration_handler(), MigrationHelper)
config = self.config
config.__class__.name = 'repository'
self.assertListEqual(filter_scripts(config, TMIGRDIR, (0,0,4), (0,1,0)),
@@ -91,6 +89,10 @@
((0, 1 ,0), TMIGRDIR+'0.1.0_repository.py')])
config.__class__.name = 'repository'
+ def test_version_strictly_lower(self):
+ self.assertTrue(version_strictly_lower(None, '1.0.0'))
+ self.assertFalse(version_strictly_lower('1.0.0', None))
+
from cubicweb.devtools import ApptestConfiguration, get_test_db_handler
--- a/test/unittest_predicates.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/unittest_predicates.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,14 +20,17 @@
from operator import eq, lt, le, gt
from contextlib import contextmanager
+from six.moves import range
+
from logilab.common.testlib import TestCase, unittest_main
from logilab.common.decorators import clear_cache
from cubicweb import Binary
from cubicweb.devtools.testlib import CubicWebTC
from cubicweb.predicates import (is_instance, adaptable, match_kwargs, match_user_groups,
- multi_lines_rset, score_entity, is_in_state,
- rql_condition, relation_possible, match_form_params)
+ multi_lines_rset, score_entity, is_in_state,
+ rql_condition, relation_possible, match_form_params,
+ paginated_rset)
from cubicweb.selectors import on_transition # XXX on_transition is deprecated
from cubicweb.view import EntityAdapter
from cubicweb.web import action
@@ -37,7 +40,7 @@
class ImplementsTC(CubicWebTC):
def test_etype_priority(self):
with self.admin_access.web_request() as req:
- f = req.create_entity('FakeFile', data_name=u'hop.txt', data=Binary('hop'),
+ f = req.create_entity('FakeFile', data_name=u'hop.txt', data=Binary(b'hop'),
data_format=u'text/plain')
rset = f.as_rset()
anyscore = is_instance('Any')(f.__class__, req, rset=rset)
@@ -488,6 +491,34 @@
"match_form_params() positional arguments must be strings")
+class PaginatedTC(CubicWebTC):
+ """tests for paginated_rset predicate"""
+
+ def setup_database(self):
+ with self.admin_access.repo_cnx() as cnx:
+ for i in range(30):
+ cnx.create_entity('CWGroup', name=u"group%d" % i)
+ cnx.commit()
+
+ def test_paginated_rset(self):
+ default_nb_pages = 1
+ web_request = self.admin_access.web_request
+ with web_request() as req:
+ rset = req.execute('Any G WHERE G is CWGroup')
+ self.assertEqual(len(rset), 34)
+ with web_request(vid='list', page_size='10') as req:
+ self.assertEqual(paginated_rset()(None, req, rset), default_nb_pages)
+ with web_request(vid='list', page_size='20') as req:
+ self.assertEqual(paginated_rset()(None, req, rset), default_nb_pages)
+ with web_request(vid='list', page_size='50') as req:
+ self.assertEqual(paginated_rset()(None, req, rset), 0)
+ with web_request(vid='list', page_size='10/') as req:
+ self.assertEqual(paginated_rset()(None, req, rset), 0)
+ with web_request(vid='list', page_size='.1') as req:
+ self.assertEqual(paginated_rset()(None, req, rset), 0)
+ with web_request(vid='list', page_size='not_an_int') as req:
+ self.assertEqual(paginated_rset()(None, req, rset), 0)
+
+
if __name__ == '__main__':
unittest_main()
-
--- a/test/unittest_rqlrewrite.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/unittest_rqlrewrite.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,6 +16,8 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+from six import string_types
+
from logilab.common.testlib import unittest_main, TestCase
from logilab.common.testlib import mock_object
from yams import BadSchemaDefinition
@@ -67,9 +69,9 @@
rewriter = _prepare_rewriter(rqlrewrite.RQLRewriter, kwargs)
snippets = []
for v, exprs in sorted(snippets_map.items()):
- rqlexprs = [isinstance(snippet, basestring)
- and mock_object(snippet_rqlst=parse('Any X WHERE '+snippet).children[0],
- expression='Any X WHERE '+snippet)
+ rqlexprs = [isinstance(snippet, string_types)
+ and mock_object(snippet_rqlst=parse(u'Any X WHERE '+snippet).children[0],
+ expression=u'Any X WHERE '+snippet)
or snippet
for snippet in exprs]
snippets.append((dict([v]), rqlexprs))
@@ -90,7 +92,7 @@
selects.append(stmt)
assert node in selects, (node, selects)
for stmt in selects:
- for var in stmt.defined_vars.itervalues():
+ for var in stmt.defined_vars.values():
assert var.stinfo['references']
vrefmap = vrefmaps[stmt]
assert not (var.stinfo['references'] ^ vrefmap[var.name]), (node.as_string(), var, var.stinfo['references'], vrefmap[var.name])
@@ -108,90 +110,90 @@
def test_base_var(self):
constraint = ('X in_state S, U in_group G, P require_state S,'
'P name "read", P require_group G')
- rqlst = parse('Card C')
+ rqlst = parse(u'Card C')
rewrite(rqlst, {('C', 'X'): (constraint,)}, {})
self.assertEqual(rqlst.as_string(),
- u"Any C WHERE C is Card, B eid %(D)s, "
- "EXISTS(C in_state A, B in_group E, F require_state A, "
- "F name 'read', F require_group E, A is State, E is CWGroup, F is CWPermission)")
+ u'Any C WHERE C is Card, B eid %(D)s, '
+ 'EXISTS(C in_state A, B in_group E, F require_state A, '
+ 'F name "read", F require_group E, A is State, E is CWGroup, F is CWPermission)')
def test_multiple_var(self):
card_constraint = ('X in_state S, U in_group G, P require_state S,'
'P name "read", P require_group G')
affaire_constraints = ('X ref LIKE "PUBLIC%"', 'U in_group G, G name "public"')
kwargs = {'u':2}
- rqlst = parse('Any S WHERE S documented_by C, C eid %(u)s')
+ rqlst = parse(u'Any S WHERE S documented_by C, C eid %(u)s')
rewrite(rqlst, {('C', 'X'): (card_constraint,), ('S', 'X'): affaire_constraints},
kwargs)
self.assertMultiLineEqual(
rqlst.as_string(),
- "Any S WHERE S documented_by C, C eid %(u)s, B eid %(D)s, "
- "EXISTS(C in_state A, B in_group E, F require_state A, "
- "F name 'read', F require_group E, A is State, E is CWGroup, F is CWPermission), "
- "(EXISTS(S ref LIKE 'PUBLIC%')) OR (EXISTS(B in_group G, G name 'public', G is CWGroup)), "
- "S is Affaire")
+ u'Any S WHERE S documented_by C, C eid %(u)s, B eid %(D)s, '
+ 'EXISTS(C in_state A, B in_group E, F require_state A, '
+ 'F name "read", F require_group E, A is State, E is CWGroup, F is CWPermission), '
+ '(EXISTS(S ref LIKE "PUBLIC%")) OR (EXISTS(B in_group G, G name "public", G is CWGroup)), '
+ 'S is Affaire')
self.assertIn('D', kwargs)
def test_or(self):
constraint = '(X identity U) OR (X in_state ST, CL identity U, CL in_state ST, ST name "subscribed")'
- rqlst = parse('Any S WHERE S owned_by C, C eid %(u)s, S is in (CWUser, CWGroup)')
+ rqlst = parse(u'Any S WHERE S owned_by C, C eid %(u)s, S is in (CWUser, CWGroup)')
rewrite(rqlst, {('C', 'X'): (constraint,)}, {'u':1})
self.assertEqual(rqlst.as_string(),
- "Any S WHERE S owned_by C, C eid %(u)s, S is IN(CWUser, CWGroup), A eid %(B)s, "
- "EXISTS((C identity A) OR (C in_state D, E identity A, "
- "E in_state D, D name 'subscribed'), D is State, E is CWUser)")
+ 'Any S WHERE S owned_by C, C eid %(u)s, S is IN(CWUser, CWGroup), A eid %(B)s, '
+ 'EXISTS((C identity A) OR (C in_state D, E identity A, '
+ 'E in_state D, D name "subscribed"), D is State, E is CWUser)')
def test_simplified_rqlst(self):
constraint = ('X in_state S, U in_group G, P require_state S,'
'P name "read", P require_group G')
- rqlst = parse('Any 2') # this is the simplified rql st for Any X WHERE X eid 12
+ rqlst = parse(u'Any 2') # this is the simplified rql st for Any X WHERE X eid 12
rewrite(rqlst, {('2', 'X'): (constraint,)}, {})
self.assertEqual(rqlst.as_string(),
- u"Any 2 WHERE B eid %(C)s, "
- "EXISTS(2 in_state A, B in_group D, E require_state A, "
- "E name 'read', E require_group D, A is State, D is CWGroup, E is CWPermission)")
+ u'Any 2 WHERE B eid %(C)s, '
+ 'EXISTS(2 in_state A, B in_group D, E require_state A, '
+ 'E name "read", E require_group D, A is State, D is CWGroup, E is CWPermission)')
def test_optional_var_1(self):
constraint = ('X in_state S, U in_group G, P require_state S,'
'P name "read", P require_group G')
- rqlst = parse('Any A,C WHERE A documented_by C?')
+ rqlst = parse(u'Any A,C WHERE A documented_by C?')
rewrite(rqlst, {('C', 'X'): (constraint,)}, {})
self.assertEqual(rqlst.as_string(),
- "Any A,C WHERE A documented_by C?, A is Affaire "
- "WITH C BEING "
- "(Any C WHERE EXISTS(C in_state B, D in_group F, G require_state B, G name 'read', "
- "G require_group F), D eid %(A)s, C is Card)")
+ u'Any A,C WHERE A documented_by C?, A is Affaire '
+ 'WITH C BEING '
+ '(Any C WHERE EXISTS(C in_state B, D in_group F, G require_state B, G name "read", '
+ 'G require_group F), D eid %(A)s, C is Card)')
def test_optional_var_2(self):
constraint = ('X in_state S, U in_group G, P require_state S,'
'P name "read", P require_group G')
- rqlst = parse('Any A,C,T WHERE A documented_by C?, C title T')
+ rqlst = parse(u'Any A,C,T WHERE A documented_by C?, C title T')
rewrite(rqlst, {('C', 'X'): (constraint,)}, {})
self.assertEqual(rqlst.as_string(),
- "Any A,C,T WHERE A documented_by C?, A is Affaire "
- "WITH C,T BEING "
- "(Any C,T WHERE C title T, EXISTS(C in_state B, D in_group F, "
- "G require_state B, G name 'read', G require_group F), "
- "D eid %(A)s, C is Card)")
+ u'Any A,C,T WHERE A documented_by C?, A is Affaire '
+ 'WITH C,T BEING '
+ '(Any C,T WHERE C title T, EXISTS(C in_state B, D in_group F, '
+ 'G require_state B, G name "read", G require_group F), '
+ 'D eid %(A)s, C is Card)')
def test_optional_var_3(self):
constraint1 = ('X in_state S, U in_group G, P require_state S,'
'P name "read", P require_group G')
constraint2 = 'X in_state S, S name "public"'
- rqlst = parse('Any A,C,T WHERE A documented_by C?, C title T')
+ rqlst = parse(u'Any A,C,T WHERE A documented_by C?, C title T')
rewrite(rqlst, {('C', 'X'): (constraint1, constraint2)}, {})
self.assertEqual(rqlst.as_string(),
- "Any A,C,T WHERE A documented_by C?, A is Affaire "
- "WITH C,T BEING (Any C,T WHERE C title T, "
- "(EXISTS(C in_state B, D in_group F, G require_state B, G name 'read', G require_group F)) "
- "OR (EXISTS(C in_state E, E name 'public')), "
- "D eid %(A)s, C is Card)")
+ u'Any A,C,T WHERE A documented_by C?, A is Affaire '
+ 'WITH C,T BEING (Any C,T WHERE C title T, '
+ '(EXISTS(C in_state B, D in_group F, G require_state B, G name "read", G require_group F)) '
+ 'OR (EXISTS(C in_state E, E name "public")), '
+ 'D eid %(A)s, C is Card)')
def test_optional_var_4(self):
constraint1 = 'A created_by U, X documented_by A'
constraint2 = 'A created_by U, X concerne A'
constraint3 = 'X created_by U'
- rqlst = parse('Any X,LA,Y WHERE LA? documented_by X, LA concerne Y')
+ rqlst = parse(u'Any X,LA,Y WHERE LA? documented_by X, LA concerne Y')
rewrite(rqlst, {('LA', 'X'): (constraint1, constraint2),
('X', 'X'): (constraint3,),
('Y', 'X'): (constraint3,)}, {})
@@ -208,7 +210,7 @@
# see test of the same name in RewriteFullTC: original problem is
# unreproducible here because it actually lies in
# RQLRewriter.insert_local_checks
- rqlst = parse('Any A,AR,X,CD WHERE A concerne X?, A ref AR, A eid %(a)s, X creation_date CD')
+ rqlst = parse(u'Any A,AR,X,CD WHERE A concerne X?, A ref AR, A eid %(a)s, X creation_date CD')
rewrite(rqlst, {('X', 'X'): ('X created_by U',),}, {'a': 3})
self.assertEqual(rqlst.as_string(),
u'Any A,AR,X,CD WHERE A concerne X?, A ref AR, A eid %(a)s WITH X,CD BEING (Any X,CD WHERE X creation_date CD, EXISTS(X created_by B), B eid %(A)s, X is IN(Division, Note, Societe))')
@@ -216,7 +218,7 @@
def test_optional_var_inlined(self):
c1 = ('X require_permission P')
c2 = ('X inlined_card O, O require_permission P')
- rqlst = parse('Any C,A,R WHERE A? inlined_card C, A ref R')
+ rqlst = parse(u'Any C,A,R WHERE A? inlined_card C, A ref R')
rewrite(rqlst, {('C', 'X'): (c1,),
('A', 'X'): (c2,),
}, {})
@@ -231,7 +233,7 @@
# def test_optional_var_inlined_has_perm(self):
# c1 = ('X require_permission P')
# c2 = ('X inlined_card O, U has_read_permission O')
- # rqlst = parse('Any C,A,R WHERE A? inlined_card C, A ref R')
+ # rqlst = parse(u'Any C,A,R WHERE A? inlined_card C, A ref R')
# rewrite(rqlst, {('C', 'X'): (c1,),
# ('A', 'X'): (c2,),
# }, {})
@@ -241,7 +243,7 @@
def test_optional_var_inlined_imbricated_error(self):
c1 = ('X require_permission P')
c2 = ('X inlined_card O, O require_permission P')
- rqlst = parse('Any C,A,R,A2,R2 WHERE A? inlined_card C, A ref R,A2? inlined_card C, A2 ref R2')
+ rqlst = parse(u'Any C,A,R,A2,R2 WHERE A? inlined_card C, A ref R,A2? inlined_card C, A2 ref R2')
self.assertRaises(BadSchemaDefinition,
rewrite, rqlst, {('C', 'X'): (c1,),
('A', 'X'): (c2,),
@@ -251,7 +253,7 @@
def test_optional_var_inlined_linked(self):
c1 = ('X require_permission P')
c2 = ('X inlined_card O, O require_permission P')
- rqlst = parse('Any A,W WHERE A inlined_card C?, C inlined_note N, '
+ rqlst = parse(u'Any A,W WHERE A inlined_card C?, C inlined_note N, '
'N inlined_affaire W')
rewrite(rqlst, {('C', 'X'): (c1,)}, {})
self.assertEqual(rqlst.as_string(),
@@ -265,70 +267,70 @@
# relation used in the rql expression can be ignored and S replaced by
# the variable from the incoming query
snippet = ('X in_state S, S name "hop"')
- rqlst = parse('Card C WHERE C in_state STATE')
+ rqlst = parse(u'Card C WHERE C in_state STATE')
rewrite(rqlst, {('C', 'X'): (snippet,)}, {})
self.assertEqual(rqlst.as_string(),
- "Any C WHERE C in_state STATE, C is Card, "
- "EXISTS(STATE name 'hop'), STATE is State")
+ 'Any C WHERE C in_state STATE, C is Card, '
+ 'EXISTS(STATE name "hop"), STATE is State')
def test_relation_optimization_1_rhs(self):
snippet = ('TW subworkflow_exit X, TW name "hop"')
- rqlst = parse('WorkflowTransition C WHERE C subworkflow_exit EXIT')
+ rqlst = parse(u'WorkflowTransition C WHERE C subworkflow_exit EXIT')
rewrite(rqlst, {('EXIT', 'X'): (snippet,)}, {})
self.assertEqual(rqlst.as_string(),
- "Any C WHERE C subworkflow_exit EXIT, C is WorkflowTransition, "
- "EXISTS(C name 'hop'), EXIT is SubWorkflowExitPoint")
+ 'Any C WHERE C subworkflow_exit EXIT, C is WorkflowTransition, '
+ 'EXISTS(C name "hop"), EXIT is SubWorkflowExitPoint')
def test_relation_optimization_2_lhs(self):
# optional relation can be shared if also optional in the snippet
snippet = ('X in_state S?, S name "hop"')
- rqlst = parse('Card C WHERE C in_state STATE?')
+ rqlst = parse(u'Card C WHERE C in_state STATE?')
rewrite(rqlst, {('C', 'X'): (snippet,)}, {})
self.assertEqual(rqlst.as_string(),
- "Any C WHERE C in_state STATE?, C is Card, "
- "EXISTS(STATE name 'hop'), STATE is State")
+ 'Any C WHERE C in_state STATE?, C is Card, '
+ 'EXISTS(STATE name "hop"), STATE is State')
def test_relation_optimization_2_rhs(self):
snippet = ('TW? subworkflow_exit X, TW name "hop"')
- rqlst = parse('SubWorkflowExitPoint EXIT WHERE C? subworkflow_exit EXIT')
+ rqlst = parse(u'SubWorkflowExitPoint EXIT WHERE C? subworkflow_exit EXIT')
rewrite(rqlst, {('EXIT', 'X'): (snippet,)}, {})
self.assertEqual(rqlst.as_string(),
- "Any EXIT WHERE C? subworkflow_exit EXIT, EXIT is SubWorkflowExitPoint, "
- "EXISTS(C name 'hop'), C is WorkflowTransition")
+ 'Any EXIT WHERE C? subworkflow_exit EXIT, EXIT is SubWorkflowExitPoint, '
+ 'EXISTS(C name "hop"), C is WorkflowTransition')
def test_relation_optimization_3_lhs(self):
# optional relation in the snippet but not in the orig tree can be shared
snippet = ('X in_state S?, S name "hop"')
- rqlst = parse('Card C WHERE C in_state STATE')
+ rqlst = parse(u'Card C WHERE C in_state STATE')
rewrite(rqlst, {('C', 'X'): (snippet,)}, {})
self.assertEqual(rqlst.as_string(),
- "Any C WHERE C in_state STATE, C is Card, "
- "EXISTS(STATE name 'hop'), STATE is State")
+ 'Any C WHERE C in_state STATE, C is Card, '
+ 'EXISTS(STATE name "hop"), STATE is State')
def test_relation_optimization_3_rhs(self):
snippet = ('TW? subworkflow_exit X, TW name "hop"')
- rqlst = parse('WorkflowTransition C WHERE C subworkflow_exit EXIT')
+ rqlst = parse(u'WorkflowTransition C WHERE C subworkflow_exit EXIT')
rewrite(rqlst, {('EXIT', 'X'): (snippet,)}, {})
self.assertEqual(rqlst.as_string(),
- "Any C WHERE C subworkflow_exit EXIT, C is WorkflowTransition, "
- "EXISTS(C name 'hop'), EXIT is SubWorkflowExitPoint")
+ 'Any C WHERE C subworkflow_exit EXIT, C is WorkflowTransition, '
+ 'EXISTS(C name "hop"), EXIT is SubWorkflowExitPoint')
def test_relation_non_optimization_1_lhs(self):
# but optional relation in the orig tree but not in the snippet can't be shared
snippet = ('X in_state S, S name "hop"')
- rqlst = parse('Card C WHERE C in_state STATE?')
+ rqlst = parse(u'Card C WHERE C in_state STATE?')
rewrite(rqlst, {('C', 'X'): (snippet,)}, {})
self.assertEqual(rqlst.as_string(),
- "Any C WHERE C in_state STATE?, C is Card, "
- "EXISTS(C in_state A, A name 'hop', A is State), STATE is State")
+ 'Any C WHERE C in_state STATE?, C is Card, '
+ 'EXISTS(C in_state A, A name "hop", A is State), STATE is State')
def test_relation_non_optimization_1_rhs(self):
snippet = ('TW subworkflow_exit X, TW name "hop"')
- rqlst = parse('SubWorkflowExitPoint EXIT WHERE C? subworkflow_exit EXIT')
+ rqlst = parse(u'SubWorkflowExitPoint EXIT WHERE C? subworkflow_exit EXIT')
rewrite(rqlst, {('EXIT', 'X'): (snippet,)}, {})
self.assertEqual(rqlst.as_string(),
- "Any EXIT WHERE C? subworkflow_exit EXIT, EXIT is SubWorkflowExitPoint, "
- "EXISTS(A subworkflow_exit EXIT, A name 'hop', A is WorkflowTransition), "
- "C is WorkflowTransition")
+ 'Any EXIT WHERE C? subworkflow_exit EXIT, EXIT is SubWorkflowExitPoint, '
+ 'EXISTS(A subworkflow_exit EXIT, A name "hop", A is WorkflowTransition), '
+ 'C is WorkflowTransition')
def test_relation_non_optimization_2(self):
"""See #3024730"""
@@ -336,7 +338,7 @@
# previously inserted, else this may introduce duplicated results, as N
# will then be shared by multiple EXISTS and so at SQL generation time,
# the table will be in the FROM clause of the outermost query
- rqlst = parse('Any A,C WHERE A inlined_card C')
+ rqlst = parse(u'Any A,C WHERE A inlined_card C')
rewrite(rqlst, {('A', 'X'): ('X inlined_card C, C inlined_note N, N owned_by U',),
('C', 'X'): ('X inlined_note N, N owned_by U',)}, {})
self.assertEqual(rqlst.as_string(),
@@ -348,35 +350,35 @@
def test_unsupported_constraint_1(self):
# CWUser doesn't have require_permission
trinfo_constraint = ('X wf_info_for Y, Y require_permission P, P name "read"')
- rqlst = parse('Any U,T WHERE U is CWUser, T wf_info_for U')
+ rqlst = parse(u'Any U,T WHERE U is CWUser, T wf_info_for U')
self.assertRaises(Unauthorized, rewrite, rqlst, {('T', 'X'): (trinfo_constraint,)}, {})
def test_unsupported_constraint_2(self):
trinfo_constraint = ('X wf_info_for Y, Y require_permission P, P name "read"')
- rqlst = parse('Any U,T WHERE U is CWUser, T wf_info_for U')
+ rqlst = parse(u'Any U,T WHERE U is CWUser, T wf_info_for U')
rewrite(rqlst, {('T', 'X'): (trinfo_constraint, 'X wf_info_for Y, Y in_group G, G name "managers"')}, {})
self.assertEqual(rqlst.as_string(),
- u"Any U,T WHERE U is CWUser, T wf_info_for U, "
- "EXISTS(U in_group B, B name 'managers', B is CWGroup), T is TrInfo")
+ u'Any U,T WHERE U is CWUser, T wf_info_for U, '
+ 'EXISTS(U in_group B, B name "managers", B is CWGroup), T is TrInfo')
def test_unsupported_constraint_3(self):
self.skipTest('raise unauthorized for now')
trinfo_constraint = ('X wf_info_for Y, Y require_permission P, P name "read"')
- rqlst = parse('Any T WHERE T wf_info_for X')
+ rqlst = parse(u'Any T WHERE T wf_info_for X')
rewrite(rqlst, {('T', 'X'): (trinfo_constraint, 'X in_group G, G name "managers"')}, {})
self.assertEqual(rqlst.as_string(),
u'XXX dunno what should be generated')
def test_add_ambiguity_exists(self):
constraint = ('X concerne Y')
- rqlst = parse('Affaire X')
+ rqlst = parse(u'Affaire X')
rewrite(rqlst, {('X', 'X'): (constraint,)}, {})
self.assertEqual(rqlst.as_string(),
u"Any X WHERE X is Affaire, ((EXISTS(X concerne A, A is Division)) OR (EXISTS(X concerne C, C is Societe))) OR (EXISTS(X concerne B, B is Note))")
def test_add_ambiguity_outerjoin(self):
constraint = ('X concerne Y')
- rqlst = parse('Any X,C WHERE X? documented_by C')
+ rqlst = parse(u'Any X,C WHERE X? documented_by C')
rewrite(rqlst, {('X', 'X'): (constraint,)}, {})
# ambiguity are kept in the sub-query, no need to be resolved using OR
self.assertEqual(rqlst.as_string(),
@@ -385,76 +387,76 @@
def test_rrqlexpr_nonexistant_subject_1(self):
constraint = RRQLExpression('S owned_by U')
- rqlst = parse('Card C')
+ rqlst = parse(u'Card C')
rewrite(rqlst, {('C', 'S'): (constraint,)}, {}, 'SU')
self.assertEqual(rqlst.as_string(),
u"Any C WHERE C is Card, A eid %(B)s, EXISTS(C owned_by A)")
- rqlst = parse('Card C')
+ rqlst = parse(u'Card C')
rewrite(rqlst, {('C', 'S'): (constraint,)}, {}, 'OU')
self.assertEqual(rqlst.as_string(),
u"Any C WHERE C is Card")
- rqlst = parse('Card C')
+ rqlst = parse(u'Card C')
rewrite(rqlst, {('C', 'S'): (constraint,)}, {}, 'SOU')
self.assertEqual(rqlst.as_string(),
u"Any C WHERE C is Card, A eid %(B)s, EXISTS(C owned_by A)")
def test_rrqlexpr_nonexistant_subject_2(self):
constraint = RRQLExpression('S owned_by U, O owned_by U, O is Card')
- rqlst = parse('Card C')
+ rqlst = parse(u'Card C')
rewrite(rqlst, {('C', 'S'): (constraint,)}, {}, 'SU')
self.assertEqual(rqlst.as_string(),
'Any C WHERE C is Card, A eid %(B)s, EXISTS(C owned_by A)')
- rqlst = parse('Card C')
+ rqlst = parse(u'Card C')
rewrite(rqlst, {('C', 'S'): (constraint,)}, {}, 'OU')
self.assertEqual(rqlst.as_string(),
'Any C WHERE C is Card, B eid %(D)s, EXISTS(A owned_by B, A is Card)')
- rqlst = parse('Card C')
+ rqlst = parse(u'Card C')
rewrite(rqlst, {('C', 'S'): (constraint,)}, {}, 'SOU')
self.assertEqual(rqlst.as_string(),
'Any C WHERE C is Card, A eid %(B)s, EXISTS(C owned_by A, D owned_by A, D is Card)')
def test_rrqlexpr_nonexistant_subject_3(self):
constraint = RRQLExpression('U in_group G, G name "users"')
- rqlst = parse('Card C')
+ rqlst = parse(u'Card C')
rewrite(rqlst, {('C', 'S'): (constraint,)}, {}, 'SU')
self.assertEqual(rqlst.as_string(),
u'Any C WHERE C is Card, A eid %(B)s, EXISTS(A in_group D, D name "users", D is CWGroup)')
def test_rrqlexpr_nonexistant_subject_4(self):
constraint = RRQLExpression('U in_group G, G name "users", S owned_by U')
- rqlst = parse('Card C')
+ rqlst = parse(u'Card C')
rewrite(rqlst, {('C', 'S'): (constraint,)}, {}, 'SU')
self.assertEqual(rqlst.as_string(),
u'Any C WHERE C is Card, A eid %(B)s, EXISTS(A in_group D, D name "users", C owned_by A, D is CWGroup)')
- rqlst = parse('Card C')
+ rqlst = parse(u'Card C')
rewrite(rqlst, {('C', 'S'): (constraint,)}, {}, 'OU')
self.assertEqual(rqlst.as_string(),
u'Any C WHERE C is Card, A eid %(B)s, EXISTS(A in_group D, D name "users", D is CWGroup)')
def test_rrqlexpr_nonexistant_subject_5(self):
constraint = RRQLExpression('S owned_by Z, O owned_by Z, O is Card')
- rqlst = parse('Card C')
+ rqlst = parse(u'Card C')
rewrite(rqlst, {('C', 'S'): (constraint,)}, {}, 'S')
self.assertEqual(rqlst.as_string(),
u"Any C WHERE C is Card, EXISTS(C owned_by A, A is CWUser)")
def test_rqlexpr_not_relation_1_1(self):
constraint = ERQLExpression('X owned_by Z, Z login "hop"', 'X')
- rqlst = parse('Affaire A WHERE NOT EXISTS(A documented_by C)')
+ rqlst = parse(u'Affaire A WHERE NOT EXISTS(A documented_by C)')
rewrite(rqlst, {('C', 'X'): (constraint,)}, {}, 'X')
self.assertEqual(rqlst.as_string(),
u'Any A WHERE NOT EXISTS(A documented_by C, EXISTS(C owned_by B, B login "hop", B is CWUser), C is Card), A is Affaire')
def test_rqlexpr_not_relation_1_2(self):
constraint = ERQLExpression('X owned_by Z, Z login "hop"', 'X')
- rqlst = parse('Affaire A WHERE NOT EXISTS(A documented_by C)')
+ rqlst = parse(u'Affaire A WHERE NOT EXISTS(A documented_by C)')
rewrite(rqlst, {('A', 'X'): (constraint,)}, {}, 'X')
self.assertEqual(rqlst.as_string(),
u'Any A WHERE NOT EXISTS(A documented_by C, C is Card), A is Affaire, EXISTS(A owned_by B, B login "hop", B is CWUser)')
def test_rqlexpr_not_relation_2(self):
constraint = ERQLExpression('X owned_by Z, Z login "hop"', 'X')
- rqlst = rqlhelper.parse('Affaire A WHERE NOT A documented_by C', annotate=False)
+ rqlst = rqlhelper.parse(u'Affaire A WHERE NOT A documented_by C', annotate=False)
rewrite(rqlst, {('C', 'X'): (constraint,)}, {}, 'X')
self.assertEqual(rqlst.as_string(),
u'Any A WHERE NOT EXISTS(A documented_by C, EXISTS(C owned_by B, B login "hop", B is CWUser), C is Card), A is Affaire')
@@ -463,7 +465,7 @@
c1 = ERQLExpression('X owned_by Z, Z login "hop"', 'X')
c2 = ERQLExpression('X owned_by Z, Z login "hip"', 'X')
c3 = ERQLExpression('X owned_by Z, Z login "momo"', 'X')
- rqlst = rqlhelper.parse('Any A WHERE A documented_by C?', annotate=False)
+ rqlst = rqlhelper.parse(u'Any A WHERE A documented_by C?', annotate=False)
rewrite(rqlst, {('C', 'X'): (c1, c2, c3)}, {}, 'X')
self.assertEqual(rqlst.as_string(),
u'Any A WHERE A documented_by C?, A is Affaire '
@@ -484,12 +486,12 @@
# 4. this variable require a rewrite
c_bad = ERQLExpression('X documented_by R, A in_state R')
- rqlst = parse('Any A, R WHERE A ref R, S is Affaire')
+ rqlst = parse(u'Any A, R WHERE A ref R, S is Affaire')
rewrite(rqlst, {('A', 'X'): (c_ok, c_bad)}, {})
def test_nonregr_is_instance_of(self):
user_expr = ERQLExpression('NOT X in_group AF, AF name "guests"')
- rqlst = parse('Any O WHERE S use_email O, S is CWUser, O is_instance_of EmailAddress')
+ rqlst = parse(u'Any O WHERE S use_email O, S is CWUser, O is_instance_of EmailAddress')
rewrite(rqlst, {('S', 'X'): (user_expr,)}, {})
self.assertEqual(rqlst.as_string(),
'Any O WHERE S use_email O, S is CWUser, O is EmailAddress, '
@@ -600,7 +602,7 @@
# Basic tests
def test_base_rule(self):
rules = {'participated_in': 'S contributor O'}
- rqlst = rqlhelper.parse('Any X WHERE X participated_in S')
+ rqlst = rqlhelper.parse(u'Any X WHERE X participated_in S')
rule_rewrite(rqlst, rules)
self.assertEqual('Any X WHERE X contributor S',
rqlst.as_string())
@@ -609,7 +611,7 @@
rules = {'illustrator_of': ('C is Contribution, C contributor S, '
'C manifestation O, C role R, '
'R name "illustrator"')}
- rqlst = rqlhelper.parse('Any A,B WHERE A illustrator_of B')
+ rqlst = rqlhelper.parse(u'Any A,B WHERE A illustrator_of B')
rule_rewrite(rqlst, rules)
self.assertEqual('Any A,B WHERE C is Contribution, '
'C contributor A, C manifestation B, '
@@ -620,7 +622,7 @@
rules = {'illustrator_of': ('C is Contribution, C contributor S, '
'C manifestation O, C role R, '
'R name "illustrator"')}
- rqlst = rqlhelper.parse('Any A WHERE EXISTS(A illustrator_of B)')
+ rqlst = rqlhelper.parse(u'Any A WHERE EXISTS(A illustrator_of B)')
rule_rewrite(rqlst, rules)
self.assertEqual('Any A WHERE EXISTS(C is Contribution, '
'C contributor A, C manifestation B, '
@@ -631,7 +633,7 @@
def test_rewrite2(self):
rules = {'illustrator_of': 'C is Contribution, C contributor S, '
'C manifestation O, C role R, R name "illustrator"'}
- rqlst = rqlhelper.parse('Any A,B WHERE A illustrator_of B, C require_permission R, S'
+ rqlst = rqlhelper.parse(u'Any A,B WHERE A illustrator_of B, C require_permission R, S'
'require_state O')
rule_rewrite(rqlst, rules)
self.assertEqual('Any A,B WHERE C require_permission R, S require_state O, '
@@ -642,7 +644,7 @@
def test_rewrite3(self):
rules = {'illustrator_of': 'C is Contribution, C contributor S, '
'C manifestation O, C role R, R name "illustrator"'}
- rqlst = rqlhelper.parse('Any A,B WHERE E require_permission T, A illustrator_of B')
+ rqlst = rqlhelper.parse(u'Any A,B WHERE E require_permission T, A illustrator_of B')
rule_rewrite(rqlst, rules)
self.assertEqual('Any A,B WHERE E require_permission T, '
'C is Contribution, C contributor A, C manifestation B, '
@@ -652,7 +654,7 @@
def test_rewrite4(self):
rules = {'illustrator_of': 'C is Contribution, C contributor S, '
'C manifestation O, C role R, R name "illustrator"'}
- rqlst = rqlhelper.parse('Any A,B WHERE C require_permission R, A illustrator_of B')
+ rqlst = rqlhelper.parse(u'Any A,B WHERE C require_permission R, A illustrator_of B')
rule_rewrite(rqlst, rules)
self.assertEqual('Any A,B WHERE C require_permission R, '
'D is Contribution, D contributor A, D manifestation B, '
@@ -662,7 +664,7 @@
def test_rewrite5(self):
rules = {'illustrator_of': 'C is Contribution, C contributor S, '
'C manifestation O, C role R, R name "illustrator"'}
- rqlst = rqlhelper.parse('Any A,B WHERE C require_permission R, A illustrator_of B, '
+ rqlst = rqlhelper.parse(u'Any A,B WHERE C require_permission R, A illustrator_of B, '
'S require_state O')
rule_rewrite(rqlst, rules)
self.assertEqual('Any A,B WHERE C require_permission R, S require_state O, '
@@ -674,7 +676,7 @@
def test_rewrite_with(self):
rules = {'illustrator_of': 'C is Contribution, C contributor S, '
'C manifestation O, C role R, R name "illustrator"'}
- rqlst = rqlhelper.parse('Any A,B WITH A, B BEING(Any X, Y WHERE X illustrator_of Y)')
+ rqlst = rqlhelper.parse(u'Any A,B WITH A, B BEING(Any X, Y WHERE X illustrator_of Y)')
rule_rewrite(rqlst, rules)
self.assertEqual('Any A,B WITH A,B BEING '
'(Any X,Y WHERE A is Contribution, A contributor X, '
@@ -684,7 +686,7 @@
def test_rewrite_with2(self):
rules = {'illustrator_of': 'C is Contribution, C contributor S, '
'C manifestation O, C role R, R name "illustrator"'}
- rqlst = rqlhelper.parse('Any A,B WHERE T require_permission C WITH A, B BEING(Any X, Y WHERE X illustrator_of Y)')
+ rqlst = rqlhelper.parse(u'Any A,B WHERE T require_permission C WITH A, B BEING(Any X, Y WHERE X illustrator_of Y)')
rule_rewrite(rqlst, rules)
self.assertEqual('Any A,B WHERE T require_permission C '
'WITH A,B BEING (Any X,Y WHERE A is Contribution, '
@@ -693,7 +695,7 @@
def test_rewrite_with3(self):
rules = {'participated_in': 'S contributor O'}
- rqlst = rqlhelper.parse('Any A,B WHERE A participated_in B '
+ rqlst = rqlhelper.parse(u'Any A,B WHERE A participated_in B '
'WITH A, B BEING(Any X,Y WHERE X contributor Y)')
rule_rewrite(rqlst, rules)
self.assertEqual('Any A,B WHERE A contributor B WITH A,B BEING '
@@ -703,7 +705,7 @@
def test_rewrite_with4(self):
rules = {'illustrator_of': 'C is Contribution, C contributor S, '
'C manifestation O, C role R, R name "illustrator"'}
- rqlst = rqlhelper.parse('Any A,B WHERE A illustrator_of B '
+ rqlst = rqlhelper.parse(u'Any A,B WHERE A illustrator_of B '
'WITH A, B BEING(Any X, Y WHERE X illustrator_of Y)')
rule_rewrite(rqlst, rules)
self.assertEqual('Any A,B WHERE C is Contribution, '
@@ -717,7 +719,7 @@
def test_rewrite_union(self):
rules = {'illustrator_of': 'C is Contribution, C contributor S, '
'C manifestation O, C role R, R name "illustrator"'}
- rqlst = rqlhelper.parse('(Any A,B WHERE A illustrator_of B) UNION'
+ rqlst = rqlhelper.parse(u'(Any A,B WHERE A illustrator_of B) UNION'
'(Any X,Y WHERE X is CWUser, Z manifestation Y)')
rule_rewrite(rqlst, rules)
self.assertEqual('(Any A,B WHERE C is Contribution, '
@@ -728,7 +730,7 @@
def test_rewrite_union2(self):
rules = {'illustrator_of': 'C is Contribution, C contributor S, '
'C manifestation O, C role R, R name "illustrator"'}
- rqlst = rqlhelper.parse('(Any Y WHERE Y match W) UNION '
+ rqlst = rqlhelper.parse(u'(Any Y WHERE Y match W) UNION '
'(Any A WHERE A illustrator_of B) UNION '
'(Any Y WHERE Y is ArtWork)')
rule_rewrite(rqlst, rules)
@@ -742,7 +744,7 @@
def test_rewrite_exists(self):
rules = {'illustrator_of': 'C is Contribution, C contributor S, '
'C manifestation O, C role R, R name "illustrator"'}
- rqlst = rqlhelper.parse('(Any A,B WHERE A illustrator_of B, '
+ rqlst = rqlhelper.parse(u'(Any A,B WHERE A illustrator_of B, '
'EXISTS(B is ArtWork))')
rule_rewrite(rqlst, rules)
self.assertEqual('Any A,B WHERE EXISTS(B is ArtWork), '
@@ -753,7 +755,7 @@
def test_rewrite_exists2(self):
rules = {'illustrator_of': 'C is Contribution, C contributor S, '
'C manifestation O, C role R, R name "illustrator"'}
- rqlst = rqlhelper.parse('(Any A,B WHERE B contributor A, EXISTS(A illustrator_of W))')
+ rqlst = rqlhelper.parse(u'(Any A,B WHERE B contributor A, EXISTS(A illustrator_of W))')
rule_rewrite(rqlst, rules)
self.assertEqual('Any A,B WHERE B contributor A, '
'EXISTS(C is Contribution, C contributor A, C manifestation W, '
@@ -763,7 +765,7 @@
def test_rewrite_exists3(self):
rules = {'illustrator_of': 'C is Contribution, C contributor S, '
'C manifestation O, C role R, R name "illustrator"'}
- rqlst = rqlhelper.parse('(Any A,B WHERE A illustrator_of B, EXISTS(A illustrator_of W))')
+ rqlst = rqlhelper.parse(u'(Any A,B WHERE A illustrator_of B, EXISTS(A illustrator_of W))')
rule_rewrite(rqlst, rules)
self.assertEqual('Any A,B WHERE EXISTS(C is Contribution, C contributor A, '
'C manifestation W, C role D, D name "illustrator"), '
@@ -774,7 +776,7 @@
# Test for GROUPBY
def test_rewrite_groupby(self):
rules = {'participated_in': 'S contributor O'}
- rqlst = rqlhelper.parse('Any SUM(SA) GROUPBY S WHERE P participated_in S, P manifestation SA')
+ rqlst = rqlhelper.parse(u'Any SUM(SA) GROUPBY S WHERE P participated_in S, P manifestation SA')
rule_rewrite(rqlst, rules)
self.assertEqual('Any SUM(SA) GROUPBY S WHERE P manifestation SA, P contributor S',
rqlst.as_string())
--- a/test/unittest_rset.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/unittest_rset.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,8 +18,9 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""unit tests for module cubicweb.utils"""
-from urlparse import urlsplit
-import pickle
+from six import string_types
+from six.moves import cPickle as pickle
+from six.moves.urllib.parse import urlsplit
from rql import parse
@@ -100,7 +101,11 @@
def test_pickle(self):
del self.rset.req
- self.assertEqual(len(pickle.dumps(self.rset)), 376)
+ rs2 = pickle.loads(pickle.dumps(self.rset))
+ self.assertEqual(self.rset.rows, rs2.rows)
+ self.assertEqual(self.rset.rowcount, rs2.rowcount)
+ self.assertEqual(self.rset.rql, rs2.rql)
+ self.assertEqual(self.rset.description, rs2.description)
def test_build_url(self):
with self.admin_access.web_request() as req:
@@ -274,7 +279,7 @@
"""make sure syntax tree is cached"""
rqlst1 = self.rset.syntax_tree()
rqlst2 = self.rset.syntax_tree()
- self.assert_(rqlst1 is rqlst2)
+ self.assertIs(rqlst1, rqlst2)
def test_get_entity_simple(self):
with self.admin_access.web_request() as req:
@@ -550,19 +555,32 @@
def test_str(self):
with self.admin_access.web_request() as req:
rset = req.execute('(Any X,N WHERE X is CWGroup, X name N)')
- self.assertIsInstance(str(rset), basestring)
+ self.assertIsInstance(str(rset), string_types)
self.assertEqual(len(str(rset).splitlines()), 1)
def test_repr(self):
with self.admin_access.web_request() as req:
rset = req.execute('(Any X,N WHERE X is CWGroup, X name N)')
- self.assertIsInstance(repr(rset), basestring)
+ self.assertIsInstance(repr(rset), string_types)
self.assertTrue(len(repr(rset).splitlines()) > 1)
rset = req.execute('(Any X WHERE X is CWGroup, X name "managers")')
- self.assertIsInstance(str(rset), basestring)
+ self.assertIsInstance(str(rset), string_types)
self.assertEqual(len(str(rset).splitlines()), 1)
+ def test_slice(self):
+ rs = ResultSet([[12000, 'adim', u'Adim chez les pinguins'],
+ [12000, 'adim', u'Jardiner facile'],
+ [13000, 'syt', u'Le carrelage en 42 leçons'],
+ [14000, 'nico', u'La tarte tatin en 15 minutes'],
+ [14000, 'nico', u"L'épluchage du castor commun"]],
+ 'Any U, L, T WHERE U is CWUser, U login L,'\
+ 'D created_by U, D title T',
+ description=[['CWUser', 'String', 'String']] * 5)
+ self.assertEqual(rs[1::2],
+ [[12000, 'adim', u'Jardiner facile'],
+ [14000, 'nico', u'La tarte tatin en 15 minutes']])
+
def test_nonregr_symmetric_relation(self):
# see https://www.cubicweb.org/ticket/4739253
with self.admin_access.client_cnx() as cnx:
--- a/test/unittest_schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/unittest_schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -105,10 +105,9 @@
#
# isinstance(cstr, RQLConstraint)
# -> expected to return RQLConstraint instances but not
- # RRQLVocabularyConstraint and QLUniqueConstraint
+ # RQLVocabularyConstraint and RQLUniqueConstraint
self.assertFalse(issubclass(RQLUniqueConstraint, RQLVocabularyConstraint))
self.assertFalse(issubclass(RQLUniqueConstraint, RQLConstraint))
- self.assertTrue(issubclass(RQLConstraint, RQLVocabularyConstraint))
def test_entity_perms(self):
self.assertEqual(eperson.get_groups('read'), set(('managers', 'users', 'guests')))
@@ -158,7 +157,7 @@
def test_knownValues_load_schema(self):
schema = loader.load(config)
- self.assert_(isinstance(schema, CubicWebSchema))
+ self.assertIsInstance(schema, CubicWebSchema)
self.assertEqual(schema.name, 'data')
entities = sorted([str(e) for e in schema.entities()])
expected_entities = ['Ami', 'BaseTransition', 'BigInt', 'Bookmark', 'Boolean', 'Bytes', 'Card',
@@ -273,11 +272,13 @@
config = TestConfiguration('data', apphome=join(dirname(__file__), 'data_schemareader'))
config.bootstrap_cubes()
schema = loader.load(config)
- self.assertEqual(schema['in_group'].rdefs.values()[0].permissions,
+ rdef = next(iter(schema['in_group'].rdefs.values()))
+ self.assertEqual(rdef.permissions,
{'read': ('managers',),
'add': ('managers',),
'delete': ('managers',)})
- self.assertEqual(schema['cw_for_source'].rdefs.values()[0].permissions,
+ rdef = next(iter(schema['cw_for_source'].rdefs.values()))
+ self.assertEqual(rdef.permissions,
{'read': ('managers', 'users'),
'add': ('managers',),
'delete': ('managers',)})
@@ -355,11 +356,11 @@
# check object/subject type
self.assertEqual([('Person','Service')],
- schema['produces_and_buys'].rdefs.keys())
+ list(schema['produces_and_buys'].rdefs.keys()))
self.assertEqual([('Person','Service')],
- schema['produces_and_buys2'].rdefs.keys())
+ list(schema['produces_and_buys2'].rdefs.keys()))
self.assertCountEqual([('Company', 'Service'), ('Person', 'Service')],
- schema['reproduce'].rdefs.keys())
+ list(schema['reproduce'].rdefs.keys()))
# check relation definitions are marked infered
rdef = schema['produces_and_buys'].rdefs[('Person','Service')]
self.assertTrue(rdef.infered)
@@ -426,7 +427,9 @@
def test(self):
self.assertEqual(normalize_expression('X bla Y,Y blur Z , Z zigoulou X '),
- 'X bla Y, Y blur Z, Z zigoulou X')
+ 'X bla Y, Y blur Z, Z zigoulou X')
+ self.assertEqual(normalize_expression('X bla Y, Y name "x,y"'),
+ 'X bla Y, Y name "x,y"')
class RQLExpressionTC(TestCase):
@@ -553,7 +556,7 @@
self.set_description('composite rdefs for %s' % etype)
yield self.assertEqual, self.composites[etype], \
sorted([(r.rtype.type, r.subject.type, r.object.type, role)
- for r, role in sorted(schema[etype].composite_rdef_roles)])
+ for r, role in schema[etype].composite_rdef_roles])
if __name__ == '__main__':
--- a/test/unittest_uilib.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/unittest_uilib.py Thu Dec 10 12:34:15 2015 +0100
@@ -200,4 +200,3 @@
if __name__ == '__main__':
unittest_main()
-
--- a/test/unittest_utils.py Wed Dec 09 18:42:13 2015 +0100
+++ b/test/unittest_utils.py Thu Dec 10 12:34:15 2015 +0100
@@ -21,12 +21,13 @@
import decimal
import datetime
+from six.moves import range
from logilab.common.testlib import TestCase, DocTest, unittest_main
from cubicweb.devtools.testlib import CubicWebTC
-from cubicweb.utils import (make_uid, UStringIO, SizeConstrainedList,
- RepeatList, HTMLHead, QueryCache, parse_repo_uri)
+from cubicweb.utils import (make_uid, UStringIO, RepeatList, HTMLHead,
+ QueryCache, parse_repo_uri)
from cubicweb.entity import Entity
try:
@@ -67,7 +68,7 @@
def test_querycache(self):
c = QueryCache(ceiling=20)
# write only
- for x in xrange(10):
+ for x in range(10):
c[x] = x
self.assertEqual(c._usage_report(),
{'transientcount': 0,
@@ -75,7 +76,7 @@
'permanentcount': 0})
c = QueryCache(ceiling=10)
# we should also get a warning
- for x in xrange(20):
+ for x in range(20):
c[x] = x
self.assertEqual(c._usage_report(),
{'transientcount': 0,
@@ -83,8 +84,8 @@
'permanentcount': 0})
# write + reads
c = QueryCache(ceiling=20)
- for n in xrange(4):
- for x in xrange(10):
+ for n in range(4):
+ for x in range(10):
c[x] = x
c[x]
self.assertEqual(c._usage_report(),
@@ -92,8 +93,8 @@
'itemcount': 10,
'permanentcount': 0})
c = QueryCache(ceiling=20)
- for n in xrange(17):
- for x in xrange(10):
+ for n in range(17):
+ for x in range(10):
c[x] = x
c[x]
self.assertEqual(c._usage_report(),
@@ -101,8 +102,8 @@
'itemcount': 10,
'permanentcount': 10})
c = QueryCache(ceiling=20)
- for n in xrange(17):
- for x in xrange(10):
+ for n in range(17):
+ for x in range(10):
c[x] = x
if n % 2:
c[x]
@@ -115,7 +116,7 @@
class UStringIOTC(TestCase):
def test_boolean_value(self):
- self.assert_(UStringIO())
+ self.assertTrue(UStringIO())
class RepeatListTC(TestCase):
@@ -165,25 +166,6 @@
self.assertEqual(l, [(1, 3)]*2)
-class SizeConstrainedListTC(TestCase):
-
- def test_append(self):
- l = SizeConstrainedList(10)
- for i in xrange(12):
- l.append(i)
- self.assertEqual(l, range(2, 12))
-
- def test_extend(self):
- testdata = [(range(5), range(5)),
- (range(10), range(10)),
- (range(12), range(2, 12)),
- ]
- for extension, expected in testdata:
- l = SizeConstrainedList(10)
- l.extend(extension)
- yield self.assertEqual, l, expected
-
-
class JSONEncoderTC(TestCase):
def setUp(self):
if json is None:
--- a/toolsutils.py Wed Dec 09 18:42:13 2015 +0100
+++ b/toolsutils.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""some utilities for cubicweb command line tools"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
@@ -37,6 +38,8 @@
def symlink(*args):
raise NotImplementedError
+from six import add_metaclass
+
from logilab.common.clcommands import Command as BaseCommand
from logilab.common.shellutils import ASK
@@ -62,29 +65,29 @@
"""create a directory if it doesn't exist yet"""
try:
makedirs(directory)
- print '-> created directory %s' % directory
+ print('-> created directory %s' % directory)
except OSError as ex:
import errno
if ex.errno != errno.EEXIST:
raise
- print '-> no need to create existing directory %s' % directory
+ print('-> no need to create existing directory %s' % directory)
def create_symlink(source, target):
"""create a symbolic link"""
if exists(target):
remove(target)
symlink(source, target)
- print '[symlink] %s <-- %s' % (target, source)
+ print('[symlink] %s <-- %s' % (target, source))
def create_copy(source, target):
import shutil
- print '[copy] %s <-- %s' % (target, source)
+ print('[copy] %s <-- %s' % (target, source))
shutil.copy2(source, target)
def rm(whatever):
import shutil
shutil.rmtree(whatever)
- print '-> removed %s' % whatever
+ print('-> removed %s' % whatever)
def show_diffs(appl_file, ref_file, askconfirm=True):
"""interactivly replace the old file with the new file according to
@@ -95,8 +98,8 @@
diffs = pipe.stdout.read()
if diffs:
if askconfirm:
- print
- print diffs
+ print()
+ print(diffs)
action = ASK.ask('Replace ?', ('Y', 'n', 'q'), 'Y').lower()
else:
action = 'y'
@@ -106,17 +109,17 @@
except IOError:
os.system('chmod a+w %s' % appl_file)
shutil.copyfile(ref_file, appl_file)
- print 'replaced'
+ print('replaced')
elif action == 'q':
sys.exit(0)
else:
copy_file = appl_file + '.default'
- copy = file(copy_file, 'w')
+ copy = open(copy_file, 'w')
copy.write(open(ref_file).read())
copy.close()
- print 'keep current version, the new file has been written to', copy_file
+ print('keep current version, the new file has been written to', copy_file)
else:
- print 'no diff between %s and %s' % (appl_file, ref_file)
+ print('no diff between %s and %s' % (appl_file, ref_file))
SKEL_EXCLUDE = ('*.py[co]', '*.orig', '*~', '*_flymake.py')
def copy_skeleton(skeldir, targetdir, context,
@@ -143,15 +146,15 @@
if not askconfirm or not exists(tfpath) or \
ASK.confirm('%s exists, overwrite?' % tfpath):
fill_templated_file(fpath, tfpath, context)
- print '[generate] %s <-- %s' % (tfpath, fpath)
+ print('[generate] %s <-- %s' % (tfpath, fpath))
elif exists(tfpath):
show_diffs(tfpath, fpath, askconfirm)
else:
shutil.copyfile(fpath, tfpath)
def fill_templated_file(fpath, tfpath, context):
- fobj = file(tfpath, 'w')
- templated = file(fpath).read()
+ fobj = open(tfpath, 'w')
+ templated = open(fpath).read()
fobj.write(templated % context)
fobj.close()
@@ -160,8 +163,8 @@
if log:
log('set permissions to 0600 for %s', filepath)
else:
- print '-> set permissions to 0600 for %s' % filepath
- chmod(filepath, 0600)
+ print('-> set permissions to 0600 for %s' % filepath)
+ chmod(filepath, 0o600)
def read_config(config_file, raise_if_unreadable=False):
"""read some simple configuration from `config_file` and return it as a
@@ -209,12 +212,13 @@
return cls
+@add_metaclass(metacmdhandler)
class CommandHandler(object):
"""configuration specific helper for cubicweb-ctl commands"""
- __metaclass__ = metacmdhandler
def __init__(self, config):
self.config = config
+
class Command(BaseCommand):
"""base class for cubicweb-ctl commands"""
@@ -234,7 +238,7 @@
raise ConfigurationError(msg)
def fail(self, reason):
- print "command failed:", reason
+ print("command failed:", reason)
sys.exit(1)
--- a/tox.ini Wed Dec 09 18:42:13 2015 +0100
+++ b/tox.ini Thu Dec 10 12:34:15 2015 +0100
@@ -8,7 +8,9 @@
[testenv:cubicweb]
deps =
-r{toxinidir}/test/requirements.txt
-commands = pytest -t test {posargs}
+commands =
+ {envpython} -m pip install --upgrade --no-deps --quiet git+git://github.com/logilab/yapps@master#egg=yapps
+ pytest -t test {posargs}
[testenv:dataimport]
@@ -29,6 +31,8 @@
-r{toxinidir}/ext/test/requirements.txt
[testenv:hooks]
+deps =
+ -r{toxinidir}/hooks/test/requirements.txt
[testenv:server]
deps =
--- a/transaction.py Wed Dec 09 18:42:13 2015 +0100
+++ b/transaction.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,7 +17,7 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
""" undoable transaction objects. """
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from cubicweb import RepositoryError
--- a/uilib.py Wed Dec 09 18:42:13 2015 +0100
+++ b/uilib.py Thu Dec 10 12:34:15 2015 +0100
@@ -26,12 +26,15 @@
import csv
import re
-from StringIO import StringIO
+from io import StringIO
+
+from six import PY2, PY3, text_type, binary_type, string_types, integer_types
from logilab.mtconverter import xml_escape, html_unescape
from logilab.common.date import ustrftime
from logilab.common.deprecation import deprecated
+from cubicweb import _
from cubicweb.utils import js_dumps
@@ -62,7 +65,7 @@
return value
def print_int(value, req, props, displaytime=True):
- return unicode(value)
+ return text_type(value)
def print_date(value, req, props, displaytime=True):
return ustrftime(value, req.property_value('ui.date-format'))
@@ -92,7 +95,7 @@
_('%d seconds')
def print_timedelta(value, req, props, displaytime=True):
- if isinstance(value, (int, long)):
+ if isinstance(value, integer_types):
# `date - date`, unlike `datetime - datetime` gives an int
# (number of days), not a timedelta
# XXX should rql be fixed to return Int instead of Interval in
@@ -122,7 +125,7 @@
return req._('no')
def print_float(value, req, props, displaytime=True):
- return unicode(req.property_value('ui.float-format') % value)
+ return text_type(req.property_value('ui.float-format') % value) # XXX cast needed ?
PRINTERS = {
'Bytes': print_bytes,
@@ -337,9 +340,8 @@
def __unicode__(self):
if self.parent:
return u'%s.%s' % (self.parent, self.id)
- return unicode(self.id)
- def __str__(self):
- return unicode(self).encode('utf8')
+ return text_type(self.id)
+ __str__ = __unicode__ if PY3 else lambda self: self.__unicode__().encode('utf-8')
def __getattr__(self, attr):
return _JSId(attr, self)
def __call__(self, *args):
@@ -357,6 +359,7 @@
if self.parent:
return u'%s(%s)' % (self.parent, ','.join(args))
return ','.join(args)
+ __str__ = __unicode__ if PY3 else lambda self: self.__unicode__().encode('utf-8')
class _JS(object):
def __getattr__(self, attr):
@@ -389,7 +392,7 @@
'img', 'area', 'input', 'col'))
def sgml_attributes(attrs):
- return u' '.join(u'%s="%s"' % (attr, xml_escape(unicode(value)))
+ return u' '.join(u'%s="%s"' % (attr, xml_escape(text_type(value)))
for attr, value in sorted(attrs.items())
if value is not None)
@@ -407,7 +410,7 @@
value += u' ' + sgml_attributes(attrs)
if content:
if escapecontent:
- content = xml_escape(unicode(content))
+ content = xml_escape(text_type(content))
value += u'>%s</%s>' % (content, tag)
else:
if tag in HTML4_EMPTY_TAGS:
@@ -436,8 +439,8 @@
stream = StringIO() #UStringIO() don't want unicode assertion
formater.format(layout, stream)
res = stream.getvalue()
- if isinstance(res, str):
- res = unicode(res, 'UTF8')
+ if isinstance(res, binary_type):
+ res = res.decode('UTF8')
return res
# traceback formatting ########################################################
@@ -445,14 +448,17 @@
import traceback
def exc_message(ex, encoding):
- try:
- excmsg = unicode(ex)
- except Exception:
+ if PY3:
+ excmsg = str(ex)
+ else:
try:
- excmsg = unicode(str(ex), encoding, 'replace')
+ excmsg = unicode(ex)
except Exception:
- excmsg = unicode(repr(ex), encoding, 'replace')
- exctype = unicode(ex.__class__.__name__)
+ try:
+ excmsg = unicode(str(ex), encoding, 'replace')
+ except Exception:
+ excmsg = unicode(repr(ex), encoding, 'replace')
+ exctype = ex.__class__.__name__
return u'%s: %s' % (exctype, excmsg)
@@ -462,7 +468,10 @@
for stackentry in traceback.extract_tb(info[2]):
res.append(u'\tFile %s, line %s, function %s' % tuple(stackentry[:3]))
if stackentry[3]:
- res.append(u'\t %s' % stackentry[3].decode('utf-8', 'replace'))
+ data = xml_escape(stackentry[3])
+ if PY2:
+ data = data.decode('utf-8', 'replace')
+ res.append(u'\t %s' % data)
res.append(u'\n')
try:
res.append(u'\t Error: %s\n' % exception)
@@ -496,14 +505,16 @@
u'<b class="function">%s</b>:<br/>'%(
xml_escape(stackentry[0]), stackentry[1], xml_escape(stackentry[2])))
if stackentry[3]:
- string = xml_escape(stackentry[3]).decode('utf-8', 'replace')
+ string = xml_escape(stackentry[3])
+ if PY2:
+ string = string.decode('utf-8', 'replace')
strings.append(u'  %s<br/>\n' % (string))
# add locals info for each entry
try:
local_context = tcbk.tb_frame.f_locals
html_info = []
chars = 0
- for name, value in local_context.iteritems():
+ for name, value in local_context.items():
value = xml_escape(repr(value))
info = u'<span class="name">%s</span>=%s, ' % (name, value)
line_length = len(name) + len(value)
@@ -526,7 +537,9 @@
# csv files / unicode support #################################################
class UnicodeCSVWriter:
- """proxies calls to csv.writer.writerow to be able to deal with unicode"""
+ """proxies calls to csv.writer.writerow to be able to deal with unicode
+
+ Under Python 3, this code no longer encodes anything."""
def __init__(self, wfunc, encoding, **kwargs):
self.writer = csv.writer(self, **kwargs)
@@ -537,9 +550,12 @@
self.wfunc(data)
def writerow(self, row):
+ if PY3:
+ self.writer.writerow(row)
+ return
csvrow = []
for elt in row:
- if isinstance(elt, unicode):
+ if isinstance(elt, text_type):
csvrow.append(elt.encode(self.encoding))
else:
csvrow.append(str(elt))
@@ -559,7 +575,7 @@
def __call__(self, function):
def newfunc(*args, **kwargs):
ret = function(*args, **kwargs)
- if isinstance(ret, basestring):
+ if isinstance(ret, string_types):
return ret[:self.maxsize]
return ret
return newfunc
@@ -568,6 +584,6 @@
def htmlescape(function):
def newfunc(*args, **kwargs):
ret = function(*args, **kwargs)
- assert isinstance(ret, basestring)
+ assert isinstance(ret, string_types)
return xml_escape(ret)
return newfunc
--- a/utils.py Wed Dec 09 18:42:13 2015 +0100
+++ b/utils.py Thu Dec 10 12:34:15 2015 +0100
@@ -33,9 +33,10 @@
from uuid import uuid4
from warnings import warn
from threading import Lock
-from urlparse import urlparse
+from logging import getLogger
-from logging import getLogger
+from six import text_type
+from six.moves.urllib.parse import urlparse
from logilab.mtconverter import xml_escape
from logilab.common.deprecation import deprecated
@@ -100,7 +101,7 @@
"""
def __init__(self, w, tag, closetag=None):
self.written = False
- self.tag = unicode(tag)
+ self.tag = text_type(tag)
self.closetag = closetag
self.w = w
@@ -116,7 +117,7 @@
def __exit__(self, exctype, value, traceback):
if self.written is True:
if self.closetag:
- self.w(unicode(self.closetag))
+ self.w(text_type(self.closetag))
else:
self.w(self.tag.replace('<', '</', 1))
@@ -138,39 +139,6 @@
yield subchild
-class SizeConstrainedList(list):
- """simple list that makes sure the list does not get bigger than a given
- size.
-
- when the list is full and a new element is added, the first element of the
- list is removed before appending the new one
-
- >>> l = SizeConstrainedList(2)
- >>> l.append(1)
- >>> l.append(2)
- >>> l
- [1, 2]
- >>> l.append(3)
- >>> l
- [2, 3]
- """
- def __init__(self, maxsize):
- self.maxsize = maxsize
-
- def append(self, element):
- if len(self) == self.maxsize:
- del self[0]
- super(SizeConstrainedList, self).append(element)
-
- def extend(self, sequence):
- super(SizeConstrainedList, self).extend(sequence)
- keepafter = len(self) - self.maxsize
- if keepafter > 0:
- del self[:keepafter]
-
- __iadd__ = extend
-
-
class RepeatList(object):
"""fake a list with the same element in each row"""
__slots__ = ('_size', '_item')
@@ -185,13 +153,13 @@
def __iter__(self):
return repeat(self._item, self._size)
def __getitem__(self, index):
+ if isinstance(index, slice):
+ # XXX could be more efficient, but do we bother?
+ return ([self._item] * self._size)[index]
return self._item
def __delitem__(self, idc):
assert self._size > 0
self._size -= 1
- def __getslice__(self, i, j):
- # XXX could be more efficient, but do we bother?
- return ([self._item] * self._size)[i:j]
def __add__(self, other):
if isinstance(other, RepeatList):
if other._item == self._item:
@@ -208,8 +176,10 @@
if isinstance(other, RepeatList):
return other._size == self._size and other._item == self._item
return self[:] == other
- # py3k future warning "Overriding __eq__ blocks inheritance of __hash__ in 3.x"
- # is annoying but won't go away because we don't want to hash() the repeatlist
+ def __ne__(self, other):
+ return not (self == other)
+ def __hash__(self):
+ raise NotImplementedError
def pop(self, i):
self._size -= 1
@@ -223,11 +193,13 @@
self.tracewrites = tracewrites
super(UStringIO, self).__init__(*args, **kwargs)
- def __nonzero__(self):
+ def __bool__(self):
return True
+ __nonzero__ = __bool__
+
def write(self, value):
- assert isinstance(value, unicode), u"unicode required not %s : %s"\
+ assert isinstance(value, text_type), u"unicode required not %s : %s"\
% (type(value).__name__, repr(value))
if self.tracewrites:
from traceback import format_stack
@@ -553,9 +525,9 @@
def _dict2js(d, predictable=False):
if predictable:
- it = sorted(d.iteritems())
+ it = sorted(d.items())
else:
- it = d.iteritems()
+ it = d.items()
res = [key + ': ' + js_dumps(val, predictable)
for key, val in it]
return '{%s}' % ', '.join(res)
--- a/view.py Wed Dec 09 18:42:13 2015 +0100
+++ b/view.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,12 +18,14 @@
"""abstract views and templates classes for CubicWeb web client"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from io import BytesIO
from warnings import warn
from functools import partial
+from six.moves import range
+
from logilab.common.deprecation import deprecated
from logilab.common.registry import yes
from logilab.mtconverter import xml_escape
@@ -173,7 +175,7 @@
# specific view
if rset.rowcount != 1:
kwargs.setdefault('initargs', self.cw_extra_kwargs)
- for i in xrange(len(rset)):
+ for i in range(len(rset)):
if wrap:
self.w(u'<div class="section">')
self.wview(self.__regid__, rset, row=i, **kwargs)
@@ -213,7 +215,7 @@
return self._cw.build_url('view', vid=self.__regid__)
coltypes = rset.column_types(0)
if len(coltypes) == 1:
- etype = iter(coltypes).next()
+ etype = next(iter(coltypes))
if not self._cw.vreg.schema.eschema(etype).final:
if len(rset) == 1:
entity = rset.get_entity(0, 0)
@@ -281,7 +283,7 @@
else :
etypes = rset.column_types(0)
if len(etypes) == 1:
- etype = iter(etypes).next()
+ etype = next(iter(etypes))
clabel = display_name(self._cw, etype, 'plural')
else :
clabel = u'#[*] (%s)' % vtitle
@@ -394,7 +396,7 @@
if rset is None:
rset = self.cw_rset = self._cw.execute(self.startup_rql())
if rset:
- for i in xrange(len(rset)):
+ for i in range(len(rset)):
self.wview(self.__regid__, rset, row=i, **kwargs)
else:
self.no_entities(**kwargs)
--- a/web/__init__.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/__init__.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,10 +20,9 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
-from urllib import quote as urlquote
-
+from six.moves.urllib.parse import quote as urlquote
from logilab.common.deprecation import deprecated
from cubicweb.web._exceptions import *
--- a/web/_exceptions.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/_exceptions.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,7 +20,7 @@
__docformat__ = "restructuredtext en"
-import httplib
+from six.moves import http_client
from cubicweb._exceptions import *
from cubicweb.utils import json_dumps
@@ -41,7 +41,7 @@
"""base class for publishing related exception"""
def __init__(self, *args, **kwargs):
- self.status = kwargs.pop('status', httplib.OK)
+ self.status = kwargs.pop('status', http_client.OK)
super(PublishException, self).__init__(*args, **kwargs)
class LogOut(PublishException):
@@ -52,7 +52,7 @@
class Redirect(PublishException):
"""raised to redirect the http request"""
- def __init__(self, location, status=httplib.SEE_OTHER):
+ def __init__(self, location, status=http_client.SEE_OTHER):
super(Redirect, self).__init__(status=status)
self.location = location
@@ -71,7 +71,7 @@
"""raised when a request can't be served because of a bad input"""
def __init__(self, *args, **kwargs):
- kwargs.setdefault('status', httplib.BAD_REQUEST)
+ kwargs.setdefault('status', http_client.BAD_REQUEST)
super(RequestError, self).__init__(*args, **kwargs)
@@ -79,14 +79,14 @@
"""raised when an edit request doesn't specify any eid to edit"""
def __init__(self, *args, **kwargs):
- kwargs.setdefault('status', httplib.BAD_REQUEST)
+ kwargs.setdefault('status', http_client.BAD_REQUEST)
super(NothingToEdit, self).__init__(*args, **kwargs)
class ProcessFormError(RequestError):
"""raised when posted data can't be processed by the corresponding field
"""
def __init__(self, *args, **kwargs):
- kwargs.setdefault('status', httplib.BAD_REQUEST)
+ kwargs.setdefault('status', http_client.BAD_REQUEST)
super(ProcessFormError, self).__init__(*args, **kwargs)
class NotFound(RequestError):
@@ -94,13 +94,13 @@
a 404 error should be returned"""
def __init__(self, *args, **kwargs):
- kwargs.setdefault('status', httplib.NOT_FOUND)
+ kwargs.setdefault('status', http_client.NOT_FOUND)
super(NotFound, self).__init__(*args, **kwargs)
class RemoteCallFailed(RequestError):
"""raised when a json remote call fails
"""
- def __init__(self, reason='', status=httplib.INTERNAL_SERVER_ERROR):
+ def __init__(self, reason='', status=http_client.INTERNAL_SERVER_ERROR):
super(RemoteCallFailed, self).__init__(reason, status=status)
self.reason = reason
--- a/web/action.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/action.py Thu Dec 10 12:34:15 2015 +0100
@@ -33,7 +33,7 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from cubicweb import target
from cubicweb.predicates import (partial_relation_possible, match_search_state,
@@ -91,7 +91,7 @@
"""base class for actions consisting to create a new object with an initial
relation set to an entity.
- Additionaly to EntityAction behaviour, this class is parametrized using
+ Additionally to EntityAction behaviour, this class is parametrized using
.rtype, .role and .target_etype attributes to check if the action apply and
if the logged user has access to it (see
:class:`~cubicweb.selectors.partial_relation_possible` selector
@@ -111,4 +111,3 @@
return self._cw.vreg["etypes"].etype_class(ttype).cw_create_url(self._cw,
__redirectpath=entity.rest_path(), __linkto=linkto,
__redirectvid=self._cw.form.get('__redirectvid', ''))
-
--- a/web/application.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/application.py Thu Dec 10 12:34:15 2015 +0100
@@ -25,7 +25,8 @@
from warnings import warn
import json
-import httplib
+from six import text_type, binary_type
+from six.moves import http_client
from logilab.common.deprecation import deprecated
@@ -68,8 +69,8 @@
def __init__(self, appli):
self.repo = appli.repo
self.vreg = appli.vreg
- self.session_manager = self.vreg['components'].select('sessionmanager',
- repo=self.repo)
+ self.session_manager = self.vreg['sessions'].select('sessionmanager',
+ repo=self.repo)
global SESSION_MANAGER
SESSION_MANAGER = self.session_manager
if self.vreg.config.mode != 'test':
@@ -80,8 +81,8 @@
def reset_session_manager(self):
data = self.session_manager.dump_data()
- self.session_manager = self.vreg['components'].select('sessionmanager',
- repo=self.repo)
+ self.session_manager = self.vreg['sessions'].select('sessionmanager',
+ repo=self.repo)
self.session_manager.restore_data(data)
global SESSION_MANAGER
SESSION_MANAGER = self.session_manager
@@ -256,7 +257,7 @@
# activate realm-based auth
realm = self.vreg.config['realm']
req.set_header('WWW-Authenticate', [('Basic', {'realm' : realm })], raw=False)
- content = ''
+ content = b''
try:
try:
session = self.get_session(req)
@@ -290,7 +291,7 @@
if self.vreg.config['auth-mode'] == 'cookie' and ex.url:
req.headers_out.setHeader('location', str(ex.url))
if ex.status is not None:
- req.status_out = httplib.SEE_OTHER
+ req.status_out = http_client.SEE_OTHER
# When the authentification is handled by http we must
# explicitly ask for authentification to flush current http
# authentification information
@@ -310,23 +311,24 @@
# the request does not use https, redirect to login form
https_url = self.vreg.config['https-url']
if https_url and req.base_url() != https_url:
- req.status_out = httplib.SEE_OTHER
+ req.status_out = http_client.SEE_OTHER
req.headers_out.setHeader('location', https_url + 'login')
else:
# We assume here that in http auth mode the user *May* provide
# Authentification Credential if asked kindly.
if self.vreg.config['auth-mode'] == 'http':
- req.status_out = httplib.UNAUTHORIZED
+ req.status_out = http_client.UNAUTHORIZED
# In the other case (coky auth) we assume that there is no way
# for the user to provide them...
# XXX But WHY ?
else:
- req.status_out = httplib.FORBIDDEN
+ req.status_out = http_client.FORBIDDEN
# If previous error handling already generated a custom content
# do not overwrite it. This is used by LogOut Except
# XXX ensure we don't actually serve content
if not content:
content = self.need_login_content(req)
+ assert isinstance(content, binary_type)
return content
@@ -368,7 +370,7 @@
except cors.CORSPreflight:
# Return directly an empty 200
req.status_out = 200
- result = ''
+ result = b''
except StatusResponse as ex:
warn('[3.16] StatusResponse is deprecated use req.status_out',
DeprecationWarning, stacklevel=2)
@@ -394,12 +396,12 @@
except Unauthorized as ex:
req.data['errmsg'] = req._('You\'re not authorized to access this page. '
'If you think you should, please contact the site administrator.')
- req.status_out = httplib.FORBIDDEN
+ req.status_out = http_client.FORBIDDEN
result = self.error_handler(req, ex, tb=False)
except Forbidden as ex:
req.data['errmsg'] = req._('This action is forbidden. '
'If you think it should be allowed, please contact the site administrator.')
- req.status_out = httplib.FORBIDDEN
+ req.status_out = http_client.FORBIDDEN
result = self.error_handler(req, ex, tb=False)
except (BadRQLQuery, RequestError) as ex:
result = self.error_handler(req, ex, tb=False)
@@ -413,7 +415,7 @@
raise
### Last defense line
except BaseException as ex:
- req.status_out = httplib.INTERNAL_SERVER_ERROR
+ req.status_out = http_client.INTERNAL_SERVER_ERROR
result = self.error_handler(req, ex, tb=True)
finally:
if req.cnx and not commited:
@@ -437,7 +439,7 @@
req.headers_out.setHeader('location', str(ex.location))
assert 300 <= ex.status < 400
req.status_out = ex.status
- return ''
+ return b''
def validation_error_handler(self, req, ex):
ex.translate(req._) # translate messages using ui language
@@ -453,9 +455,9 @@
# messages.
location = req.form['__errorurl'].rsplit('#', 1)[0]
req.headers_out.setHeader('location', str(location))
- req.status_out = httplib.SEE_OTHER
- return ''
- req.status_out = httplib.CONFLICT
+ req.status_out = http_client.SEE_OTHER
+ return b''
+ req.status_out = http_client.CONFLICT
return self.error_handler(req, ex, tb=False)
def error_handler(self, req, ex, tb=False):
@@ -491,14 +493,14 @@
def ajax_error_handler(self, req, ex):
req.set_header('content-type', 'application/json')
- status = httplib.INTERNAL_SERVER_ERROR
+ status = http_client.INTERNAL_SERVER_ERROR
if isinstance(ex, PublishException) and ex.status is not None:
status = ex.status
if req.status_out < 400:
# don't overwrite it if it's already set
req.status_out = status
- json_dumper = getattr(ex, 'dumps', lambda : json.dumps({'reason': unicode(ex)}))
- return json_dumper()
+ json_dumper = getattr(ex, 'dumps', lambda : json.dumps({'reason': text_type(ex)}))
+ return json_dumper().encode('utf-8')
# special case handling
--- a/web/box.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/box.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,9 @@
"""abstract box classes for CubicWeb web client"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
+
+from six import add_metaclass
from logilab.mtconverter import xml_escape
from logilab.common.deprecation import class_deprecated, class_renamed
@@ -41,7 +43,7 @@
actions_by_cat.setdefault(action.category, []).append(
(action.title, action) )
for key, values in actions_by_cat.items():
- actions_by_cat[key] = [act for title, act in sorted(values)]
+ actions_by_cat[key] = [act for title, act in sorted(values, key=lambda x: x[0])]
if categories_in_order:
for cat in categories_in_order:
if cat in actions_by_cat:
@@ -53,6 +55,7 @@
# old box system, deprecated ###################################################
+@add_metaclass(class_deprecated)
class BoxTemplate(View):
"""base template for boxes, usually a (contextual) list of possible
actions. Various classes attributes may be used to control the box
@@ -66,7 +69,6 @@
box.render(self.w)
"""
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.10] *BoxTemplate classes are deprecated, use *CtxComponent instead (%(cls)s)'
__registry__ = 'ctxcomponents'
@@ -193,4 +195,3 @@
AjaxEditRelationBoxTemplate = class_renamed(
'AjaxEditRelationBoxTemplate', AjaxEditRelationCtxComponent,
'[3.10] AjaxEditRelationBoxTemplate has been renamed to AjaxEditRelationCtxComponent (%(cls)s)')
-
--- a/web/captcha.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/captcha.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,7 +22,9 @@
__docformat__ = "restructuredtext en"
from random import randint, choice
-from cStringIO import StringIO
+from io import BytesIO
+
+from six.moves import range
from PIL import Image, ImageFont, ImageDraw, ImageFilter
@@ -51,7 +53,7 @@
draw = ImageDraw.Draw(img)
# draw 100 random colored boxes on the background
x, y = img.size
- for num in xrange(100):
+ for num in range(100):
draw.rectangle((randint(0, x), randint(0, y),
randint(0, x), randint(0, y)),
fill=randint(0, 0xffffff))
@@ -67,7 +69,7 @@
"""
text = u''.join(choice('QWERTYUOPASDFGHJKLZXCVBNM') for i in range(size))
img = pil_captcha(text, fontfile, fontsize)
- out = StringIO()
+ out = BytesIO()
img.save(out, format)
out.seek(0)
return text, out
--- a/web/component.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/component.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,10 +20,12 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from warnings import warn
+from six import PY3, add_metaclass, text_type
+
from logilab.common.deprecation import class_deprecated, class_renamed, deprecated
from logilab.mtconverter import xml_escape
@@ -215,6 +217,9 @@
def __unicode__(self):
return tags.a(self.label, href=self.href, **self.attrs)
+ if PY3:
+ __str__ = __unicode__
+
def render(self, w):
w(tags.a(self.label, href=self.href, **self.attrs))
@@ -425,7 +430,7 @@
@property
def domid(self):
- return domid(self.__regid__) + unicode(self.entity.eid)
+ return domid(self.__regid__) + text_type(self.entity.eid)
def lazy_view_holder(self, w, entity, oid, registry='views'):
"""add a holder and return a URL that may be used to replace this
@@ -498,7 +503,7 @@
args['subject'],
args['object'])
return u'[<a href="javascript: %s" class="action">%s</a>] %s' % (
- xml_escape(unicode(jscall)), label, etarget.view('incontext'))
+ xml_escape(text_type(jscall)), label, etarget.view('incontext'))
def related_boxitems(self, entity):
return [self.box_item(entity, etarget, 'delete_relation', u'-')
@@ -515,7 +520,7 @@
"""returns the list of unrelated entities, using the entity's
appropriate vocabulary function
"""
- skip = set(unicode(e.eid) for e in entity.related(self.rtype, role(self),
+ skip = set(text_type(e.eid) for e in entity.related(self.rtype, role(self),
entities=True))
skip.add(None)
skip.add(INTERNAL_FIELD_VALUE)
@@ -571,7 +576,7 @@
# to be defined in concrete classes
rtype = role = target_etype = None
- # class attributes below *must* be set in concrete classes (additionaly to
+ # class attributes below *must* be set in concrete classes (additionally to
# rtype / role [/ target_etype]. They should correspond to js_* methods on
# the json controller
@@ -633,7 +638,7 @@
if maydel:
if not js_css_added:
js_css_added = self.add_js_css()
- jscall = unicode(js.ajaxBoxRemoveLinkedEntity(
+ jscall = text_type(js.ajaxBoxRemoveLinkedEntity(
self.__regid__, entity.eid, rentity.eid,
self.fname_remove,
self.removed_msg and _(self.removed_msg)))
@@ -648,7 +653,7 @@
if mayadd:
multiple = self.rdef.role_cardinality(self.role) in '*+'
w(u'<table><tr><td>')
- jscall = unicode(js.ajaxBoxShowSelector(
+ jscall = text_type(js.ajaxBoxShowSelector(
self.__regid__, entity.eid, self.fname_vocabulary,
self.fname_validate, self.added_msg and _(self.added_msg),
_(stdmsgs.BUTTON_OK[0]), _(stdmsgs.BUTTON_CANCEL[0]),
@@ -677,6 +682,7 @@
# old contextual components, deprecated ########################################
+@add_metaclass(class_deprecated)
class EntityVComponent(Component):
"""abstract base class for additinal components displayed in content
headers and footer according to:
@@ -687,7 +693,6 @@
it should be configured using .accepts, .etype, .rtype, .target and
.context class attributes
"""
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.10] *VComponent classes are deprecated, use *CtxComponent instead (%(cls)s)'
__registry__ = 'ctxcomponents'
--- a/web/controller.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/controller.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,6 +19,8 @@
__docformat__ = "restructuredtext en"
+from six import PY2
+
from logilab.mtconverter import xml_escape
from logilab.common.registry import yes
from logilab.common.deprecation import deprecated
@@ -87,7 +89,7 @@
rql = req.form.get('rql')
if rql:
req.ensure_ro_rql(rql)
- if not isinstance(rql, unicode):
+ if PY2 and not isinstance(rql, unicode):
rql = unicode(rql, req.encoding)
pp = req.vreg['components'].select_or_none('magicsearch', req)
if pp is not None:
@@ -132,8 +134,6 @@
newparams['_cwmsgid'] = self._cw.set_redirect_message(msg)
if '__action_apply' in self._cw.form:
self._return_to_edition_view(newparams)
- if '__action_cancel' in self._cw.form:
- self._return_to_lastpage(newparams)
else:
self._return_to_original_view(newparams)
@@ -155,7 +155,7 @@
and '_cwmsgid' in newparams):
# are we here on creation or modification?
if any(eid == self._edited_entity.eid
- for eid in self._cw.data.get('eidmap', {}).itervalues()):
+ for eid in self._cw.data.get('eidmap', {}).values()):
msg = self._cw._('click here to see created entity')
else:
msg = self._cw._('click here to see edited entity')
@@ -201,11 +201,9 @@
raise Redirect(self._cw.build_url(path, **newparams))
- def _return_to_lastpage(self, newparams):
- """cancel-button case: in this case we are always expecting to go back
- where we came from, and this is not easy. Currently we suppose that
- __redirectpath is specifying that place if found, else we look in the
- request breadcrumbs for the last visited page.
+ def _redirect(self, newparams):
+ """Raise a redirect. We use __redirectpath if it specified, else we
+ return to the home page.
"""
if '__redirectpath' in self._cw.form:
# if redirect path was explicitly specified in the form, use it
@@ -213,7 +211,7 @@
url = self._cw.build_url(path)
url = append_url_params(url, self._cw.form.get('__redirectparams'))
else:
- url = self._cw.last_visited_page()
+ url = self._cw.base_url()
# The newparams must update the params in all cases
url = self._cw.rebuild_url(url, **newparams)
raise Redirect(url)
@@ -221,4 +219,3 @@
from cubicweb import set_log_methods
set_log_methods(Controller, LOGGER)
-
--- a/web/cors.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/cors.py Thu Dec 10 12:34:15 2015 +0100
@@ -14,7 +14,7 @@
"""
-import urlparse
+from six.moves.urllib.parse import urlsplit
from cubicweb.web import LOGGER
info = LOGGER.info
@@ -37,7 +37,7 @@
In case of non-compliance, no CORS-related header is set.
"""
- base_url = urlparse.urlsplit(req.base_url())
+ base_url = urlsplit(req.base_url())
expected_host = '://'.join((base_url.scheme, base_url.netloc))
if not req.get_header('Origin') or req.get_header('Origin') == expected_host:
# not a CORS request, nothing to do
@@ -50,7 +50,7 @@
process_preflight(req, config)
else: # Simple CORS or actual request
process_simple(req, config)
- except CORSFailed, exc:
+ except CORSFailed as exc:
info('Cross origin resource sharing failed: %s' % exc)
except CORSPreflight:
info('Cross origin resource sharing: valid Preflight request %s')
@@ -101,7 +101,7 @@
if '*' not in allowed_origins and origin not in allowed_origins:
raise CORSFailed('Origin is not allowed')
# bit of sanity check; see "6.3 Security"
- myhost = urlparse.urlsplit(req.base_url()).netloc
+ myhost = urlsplit(req.base_url()).netloc
host = req.get_header('Host')
if host != myhost:
info('cross origin resource sharing detected possible '
@@ -111,4 +111,3 @@
# include "Vary: Origin" header (see 6.4)
req.headers_out.addHeader('Vary', 'Origin')
return origin
-
--- a/web/data/cubicweb.edition.js Wed Dec 09 18:42:13 2015 +0100
+++ b/web/data/cubicweb.edition.js Thu Dec 10 12:34:15 2015 +0100
@@ -537,6 +537,24 @@
}
/**
+ * Cancel the operations done on the given form.
+ *
+ */
+$(function () {
+ $(document).on('click', '.cwjs-edition-cancel', function (evt) {
+ var $mynode = $(evt.currentTarget),
+ $form = $mynode.closest('form'),
+ $error = $form.find(':input[name="__errorurl"]'),
+ errorurl = $error.attr('value'),
+ args = ajaxFuncArgs('cancel_edition', null, errorurl);
+ loadRemote(AJAX_BASE_URL, args, 'POST', true);
+ history.back();
+ return false;
+ });
+});
+
+
+/**
* .. function:: validateForm(formid, action, onsuccess, onfailure)
*
* called on traditionnal form submission : the idea is to try
--- a/web/facet.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/facet.py Thu Dec 10 12:34:15 2015 +0100
@@ -50,13 +50,15 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from functools import reduce
from warnings import warn
from copy import deepcopy
from datetime import datetime, timedelta
+from six import text_type, string_types
+
from logilab.mtconverter import xml_escape
from logilab.common.graph import has_path
from logilab.common.decorators import cached, cachedproperty
@@ -80,7 +82,7 @@
ptypes = facet.cw_rset.column_types(0)
if len(ptypes) == 1:
return display_name(facet._cw, facet.rtype, form=facet.role,
- context=iter(ptypes).next())
+ context=next(iter(ptypes)))
return display_name(facet._cw, facet.rtype, form=facet.role)
def get_facet(req, facetid, select, filtered_variable):
@@ -133,7 +135,7 @@
or the first variable selected in column 0
"""
if mainvar is None:
- vref = select.selection[0].iget_nodes(nodes.VariableRef).next()
+ vref = next(select.selection[0].iget_nodes(nodes.VariableRef))
return vref.variable
return select.defined_vars[mainvar]
@@ -156,7 +158,7 @@
for term in select.selection[:]:
select.remove_selected(term)
# remove unbound variables which only have some type restriction
- for dvar in list(select.defined_vars.itervalues()):
+ for dvar in list(select.defined_vars.values()):
if not (dvar is filtered_variable or dvar.stinfo['relations']):
select.undefine_variable(dvar)
# global tree config: DISTINCT, LIMIT, OFFSET
@@ -305,7 +307,7 @@
# optional relation
return ovar
if all(rdef.cardinality[cardidx] in '1+'
- for rdef in rschema.rdefs.itervalues()):
+ for rdef in rschema.rdefs.values()):
# mandatory relation without any restriction on the other variable
for orel in ovar.stinfo['relations']:
if rel is orel:
@@ -670,7 +672,7 @@
insert_attr_select_relation(
select, self.filtered_variable, self.rtype, self.role,
self.target_attr, select_target_entity=False)
- values = [unicode(x) for x, in self.rqlexec(select.as_string())]
+ values = [text_type(x) for x, in self.rqlexec(select.as_string())]
except Exception:
self.exception('while computing values for %s', self)
return []
@@ -719,14 +721,14 @@
def rset_vocabulary(self, rset):
if self.i18nable:
- _ = self._cw._
+ tr = self._cw._
else:
- _ = unicode
+ tr = text_type
if self.rql_sort:
- values = [(_(label), eid) for eid, label in rset]
+ values = [(tr(label), eid) for eid, label in rset]
else:
if self.label_vid is None:
- values = [(_(label), eid) for eid, label in rset]
+ values = [(tr(label), eid) for eid, label in rset]
else:
values = [(entity.view(self.label_vid), entity.eid)
for entity in rset.entities()]
@@ -754,7 +756,7 @@
# XXX handle rel is None case in RQLPathFacet?
if self.restr_attr != 'eid':
self.select.set_distinct(True)
- if isinstance(value, basestring):
+ if isinstance(value, string_types):
# only one value selected
if value:
self.select.add_constant_restriction(
@@ -808,7 +810,7 @@
rschema = self._cw.vreg.schema.rschema(self.rtype)
# XXX when called via ajax, no rset to compute possible types
possibletypes = self.cw_rset and self.cw_rset.column_types(0)
- for rdef in rschema.rdefs.itervalues():
+ for rdef in rschema.rdefs.values():
if possibletypes is not None:
if self.role == 'subject':
if rdef.subject not in possibletypes:
@@ -829,13 +831,13 @@
if self._cw.vreg.schema.rschema(self.rtype).final:
return False
if self.role == 'object':
- subj = utils.rqlvar_maker(defined=self.select.defined_vars,
- aliases=self.select.aliases).next()
+ subj = next(utils.rqlvar_maker(defined=self.select.defined_vars,
+ aliases=self.select.aliases))
obj = self.filtered_variable.name
else:
subj = self.filtered_variable.name
- obj = utils.rqlvar_maker(defined=self.select.defined_vars,
- aliases=self.select.aliases).next()
+ obj = next(utils.rqlvar_maker(defined=self.select.defined_vars,
+ aliases=self.select.aliases))
restrictions = []
if self.select.where:
restrictions.append(self.select.where.as_string())
@@ -916,15 +918,13 @@
def rset_vocabulary(self, rset):
if self.i18nable:
- _ = self._cw._
+ tr = self._cw._
else:
- _ = unicode
+ tr = text_type
if self.rql_sort:
- return [(_(value), value) for value, in rset]
- values = [(_(value), value) for value, in rset]
- if self.sortasc:
- return sorted(values)
- return reversed(sorted(values))
+ return [(tr(value), value) for value, in rset]
+ values = [(tr(value), value) for value, in rset]
+ return sorted(values, reverse=not self.sortasc)
class AttributeFacet(RelationAttributeFacet):
@@ -1073,7 +1073,7 @@
assert self.path and isinstance(self.path, (list, tuple)), \
'path should be a list of 3-uples, not %s' % self.path
for part in self.path:
- if isinstance(part, basestring):
+ if isinstance(part, string_types):
part = part.split()
assert len(part) == 3, \
'path should be a list of 3-uples, not %s' % part
@@ -1126,7 +1126,7 @@
cleanup_select(select, self.filtered_variable)
varmap, restrvar = self.add_path_to_select(skiplabel=True)
select.append_selected(nodes.VariableRef(restrvar))
- values = [unicode(x) for x, in self.rqlexec(select.as_string())]
+ values = [text_type(x) for x, in self.rqlexec(select.as_string())]
except Exception:
self.exception('while computing values for %s', self)
return []
@@ -1149,7 +1149,7 @@
varmap = {'X': self.filtered_variable}
actual_filter_variable = None
for part in self.path:
- if isinstance(part, basestring):
+ if isinstance(part, string_types):
part = part.split()
subject, rtype, object = part
if skiplabel and object == self.label_variable:
@@ -1165,7 +1165,7 @@
if len(attrtypes) > 1:
raise Exception('ambigous attribute %s, specify attrtype on %s'
% (rtype, self.__class__))
- self.restr_attr_type = iter(attrtypes).next()
+ self.restr_attr_type = next(iter(attrtypes))
if skipattrfilter:
actual_filter_variable = subject
continue
@@ -1253,7 +1253,7 @@
rset = self._range_rset()
if rset:
minv, maxv = rset[0]
- return [(unicode(minv), minv), (unicode(maxv), maxv)]
+ return [(text_type(minv), minv), (text_type(maxv), maxv)]
return []
def possible_values(self):
@@ -1272,7 +1272,7 @@
def formatvalue(self, value):
"""format `value` before in order to insert it in the RQL query"""
- return unicode(value)
+ return text_type(value)
def infvalue(self, min=False):
if min:
@@ -1373,7 +1373,7 @@
# *list* (see rqlexec implementation)
if rset:
minv, maxv = rset[0]
- return [(unicode(minv), minv), (unicode(maxv), maxv)]
+ return [(text_type(minv), minv), (text_type(maxv), maxv)]
return []
@@ -1392,7 +1392,7 @@
skiplabel=True, skipattrfilter=True)
restrel = None
for part in self.path:
- if isinstance(part, basestring):
+ if isinstance(part, string_types):
part = part.split()
subject, rtype, object = part
if object == self.filter_variable:
@@ -1516,7 +1516,7 @@
if not val or val & mask])
def possible_values(self):
- return [unicode(val) for label, val in self.vocabulary()]
+ return [text_type(val) for label, val in self.vocabulary()]
## html widets ################################################################
@@ -1595,7 +1595,7 @@
if selected:
cssclass += ' facetValueSelected'
w(u'<div class="%s" cubicweb:value="%s">\n'
- % (cssclass, xml_escape(unicode(value))))
+ % (cssclass, xml_escape(text_type(value))))
# If it is overflowed one must add padding to compensate for the vertical
# scrollbar; given current css values, 4 blanks work perfectly ...
padding = u' ' * self.scrollbar_padding_factor if overflow else u''
@@ -1754,7 +1754,7 @@
imgsrc = self._cw.data_url(self.unselected_img)
imgalt = self._cw._('not selected')
w(u'<div class="%s" cubicweb:value="%s">\n'
- % (cssclass, xml_escape(unicode(self.value))))
+ % (cssclass, xml_escape(text_type(self.value))))
w(u'<div>')
w(u'<img src="%s" alt="%s" cubicweb:unselimg="true" /> ' % (imgsrc, imgalt))
w(u'<label class="facetTitle" cubicweb:facetName="%s">%s</label>'
--- a/web/form.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/form.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,6 +20,8 @@
from warnings import warn
+from six import add_metaclass
+
from logilab.common.decorators import iclassmethod
from logilab.common.deprecation import deprecated
@@ -74,8 +76,8 @@
found
"""
+@add_metaclass(metafieldsform)
class Form(AppObject):
- __metaclass__ = metafieldsform
__registry__ = 'forms'
parent_form = None
@@ -120,7 +122,7 @@
extrakw = {}
# search for navigation parameters and customization of existing
# attributes; remaining stuff goes in extrakwargs
- for key, val in kwargs.iteritems():
+ for key, val in kwargs.items():
if key in controller.NAV_FORM_PARAMETERS:
hiddens.append( (key, val) )
elif key == 'redirect_path':
@@ -280,4 +282,3 @@
def remaining_errors(self):
return sorted(self.form_valerror.errors.items())
-
--- a/web/formfields.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/formfields.py Thu Dec 10 12:34:15 2015 +0100
@@ -66,6 +66,8 @@
from warnings import warn
from datetime import datetime, timedelta
+from six import PY2, text_type, string_types
+
from logilab.mtconverter import xml_escape
from logilab.common import nullobject
from logilab.common.date import ustrftime
@@ -159,7 +161,7 @@
:attr:`order`
key used by automatic forms to sort fields
:attr:`ignore_req_params`
- when true, this field won't consider value potentialy specified using
+ when true, this field won't consider value potentially specified using
request's form parameters (eg you won't be able to specify a value using for
instance url like http://mywebsite.com/form?field=value)
@@ -231,11 +233,14 @@
def __unicode__(self):
return self.as_string(False)
- def __str__(self):
- return self.as_string(False).encode('UTF8')
+ if PY2:
+ def __str__(self):
+ return self.as_string(False).encode('UTF8')
+ else:
+ __str__ = __unicode__
def __repr__(self):
- return self.as_string(True).encode('UTF8')
+ return self.as_string(True)
def init_widget(self, widget):
if widget is not None:
@@ -279,7 +284,7 @@
return u''
if value is True:
return u'1'
- return unicode(value)
+ return text_type(value)
def get_widget(self, form):
"""return the widget instance associated to this field"""
@@ -381,7 +386,7 @@
assert self.choices is not None
if callable(self.choices):
# pylint: disable=E1102
- if getattr(self.choices, 'im_self', None) is self:
+ if getattr(self.choices, '__self__', None) is self:
vocab = self.choices(form=form, **kwargs)
else:
vocab = self.choices(form=form, field=self, **kwargs)
@@ -508,7 +513,7 @@
class StringField(Field):
"""Use this field to edit unicode string (`String` yams type). This field
- additionaly support a `max_length` attribute that specify a maximum size for
+ additionally support a `max_length` attribute that specify a maximum size for
the string (`None` meaning no limit).
Unless explicitly specified, the widget for this field will be:
@@ -780,7 +785,7 @@
If the stream format is one of text/plain, text/html, text/rest,
text/markdown
- then a :class:`~cubicweb.web.formwidgets.TextArea` will be additionaly
+ then a :class:`~cubicweb.web.formwidgets.TextArea` will be additionally
displayed, allowing to directly the file's content when desired, instead
of choosing a file from user's file system.
"""
@@ -794,7 +799,7 @@
if data:
encoding = self.encoding(form)
try:
- form.formvalues[(self, form)] = unicode(data.getvalue(), encoding)
+ form.formvalues[(self, form)] = data.getvalue().decode(encoding)
except UnicodeError:
pass
else:
@@ -815,7 +820,7 @@
def _process_form_value(self, form):
value = form._cw.form.get(self.input_name(form))
- if isinstance(value, unicode):
+ if isinstance(value, text_type):
# file modified using a text widget
return Binary(value.encode(self.encoding(form)))
return super(EditableFileField, self)._process_form_value(form)
@@ -823,7 +828,7 @@
class BigIntField(Field):
"""Use this field to edit big integers (`BigInt` yams type). This field
- additionaly support `min` and `max` attributes that specify a minimum and/or
+ additionally support `min` and `max` attributes that specify a minimum and/or
maximum value for the integer (`None` meaning no boundary).
Unless explicitly specified, the widget for this field will be a
@@ -842,7 +847,7 @@
self.widget.attrs.setdefault('size', self.default_text_input_size)
def _ensure_correctly_typed(self, form, value):
- if isinstance(value, basestring):
+ if isinstance(value, string_types):
value = value.strip()
if not value:
return None
@@ -907,7 +912,7 @@
class FloatField(IntField):
- """Use this field to edit floats (`Float` yams type). This field additionaly
+ """Use this field to edit floats (`Float` yams type). This field additionally
support `min` and `max` attributes as the
:class:`~cubicweb.web.formfields.IntField`.
@@ -924,7 +929,7 @@
return self.format_single_value(req, 1.234)
def _ensure_correctly_typed(self, form, value):
- if isinstance(value, basestring):
+ if isinstance(value, string_types):
value = value.strip()
if not value:
return None
@@ -946,7 +951,7 @@
def format_single_value(self, req, value):
if value:
value = format_time(value.days * 24 * 3600 + value.seconds)
- return unicode(value)
+ return text_type(value)
return u''
def example_format(self, req):
@@ -956,7 +961,7 @@
return u'20s, 10min, 24h, 4d'
def _ensure_correctly_typed(self, form, value):
- if isinstance(value, basestring):
+ if isinstance(value, string_types):
value = value.strip()
if not value:
return None
@@ -986,14 +991,14 @@
return self.format_single_value(req, datetime.now())
def _ensure_correctly_typed(self, form, value):
- if isinstance(value, basestring):
+ if isinstance(value, string_types):
value = value.strip()
if not value:
return None
try:
value = form._cw.parse_datetime(value, self.etype)
except ValueError as ex:
- raise ProcessFormError(unicode(ex))
+ raise ProcessFormError(text_type(ex))
return value
@@ -1083,7 +1088,7 @@
linkedto = form.linked_to.get((self.name, self.role))
if linkedto:
buildent = form._cw.entity_from_eid
- return [(buildent(eid).view('combobox'), unicode(eid))
+ return [(buildent(eid).view('combobox'), text_type(eid))
for eid in linkedto]
return []
@@ -1095,7 +1100,7 @@
# vocabulary doesn't include current values, add them
if form.edited_entity.has_eid():
rset = form.edited_entity.related(self.name, self.role)
- vocab += [(e.view('combobox'), unicode(e.eid))
+ vocab += [(e.view('combobox'), text_type(e.eid))
for e in rset.entities()]
return vocab
@@ -1129,11 +1134,11 @@
if entity.eid in done:
continue
done.add(entity.eid)
- res.append((entity.view('combobox'), unicode(entity.eid)))
+ res.append((entity.view('combobox'), text_type(entity.eid)))
return res
def format_single_value(self, req, value):
- return unicode(value)
+ return text_type(value)
def process_form_value(self, form):
"""process posted form and return correctly typed value"""
--- a/web/formwidgets.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/formwidgets.py Thu Dec 10 12:34:15 2015 +0100
@@ -99,6 +99,8 @@
from datetime import date
from warnings import warn
+from six import text_type, string_types
+
from logilab.mtconverter import xml_escape
from logilab.common.deprecation import deprecated
from logilab.common.date import todatetime
@@ -282,7 +284,7 @@
"""
posted = form._cw.form
val = posted.get(field.input_name(form, self.suffix))
- if isinstance(val, basestring):
+ if isinstance(val, string_types):
val = val.strip()
return val
@@ -416,7 +418,7 @@
lines = value.splitlines()
linecount = len(lines)
for line in lines:
- linecount += len(line) / self._columns
+ linecount += len(line) // self._columns
attrs.setdefault('cols', self._columns)
attrs.setdefault('rows', min(self._maxrows, linecount + self._minrows))
return tags.textarea(value, name=field.input_name(form, self.suffix),
@@ -474,7 +476,7 @@
options.append(u'</optgroup>')
if not 'size' in attrs:
if self._multiple:
- size = unicode(min(self.default_size, len(vocab) or 1))
+ size = text_type(min(self.default_size, len(vocab) or 1))
else:
size = u'1'
attrs['size'] = size
@@ -616,7 +618,7 @@
iattrs['checked'] = u'checked'
tag = tags.input(name=field.input_name(form, self.suffix),
type=self.type, value=value, **iattrs)
- options.append(u'%s %s' % (tag, label))
+ options.append(u'<label>%s %s</label>' % (tag, xml_escape(label)))
return sep.join(options)
@@ -706,7 +708,7 @@
else:
value = self.value
attrs = self.attributes(form, field)
- attrs.setdefault('size', unicode(self.default_size))
+ attrs.setdefault('size', text_type(self.default_size))
return tags.input(name=field.input_name(form, self.suffix),
value=value, type='text', **attrs)
@@ -779,13 +781,13 @@
try:
date = todatetime(req.parse_datetime(datestr, 'Date'))
except ValueError as exc:
- raise ProcessFormError(unicode(exc))
+ raise ProcessFormError(text_type(exc))
if timestr is None:
return date
try:
time = req.parse_datetime(timestr, 'Time')
except ValueError as exc:
- raise ProcessFormError(unicode(exc))
+ raise ProcessFormError(text_type(exc))
return date.replace(hour=time.hour, minute=time.minute, second=time.second)
@@ -993,12 +995,12 @@
req = form._cw
values = {}
path = req.form.get(field.input_name(form, 'path'))
- if isinstance(path, basestring):
+ if isinstance(path, string_types):
path = path.strip()
if path is None:
path = u''
fqs = req.form.get(field.input_name(form, 'fqs'))
- if isinstance(fqs, basestring):
+ if isinstance(fqs, string_types):
fqs = fqs.strip() or None
if fqs:
for i, line in enumerate(fqs.split('\n')):
@@ -1009,7 +1011,7 @@
except ValueError:
raise ProcessFormError(req._("wrong query parameter line %s") % (i+1))
# value will be url quoted by build_url_params
- values.setdefault(key.encode(req.encoding), []).append(val)
+ values.setdefault(key, []).append(val)
if not values:
return path
return u'%s?%s' % (path, req.build_url_params(**values))
@@ -1094,4 +1096,3 @@
'<img src="%(imgsrc)s" alt="%(label)s"/>%(label)s</a>' % {
'label': label, 'imgsrc': imgsrc,
'domid': self.domid, 'href': self.href}
-
--- a/web/htmlwidgets.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/htmlwidgets.py Thu Dec 10 12:34:15 2015 +0100
@@ -24,6 +24,9 @@
import random
from math import floor
+from six import add_metaclass
+from six.moves import range
+
from logilab.mtconverter import xml_escape
from logilab.common.deprecation import class_deprecated
@@ -115,9 +118,9 @@
self.w(u'</div>')
+@add_metaclass(class_deprecated)
class SideBoxWidget(BoxWidget):
"""default CubicWeb's sidebox widget"""
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.10] class %(cls)s is deprecated'
title_class = u'sideBoxTitle'
@@ -207,9 +210,9 @@
self.w(u'</ul></div></div>')
+@add_metaclass(class_deprecated)
class BoxField(HTMLWidget):
"""couples label / value meant to be displayed in a box"""
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.10] class %(cls)s is deprecated'
def __init__(self, label, value):
self.label = label
@@ -220,18 +223,19 @@
u'<span class="value">%s</span></div></li>'
% (self.label, self.value))
+
+@add_metaclass(class_deprecated)
class BoxSeparator(HTMLWidget):
"""a menu separator"""
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.10] class %(cls)s is deprecated'
def _render(self):
self.w(u'</ul><hr class="boxSeparator"/><ul>')
+@add_metaclass(class_deprecated)
class BoxLink(HTMLWidget):
"""a link in a box"""
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.10] class %(cls)s is deprecated'
def __init__(self, href, label, _class='', title='', ident='', escape=False):
self.href = href
@@ -252,9 +256,9 @@
self.w(u'<li class="%s">%s</li>\n' % (self._class, link))
+@add_metaclass(class_deprecated)
class BoxHtml(HTMLWidget):
"""a form in a box"""
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.10] class %(cls)s is deprecated'
def __init__(self, rawhtml):
self.rawhtml = rawhtml
@@ -339,17 +343,17 @@
self.w(u'<thead>')
self.w(u'<tr class="header">')
for column in self.columns:
- attrs = ('%s="%s"' % (name, value) for name, value in column.cell_attrs.iteritems())
+ attrs = ('%s="%s"' % (name, value) for name, value in column.cell_attrs.items())
self.w(u'<th %s>%s</th>' % (' '.join(attrs), column.name or u''))
self.w(u'</tr>')
self.w(u'</thead><tbody>')
- for rowindex in xrange(len(self.model.get_rows())):
+ for rowindex in range(len(self.model.get_rows())):
klass = (rowindex%2==1) and 'odd' or 'even'
self.w(u'<tr class="%s" %s>' % (klass, self.highlight))
for column, sortvalue in self.itercols(rowindex):
attrs = dict(column.cell_attrs)
attrs["cubicweb:sortvalue"] = sortvalue
- attrs = ('%s="%s"' % (name, value) for name, value in attrs.iteritems())
+ attrs = ('%s="%s"' % (name, value) for name, value in attrs.items())
self.w(u'<td %s>' % (' '.join(attrs)))
for cellvid, colindex in column.cellrenderers:
self.model.render_cell(cellvid, rowindex, colindex, w=self.w)
@@ -361,5 +365,3 @@
def itercols(self, rowindex):
for column in self.columns:
yield column, self.model.sortvalue(rowindex, column.rset_sortcol)
-
-
--- a/web/http_headers.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/http_headers.py Thu Dec 10 12:34:15 2015 +0100
@@ -2,11 +2,14 @@
# http://twistedmatrix.com/trac/wiki/TwistedWeb2
-import types, time
+import time
from calendar import timegm
import base64
import re
-import urlparse
+
+from six import string_types
+from six.moves.urllib.parse import urlparse
+
def dashCapitalize(s):
''' Capitalize a string, making sure to treat - as a word seperator '''
@@ -295,9 +298,9 @@
cur = cur+1
if qpair:
- raise ValueError, "Missing character after '\\'"
+ raise ValueError("Missing character after '\\'")
if quoted:
- raise ValueError, "Missing end quote"
+ raise ValueError("Missing end quote")
if start != cur:
if foldCase:
@@ -347,7 +350,7 @@
##### parser utilities:
def checkSingleToken(tokens):
if len(tokens) != 1:
- raise ValueError, "Expected single token, not %s." % (tokens,)
+ raise ValueError("Expected single token, not %s." % (tokens,))
return tokens[0]
def parseKeyValue(val):
@@ -355,11 +358,11 @@
return val[0], None
elif len(val) == 3 and val[1] == Token('='):
return val[0], val[2]
- raise ValueError, "Expected key or key=value, but got %s." % (val,)
+ raise ValueError("Expected key or key=value, but got %s." % (val,))
def parseArgs(field):
args = split(field, Token(';'))
- val = args.next()
+ val = next(args)
args = [parseKeyValue(arg) for arg in args]
return val, args
@@ -380,7 +383,7 @@
def unique(seq):
'''if seq is not a string, check it's a sequence of one element and return it'''
- if isinstance(seq, basestring):
+ if isinstance(seq, string_types):
return seq
if len(seq) != 1:
raise ValueError('single value required, not %s' % seq)
@@ -398,7 +401,7 @@
"""Ensure origin is a valid URL-base stuff, or null"""
if origin == 'null':
return origin
- p = urlparse.urlparse(origin)
+ p = urlparse(origin)
if p.params or p.query or p.username or p.path not in ('', '/'):
raise ValueError('Incorrect Accept-Control-Allow-Origin value %s' % origin)
if p.scheme not in ('http', 'https'):
@@ -452,14 +455,15 @@
"""
if (value in (True, 1) or
- isinstance(value, basestring) and value.lower() == 'true'):
+ isinstance(value, string_types) and value.lower() == 'true'):
return 'true'
if (value in (False, 0) or
- isinstance(value, basestring) and value.lower() == 'false'):
+ isinstance(value, string_types) and value.lower() == 'false'):
return 'false'
raise ValueError("Invalid true/false header value: %s" % value)
class MimeType(object):
+ @classmethod
def fromString(klass, mimeTypeString):
"""Generate a MimeType object from the given string.
@@ -469,8 +473,6 @@
"""
return DefaultHTTPHandler.parse('content-type', [mimeTypeString])
- fromString = classmethod(fromString)
-
def __init__(self, mediaType, mediaSubtype, params={}, **kwargs):
"""
@type mediaType: C{str}
@@ -499,14 +501,14 @@
return "MimeType(%r, %r, %r)" % (self.mediaType, self.mediaSubtype, self.params)
def __hash__(self):
- return hash(self.mediaType)^hash(self.mediaSubtype)^hash(tuple(self.params.iteritems()))
+ return hash(self.mediaType)^hash(self.mediaSubtype)^hash(tuple(self.params.items()))
##### Specific header parsers.
def parseAccept(field):
type, args = parseArgs(field)
if len(type) != 3 or type[1] != Token('/'):
- raise ValueError, "MIME Type "+str(type)+" invalid."
+ raise ValueError("MIME Type "+str(type)+" invalid.")
# okay, this spec is screwy. A 'q' parameter is used as the separator
# between MIME parameters and (as yet undefined) additional HTTP
@@ -569,7 +571,7 @@
type, args = parseArgs(header)
if len(type) != 3 or type[1] != Token('/'):
- raise ValueError, "MIME Type "+str(type)+" invalid."
+ raise ValueError("MIME Type "+str(type)+" invalid.")
args = [(kv[0].lower(), kv[1]) for kv in args]
@@ -730,7 +732,7 @@
out ="%s/%s"%(mimeType.mediaType, mimeType.mediaSubtype)
if mimeType.params:
- out+=';'+generateKeyValues(mimeType.params.iteritems())
+ out+=';'+generateKeyValues(mimeType.params.items())
if q != 1.0:
out+=(';q=%.3f' % (q,)).rstrip('0').rstrip('.')
@@ -766,7 +768,8 @@
v = [field.strip().lower() for field in v.split(',')]
return k, v
-def generateCacheControl((k, v)):
+def generateCacheControl(args):
+ k, v = args
if v is None:
return str(k)
else:
@@ -833,7 +836,7 @@
def generateContentType(mimeType):
out = "%s/%s" % (mimeType.mediaType, mimeType.mediaSubtype)
if mimeType.params:
- out += ';' + generateKeyValues(mimeType.params.iteritems())
+ out += ';' + generateKeyValues(mimeType.params.items())
return out
def generateIfRange(dateOrETag):
@@ -854,7 +857,7 @@
try:
l = []
- for k, v in dict(challenge).iteritems():
+ for k, v in dict(challenge).items():
l.append("%s=%s" % (k, quoteString(v)))
_generated.append("%s %s" % (scheme, ", ".join(l)))
@@ -864,7 +867,7 @@
return _generated
def generateAuthorization(seq):
- return [' '.join(seq)]
+ return [' '.join(str(v) for v in seq)]
####
@@ -1326,10 +1329,10 @@
self._headers = {}
self.handler = handler
if headers is not None:
- for key, value in headers.iteritems():
+ for key, value in headers.items():
self.setHeader(key, value)
if rawHeaders is not None:
- for key, value in rawHeaders.iteritems():
+ for key, value in rawHeaders.items():
self.setRawHeaders(key, value)
def _setRawHeaders(self, headers):
@@ -1458,7 +1461,7 @@
"""Return an iterator of key, value pairs of all headers
contained in this object, as strings. The keys are capitalized
in canonical capitalization."""
- for k, v in self._raw_headers.iteritems():
+ for k, v in self._raw_headers.items():
if v is _RecalcNeeded:
v = self._toRaw(k)
yield self.canonicalNameCaps(k), v
@@ -1480,7 +1483,7 @@
is strictly an error, but we're nice.).
"""
-iteritems = lambda x: x.iteritems()
+iteritems = lambda x: x.items()
parser_general_headers = {
--- a/web/httpcache.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/httpcache.py Thu Dec 10 12:34:15 2015 +0100
@@ -31,6 +31,7 @@
def set_headers(self):
self.req.set_header('Cache-control', 'no-cache')
+ self.req.set_header('Expires', 'Sat, 01 Jan 2000 00:00:00 GMT')
class MaxAgeHTTPCacheManager(NoHTTPCacheManager):
@@ -68,7 +69,7 @@
try:
req.set_header('Etag', '"%s"' % self.etag())
except NoEtag:
- self.req.set_header('Cache-control', 'no-cache')
+ super(EtagHTTPCacheManager, self).set_headers()
return
req.set_header('Cache-control',
'must-revalidate,max-age=%s' % self.max_age())
@@ -178,4 +179,3 @@
('if-none-match', if_none_match),
#('if-modified-since', if_modified_since),
]
-
--- a/web/propertysheet.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/propertysheet.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,6 +22,8 @@
import re
import os
import os.path as osp
+import tempfile
+
TYPE_CHECKS = [('STYLESHEETS', list), ('JAVASCRIPTS', list),
('STYLESHEETS_IE', list), ('STYLESHEETS_PRINT', list),
@@ -51,13 +53,13 @@
self.clear()
self._ordered_propfiles = []
self._propfile_mtime = {}
- self._sourcefile_mtime = {}
- self._cache = {}
def load(self, fpath):
scriptglobals = self.context.copy()
scriptglobals['__file__'] = fpath
- execfile(fpath, scriptglobals, self)
+ with open(fpath, 'rb') as fobj:
+ code = compile(fobj.read(), fpath, 'exec')
+ exec(code, scriptglobals, self)
for name, type in TYPE_CHECKS:
if name in self:
if not isinstance(self[name], type):
@@ -67,10 +69,7 @@
self._ordered_propfiles.append(fpath)
def need_reload(self):
- for rid, (adirectory, rdirectory, mtime) in self._cache.items():
- if os.stat(osp.join(rdirectory, rid)).st_mtime > mtime:
- del self._cache[rid]
- for fpath, mtime in self._propfile_mtime.iteritems():
+ for fpath, mtime in self._propfile_mtime.items():
if os.stat(fpath).st_mtime > mtime:
return True
return False
@@ -86,31 +85,29 @@
self.reload()
def process_resource(self, rdirectory, rid):
+ cachefile = osp.join(self._cache_directory, rid)
+ self.debug('processing %s/%s into %s',
+ rdirectory, rid, cachefile)
+ rcachedir = osp.dirname(cachefile)
+ if not osp.exists(rcachedir):
+ os.makedirs(rcachedir)
+ sourcefile = osp.join(rdirectory, rid)
+ with open(sourcefile) as f:
+ content = f.read()
+ # XXX replace % not followed by a paren by %% to avoid having to do
+ # this in the source css file ?
try:
- return self._cache[rid][0]
- except KeyError:
- cachefile = osp.join(self._cache_directory, rid)
- self.debug('caching processed %s/%s into %s',
- rdirectory, rid, cachefile)
- rcachedir = osp.dirname(cachefile)
- if not osp.exists(rcachedir):
- os.makedirs(rcachedir)
- sourcefile = osp.join(rdirectory, rid)
- content = file(sourcefile).read()
- # XXX replace % not followed by a paren by %% to avoid having to do
- # this in the source css file ?
- try:
- content = self.compile(content)
- except ValueError as ex:
- self.error("can't process %s/%s: %s", rdirectory, rid, ex)
- adirectory = rdirectory
- else:
- stream = file(cachefile, 'w')
+ content = self.compile(content)
+ except ValueError as ex:
+ self.error("can't process %s/%s: %s", rdirectory, rid, ex)
+ adirectory = rdirectory
+ else:
+ tmpfd, tmpfile = tempfile.mkstemp(dir=rcachedir, prefix=osp.basename(cachefile))
+ with os.fdopen(tmpfd, 'w') as stream:
stream.write(content)
- stream.close()
- adirectory = self._cache_directory
- self._cache[rid] = (adirectory, rdirectory, os.stat(sourcefile).st_mtime)
- return adirectory
+ os.rename(tmpfile, cachefile)
+ adirectory = self._cache_directory
+ return adirectory
def compile(self, content):
return self._percent_rgx.sub('%%', content) % self
--- a/web/request.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/request.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,15 +22,16 @@
import time
import random
import base64
-import urllib
-from StringIO import StringIO
from hashlib import sha1 # pylint: disable=E0611
-from Cookie import SimpleCookie
from calendar import timegm
from datetime import date, datetime
-from urlparse import urlsplit
-import httplib
from warnings import warn
+from io import BytesIO
+
+from six import PY2, binary_type, text_type, string_types
+from six.moves import http_client
+from six.moves.urllib.parse import urlsplit, quote as urlquote
+from six.moves.http_cookies import SimpleCookie
from rql.utils import rqlvar_maker
@@ -41,7 +42,7 @@
from cubicweb import AuthenticationError
from cubicweb.req import RequestSessionBase
from cubicweb.uilib import remove_html_tags, js
-from cubicweb.utils import SizeConstrainedList, HTMLHead, make_uid
+from cubicweb.utils import HTMLHead, make_uid
from cubicweb.view import TRANSITIONAL_DOCTYPE_NOEXT
from cubicweb.web import (INTERNAL_FIELD_VALUE, LOGGER, NothingToEdit,
RequestError, StatusResponse)
@@ -51,7 +52,7 @@
_MARKER = object()
def build_cb_uid(seed):
- sha = sha1('%s%s%s' % (time.time(), seed, random.random()))
+ sha = sha1(('%s%s%s' % (time.time(), seed, random.random())).encode('ascii'))
return 'cb_%s' % (sha.hexdigest())
@@ -137,12 +138,12 @@
#: received headers
self._headers_in = Headers()
if headers is not None:
- for k, v in headers.iteritems():
+ for k, v in headers.items():
self._headers_in.addRawHeader(k, v)
#: form parameters
self.setup_params(form)
#: received body
- self.content = StringIO()
+ self.content = BytesIO()
# prepare output header
#: Header used for the final response
self.headers_out = Headers()
@@ -242,7 +243,7 @@
'__redirectvid', '__redirectrql'))
def setup_params(self, params):
- """WARNING: we're intentionaly leaving INTERNAL_FIELD_VALUE here
+ """WARNING: we're intentionally leaving INTERNAL_FIELD_VALUE here
subclasses should overrides to
"""
@@ -250,12 +251,13 @@
if params is None:
return
encoding = self.encoding
- for param, val in params.iteritems():
+ for param, val in params.items():
if isinstance(val, (tuple, list)):
- val = [unicode(x, encoding) for x in val]
+ if PY2:
+ val = [unicode(x, encoding) for x in val]
if len(val) == 1:
val = val[0]
- elif isinstance(val, str):
+ elif PY2 and isinstance(val, str):
val = unicode(val, encoding)
if param in self.no_script_form_params and val:
val = self.no_script_form_param(param, val)
@@ -317,7 +319,7 @@
return None
def set_message(self, msg):
- assert isinstance(msg, unicode)
+ assert isinstance(msg, text_type)
self.reset_message()
self._msg = msg
@@ -330,7 +332,7 @@
def set_redirect_message(self, msg):
# TODO - this should probably be merged with append_to_redirect_message
- assert isinstance(msg, unicode)
+ assert isinstance(msg, text_type)
msgid = self.redirect_message_id()
self.session.data[msgid] = msg
return msgid
@@ -396,26 +398,6 @@
return False
return True
- def update_breadcrumbs(self):
- """stores the last visisted page in session data"""
- searchstate = self.search_state[0]
- if searchstate == 'normal':
- breadcrumbs = self.session.data.get('breadcrumbs')
- if breadcrumbs is None:
- breadcrumbs = SizeConstrainedList(10)
- self.session.data['breadcrumbs'] = breadcrumbs
- breadcrumbs.append(self.url())
- else:
- url = self.url()
- if breadcrumbs and breadcrumbs[-1] != url:
- breadcrumbs.append(url)
-
- def last_visited_page(self):
- breadcrumbs = self.session.data.get('breadcrumbs')
- if breadcrumbs:
- return breadcrumbs.pop()
- return self.base_url()
-
# web edition helpers #####################################################
@cached # so it's writed only once
@@ -437,7 +419,7 @@
eids = form['eid']
except KeyError:
raise NothingToEdit(self._('no selected entities'))
- if isinstance(eids, basestring):
+ if isinstance(eids, string_types):
eids = (eids,)
for peid in eids:
if withtype:
@@ -569,18 +551,18 @@
header = [disposition]
unicode_filename = None
try:
- ascii_filename = filename.encode('ascii')
+ ascii_filename = filename.encode('ascii').decode('ascii')
except UnicodeEncodeError:
# fallback filename for very old browser
unicode_filename = filename
- ascii_filename = filename.encode('ascii', 'ignore')
+ ascii_filename = filename.encode('ascii', 'ignore').decode('ascii')
# escape " and \
# see http://greenbytes.de/tech/tc2231/#attwithfilenameandextparamescaped
ascii_filename = ascii_filename.replace('\x5c', r'\\').replace('"', r'\"')
header.append('filename="%s"' % ascii_filename)
if unicode_filename is not None:
# encoded filename according RFC5987
- urlquoted_filename = urllib.quote(unicode_filename.encode('utf-8'), '')
+ urlquoted_filename = urlquote(unicode_filename.encode('utf-8'), '')
header.append("filename*=utf-8''" + urlquoted_filename)
self.set_header('content-disposition', ';'.join(header))
@@ -596,7 +578,7 @@
:param localfile: if True, the default data dir prefix is added to the
JS filename
"""
- if isinstance(jsfiles, basestring):
+ if isinstance(jsfiles, string_types):
jsfiles = (jsfiles,)
for jsfile in jsfiles:
if localfile:
@@ -616,7 +598,7 @@
the css inclusion. cf:
http://msdn.microsoft.com/en-us/library/ms537512(VS.85).aspx
"""
- if isinstance(cssfiles, basestring):
+ if isinstance(cssfiles, string_types):
cssfiles = (cssfiles,)
if ieonly:
if self.ie_browser():
@@ -702,7 +684,7 @@
return urlsplit(self.base_url())[2]
def data_url(self, relpath):
- """returns the absolute path for a data resouce"""
+ """returns the absolute path for a data resource"""
return self.datadir_url + relpath
@cached
@@ -722,25 +704,19 @@
Some response cache headers may be set by this method.
"""
modified = True
- if self.get_header('Cache-Control') not in ('max-age=0', 'no-cache'):
- # Here, we search for any invalid 'not modified' condition
- # see http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3
- validators = get_validators(self._headers_in)
- if validators: # if we have no
- modified = any(func(val, self.headers_out) for func, val in validators)
+ # Here, we search for any invalid 'not modified' condition
+ # see http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3
+ validators = get_validators(self._headers_in)
+ if validators: # if we have no
+ modified = any(func(val, self.headers_out) for func, val in validators)
# Forge expected response
- if modified:
- if 'Expires' not in self.headers_out:
- # Expires header seems to be required by IE7 -- Are you sure ?
- self.add_header('Expires', 'Sat, 01 Jan 2000 00:00:00 GMT')
- # /!\ no raise, the function returns and we keep processing the request
- else:
+ if not modified:
# overwrite headers_out to forge a brand new not-modified response
self.headers_out = self._forge_cached_headers()
if self.http_method() in ('HEAD', 'GET'):
- self.status_out = httplib.NOT_MODIFIED
+ self.status_out = http_client.NOT_MODIFIED
else:
- self.status_out = httplib.PRECONDITION_FAILED
+ self.status_out = http_client.PRECONDITION_FAILED
# XXX replace by True once validate_cache bw compat method is dropped
return self.status_out
# XXX replace by False once validate_cache bw compat method is dropped
@@ -800,7 +776,7 @@
def header_accept_language(self):
"""returns an ordered list of preferred languages"""
acceptedlangs = self.get_header('Accept-Language', raw=False) or {}
- for lang, _ in sorted(acceptedlangs.iteritems(), key=lambda x: x[1],
+ for lang, _ in sorted(acceptedlangs.items(), key=lambda x: x[1],
reverse=True):
lang = lang.split('-')[0]
yield lang
@@ -844,7 +820,7 @@
scheme = scheme.lower()
try:
assert scheme == "basic"
- user, passwd = base64.decodestring(rest).split(":", 1)
+ user, passwd = base64.decodestring(rest.encode('ascii')).split(b":", 1)
# XXX HTTP header encoding: use email.Header?
return user.decode('UTF8'), passwd
except Exception as ex:
@@ -966,8 +942,10 @@
def __getattribute__(self, attr):
raise AuthenticationError()
- def __nonzero__(self):
+ def __bool__(self):
return False
+
+ __nonzero__ = __bool__
class _MockAnonymousSession(object):
sessionid = 'thisisnotarealsession'
@@ -1023,8 +1001,8 @@
self.set_language(lang)
except KeyError:
# this occurs usually during test execution
- self._ = self.__ = unicode
- self.pgettext = lambda x, y: unicode(y)
+ self._ = self.__ = text_type
+ self.pgettext = lambda x, y: text_type(y)
entity_metas = _cnx_func('entity_metas')
source_defs = _cnx_func('source_defs')
--- a/web/schemaviewer.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/schemaviewer.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,9 @@
"""an helper class to display CubicWeb schema using ureports"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
+
+from six import string_types
from logilab.common.ureports import Section, Title, Table, Link, Span, Text
@@ -218,7 +220,7 @@
elif prop == 'constraints':
val = ', '.join([c.expression for c in val])
elif isinstance(val, dict):
- for key, value in val.iteritems():
+ for key, value in val.items():
if isinstance(value, (list, tuple)):
val[key] = ', '.join(sorted( str(v) for v in value))
val = str(val)
@@ -226,7 +228,7 @@
elif isinstance(val, (list, tuple)):
val = sorted(val)
val = ', '.join(str(v) for v in val)
- elif val and isinstance(val, basestring):
+ elif val and isinstance(val, string_types):
val = _(val)
else:
val = str(val)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/data/static/jstests/ajax_url0.html Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,3 @@
+<div id="ajaxroot">
+ <h1>Hello</h1>
+</div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/data/static/jstests/ajax_url1.html Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,6 @@
+<div id="ajaxroot">
+ <div class="ajaxHtmlHead">
+ <cubicweb:script src="http://foo.js" type="text/javascript"> </cubicweb:script>
+ </div>
+ <h1>Hello</h1>
+</div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/data/static/jstests/ajaxresult.json Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,1 @@
+["foo", "bar"]
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/data/static/jstests/test_ajax.html Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,26 @@
+<html>
+ <head>
+ <!-- dependencies -->
+ <script type="text/javascript">
+ var JSON_BASE_URL = '';
+ </script>
+ <script type="text/javascript" src="/data/jquery.js"></script>
+ <script src="/data/cubicweb.js" type="text/javascript"></script>
+ <script src="/data/cubicweb.htmlhelpers.js" type="text/javascript"></script>
+ <script src="/data/cubicweb.python.js" type="text/javascript"></script>
+ <script src="/data/cubicweb.compat.js" type="text/javascript"></script>
+ <script src="/data/cubicweb.ajax.js" type="text/javascript"></script>
+ <!-- qunit files -->
+ <script type="text/javascript" src="/devtools/qunit.js"></script>
+ <link rel="stylesheet" type="text/css" media="all" href="/devtools/qunit.css" />
+ <!-- test suite -->
+ <script src="/devtools/cwmock.js" type="text/javascript"></script>
+ <script src="test_ajax.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <div id="main"> </div>
+ <h1 id="qunit-header">cubicweb.ajax.js functions tests</h1>
+ <h2 id="qunit-banner"></h2>
+ <ol id="qunit-tests">
+ </body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/data/static/jstests/test_ajax.js Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,274 @@
+$(document).ready(function() {
+
+ QUnit.module("ajax", {
+ setup: function() {
+ this.scriptsLength = $('head script[src]').length-1;
+ this.cssLength = $('head link[rel=stylesheet]').length-1;
+ // re-initialize cw loaded cache so that each tests run in a
+ // clean environment, have a lookt at _loadAjaxHtmlHead implementation
+ // in cubicweb.ajax.js for more information.
+ cw.loaded_scripts = [];
+ cw.loaded_links = [];
+ },
+ teardown: function() {
+ $('head script[src]:lt(' + ($('head script[src]').length - 1 - this.scriptsLength) + ')').remove();
+ $('head link[rel=stylesheet]:gt(' + this.cssLength + ')').remove();
+ }
+ });
+
+ function jsSources() {
+ return $.map($('head script[src]'), function(script) {
+ return script.getAttribute('src');
+ });
+ }
+
+ QUnit.test('test simple h1 inclusion (ajax_url0.html)', function (assert) {
+ assert.expect(3);
+ assert.equal($('#qunit-fixture').children().length, 0);
+ var done = assert.async();
+ $('#qunit-fixture').loadxhtml('static/jstests/ajax_url0.html', null, 'GET')
+ .addCallback(function() {
+ try {
+ assert.equal($('#qunit-fixture').children().length, 1);
+ assert.equal($('#qunit-fixture h1').html(), 'Hello');
+ } finally {
+ done();
+ };
+ }
+ );
+ });
+
+ QUnit.test('test simple html head inclusion (ajax_url1.html)', function (assert) {
+ assert.expect(6);
+ var scriptsIncluded = jsSources();
+ assert.equal(jQuery.inArray('http://foo.js', scriptsIncluded), - 1);
+ var done = assert.async();
+ $('#qunit-fixture').loadxhtml('static/jstests/ajax_url1.html', null, 'GET')
+ .addCallback(function() {
+ try {
+ var origLength = scriptsIncluded.length;
+ scriptsIncluded = jsSources();
+ // check that foo.js has been prepended to <head>
+ assert.equal(scriptsIncluded.length, origLength + 1);
+ assert.equal(scriptsIncluded.indexOf('http://foo.js'), 0);
+ // check that <div class="ajaxHtmlHead"> has been removed
+ assert.equal($('#qunit-fixture').children().length, 1);
+ assert.equal($('div.ajaxHtmlHead').length, 0);
+ assert.equal($('#qunit-fixture h1').html(), 'Hello');
+ } finally {
+ done();
+ };
+ }
+ );
+ });
+
+ QUnit.test('test addCallback', function (assert) {
+ assert.expect(3);
+ assert.equal($('#qunit-fixture').children().length, 0);
+ var done = assert.async();
+ var d = $('#qunit-fixture').loadxhtml('static/jstests/ajax_url0.html', null, 'GET');
+ d.addCallback(function() {
+ try {
+ assert.equal($('#qunit-fixture').children().length, 1);
+ assert.equal($('#qunit-fixture h1').html(), 'Hello');
+ } finally {
+ done();
+ };
+ });
+ });
+
+ QUnit.test('test callback after synchronous request', function (assert) {
+ assert.expect(1);
+ var deferred = new Deferred();
+ var result = jQuery.ajax({
+ url: 'static/jstests/ajax_url0.html',
+ async: false,
+ beforeSend: function(xhr) {
+ deferred._req = xhr;
+ },
+ success: function(data, status) {
+ deferred.success(data);
+ }
+ });
+ var done = assert.async();
+ deferred.addCallback(function() {
+ try {
+ // add an assertion to ensure the callback is executed
+ assert.ok(true, "callback is executed");
+ } finally {
+ done();
+ };
+ });
+ });
+
+ QUnit.test('test addCallback with parameters', function (assert) {
+ assert.expect(3);
+ assert.equal($('#qunit-fixture').children().length, 0);
+ var done = assert.async();
+ var d = $('#qunit-fixture').loadxhtml('static/jstests/ajax_url0.html', null, 'GET');
+ d.addCallback(function(data, req, arg1, arg2) {
+ try {
+ assert.equal(arg1, 'Hello');
+ assert.equal(arg2, 'world');
+ } finally {
+ done();
+ };
+ },
+ 'Hello', 'world');
+ });
+
+ QUnit.test('test callback after synchronous request with parameters', function (assert) {
+ assert.expect(3);
+ var deferred = new Deferred();
+ deferred.addCallback(function(data, req, arg1, arg2) {
+ // add an assertion to ensure the callback is executed
+ try {
+ assert.ok(true, "callback is executed");
+ assert.equal(arg1, 'Hello');
+ assert.equal(arg2, 'world');
+ } finally {
+ done();
+ };
+ },
+ 'Hello', 'world');
+ deferred.addErrback(function() {
+ // throw an exception to start errback chain
+ try {
+ throw this._error;
+ } finally {
+ done();
+ };
+ });
+ var done = assert.async();
+ var result = jQuery.ajax({
+ url: 'static/jstests/ajax_url0.html',
+ async: false,
+ beforeSend: function(xhr) {
+ deferred._req = xhr;
+ },
+ success: function(data, status) {
+ deferred.success(data);
+ }
+ });
+ });
+
+ QUnit.test('test addErrback', function (assert) {
+ assert.expect(1);
+ var done = assert.async();
+ var d = $('#qunit-fixture').loadxhtml('static/jstests/nonexistent.html', null, 'GET');
+ d.addCallback(function() {
+ // should not be executed
+ assert.ok(false, "callback is executed");
+ });
+ d.addErrback(function() {
+ try {
+ assert.ok(true, "errback is executed");
+ } finally {
+ done();
+ };
+ });
+ });
+
+ QUnit.test('test callback execution order', function (assert) {
+ assert.expect(3);
+ var counter = 0;
+ var done = assert.async();
+ var d = $('#qunit-fixture').loadxhtml('static/jstests/ajax_url0.html', null, 'GET');
+ d.addCallback(function() {
+ assert.equal(++counter, 1); // should be executed first
+ });
+ d.addCallback(function() {
+ assert.equal(++counter, 2);
+ });
+ d.addCallback(function() {
+ try {
+ assert.equal(++counter, 3);
+ } finally {
+ done();
+ }
+ });
+ });
+
+ QUnit.test('test already included resources are ignored (ajax_url1.html)', function (assert) {
+ assert.expect(10);
+ var scriptsIncluded = jsSources();
+ // NOTE:
+ assert.equal(jQuery.inArray('http://foo.js', scriptsIncluded), -1);
+ assert.equal($('head link').length, 1);
+ /* use endswith because in pytest context we have an absolute path */
+ assert.ok($('head link').attr('href').endswith('/qunit.css'), 'qunit.css is loaded');
+ var done = assert.async();
+ $('#qunit-fixture').loadxhtml('static/jstests/ajax_url1.html', null, 'GET')
+ .addCallback(function() {
+ var origLength = scriptsIncluded.length;
+ scriptsIncluded = jsSources();
+ try {
+ // check that foo.js has been inserted in <head>
+ assert.equal(scriptsIncluded.length, origLength + 1);
+ assert.equal(scriptsIncluded.indexOf('http://foo.js'), 0);
+ // check that <div class="ajaxHtmlHead"> has been removed
+ assert.equal($('#qunit-fixture').children().length, 1);
+ assert.equal($('div.ajaxHtmlHead').length, 0);
+ assert.equal($('#qunit-fixture h1').html(), 'Hello');
+ // qunit.css is not added twice
+ assert.equal($('head link').length, 1);
+ /* use endswith because in pytest context we have an absolute path */
+ assert.ok($('head link').attr('href').endswith('/qunit.css'), 'qunit.css is loaded');
+ } finally {
+ done();
+ }
+ }
+ );
+ });
+
+ QUnit.test('test synchronous request loadRemote', function (assert) {
+ var res = loadRemote('static/jstests/ajaxresult.json', {},
+ 'GET', true);
+ assert.deepEqual(res, ['foo', 'bar']);
+ });
+
+ QUnit.test('test event on CubicWeb', function (assert) {
+ assert.expect(1);
+ var done = assert.async();
+ var events = null;
+ $(CubicWeb).bind('server-response', function() {
+ // check that server-response event on CubicWeb is triggered
+ events = 'CubicWeb';
+ });
+ $('#qunit-fixture').loadxhtml('static/jstests/ajax_url0.html', null, 'GET')
+ .addCallback(function() {
+ try {
+ assert.equal(events, 'CubicWeb');
+ } finally {
+ done();
+ };
+ }
+ );
+ });
+
+ QUnit.test('test event on node', function (assert) {
+ assert.expect(3);
+ var done = assert.async();
+ var nodes = [];
+ $('#qunit-fixture').bind('server-response', function() {
+ nodes.push('node');
+ });
+ $(CubicWeb).bind('server-response', function() {
+ nodes.push('CubicWeb');
+ });
+ $('#qunit-fixture').loadxhtml('static/jstests/ajax_url0.html', null, 'GET')
+ .addCallback(function() {
+ try {
+ assert.equal(nodes.length, 2);
+ // check that server-response event on CubicWeb is triggered
+ // only once and event server-response on node is triggered
+ assert.equal(nodes[0], 'CubicWeb');
+ assert.equal(nodes[1], 'node');
+ } finally {
+ done();
+ };
+ }
+ );
+ });
+});
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/data/static/jstests/test_htmlhelpers.html Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,22 @@
+<html>
+ <head>
+ <!-- dependencies -->
+ <script type="text/javascript" src="../../data/jquery.js"></script>
+ <script src="../../data/cubicweb.python.js" type="text/javascript"></script>
+ <script src="../../data/cubicweb.js" type="text/javascript"></script>
+ <script src="../../data/cubicweb.compat.js" type="text/javascript"></script>
+ <script src="../../data/cubicweb.htmlhelpers.js" type="text/javascript"></script>
+ <!-- qunit files -->
+ <script type="text/javascript" src="../../../devtools/data/qunit.js"></script>
+ <link rel="stylesheet" type="text/css" media="all" href="../../../devtools/data/qunit.css" />
+ <!-- test suite -->
+ <script src="cwmock.js" type="text/javascript"></script>
+ <script src="test_htmlhelpers.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <div id="main"> </div>
+ <h1 id="qunit-header">cubicweb.htmlhelpers.js functions tests</h1>
+ <h2 id="qunit-banner"></h2>
+ <ol id="qunit-tests">
+ </body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/data/static/jstests/test_htmlhelpers.js Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,36 @@
+$(document).ready(function() {
+
+ QUnit.module("module2", {
+ setup: function() {
+ $('#qunit-fixture').append('<select id="theselect" multiple="multiple" size="2">' +
+ '</select>');
+ }
+ });
+
+ QUnit.test("test first selected", function (assert) {
+ $('#theselect').append('<option value="foo">foo</option>' +
+ '<option selected="selected" value="bar">bar</option>' +
+ '<option value="baz">baz</option>' +
+ '<option selected="selecetd"value="spam">spam</option>');
+ var selected = firstSelected(document.getElementById("theselect"));
+ assert.equal(selected.value, 'bar');
+ });
+
+ QUnit.test("test first selected 2", function (assert) {
+ $('#theselect').append('<option value="foo">foo</option>' +
+ '<option value="bar">bar</option>' +
+ '<option value="baz">baz</option>' +
+ '<option value="spam">spam</option>');
+ var selected = firstSelected(document.getElementById("theselect"));
+ assert.equal(selected, null);
+ });
+
+ QUnit.module("visibilty");
+ QUnit.test('toggleVisibility', function (assert) {
+ $('#qunit-fixture').append('<div id="foo"></div>');
+ toggleVisibility('foo');
+ assert.ok($('#foo').hasClass('hidden'), 'check hidden class is set');
+ });
+
+});
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/data/static/jstests/test_utils.html Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,22 @@
+<html>
+ <head>
+ <!-- dependencies -->
+ <script type="text/javascript" src="utils.js"></script>
+ <script type="text/javascript" src="../../data/jquery.js"></script>
+ <script src="../../data/cubicweb.python.js" type="text/javascript"></script>
+ <script src="../../data/cubicweb.js" type="text/javascript"></script>
+ <script src="../../data/cubicweb.compat.js" type="text/javascript"></script>
+ <!-- qunit files -->
+ <script type="text/javascript" src="../../../devtools/data/qunit.js"></script>
+ <link rel="stylesheet" type="text/css" media="all" href="../../../devtools/data/qunit.css" />
+ <!-- test suite -->
+ <script src="cwmock.js" type="text/javascript"></script>
+ <script src="test_utils.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <div id="main"> </div>
+ <h1 id="qunit-header">cw.utils functions tests</h1>
+ <h2 id="qunit-banner"></h2>
+ <ol id="qunit-tests">
+ </body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/data/static/jstests/test_utils.js Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,92 @@
+$(document).ready(function() {
+
+ QUnit.module("datetime");
+
+ QUnit.test("test full datetime", function (assert) {
+ assert.equal(cw.utils.toISOTimestamp(new Date(1986, 3, 18, 10, 30, 0, 0)),
+ '1986-04-18 10:30:00');
+ });
+
+ QUnit.test("test only date", function (assert) {
+ assert.equal(cw.utils.toISOTimestamp(new Date(1986, 3, 18)), '1986-04-18 00:00:00');
+ });
+
+ QUnit.test("test null", function (assert) {
+ assert.equal(cw.utils.toISOTimestamp(null), null);
+ });
+
+ QUnit.module("parsing");
+ QUnit.test("test basic number parsing", function (assert) {
+ var d = strptime('2008/08/08', '%Y/%m/%d');
+ assert.deepEqual(datetuple(d), [2008, 8, 8, 0, 0]);
+ d = strptime('2008/8/8', '%Y/%m/%d');
+ assert.deepEqual(datetuple(d), [2008, 8, 8, 0, 0]);
+ d = strptime('8/8/8', '%Y/%m/%d');
+ assert.deepEqual(datetuple(d), [8, 8, 8, 0, 0]);
+ d = strptime('0/8/8', '%Y/%m/%d');
+ assert.deepEqual(datetuple(d), [0, 8, 8, 0, 0]);
+ d = strptime('-10/8/8', '%Y/%m/%d');
+ assert.deepEqual(datetuple(d), [-10, 8, 8, 0, 0]);
+ d = strptime('-35000', '%Y');
+ assert.deepEqual(datetuple(d), [-35000, 1, 1, 0, 0]);
+ });
+
+ QUnit.test("test custom format parsing", function (assert) {
+ var d = strptime('2008-08-08', '%Y-%m-%d');
+ assert.deepEqual(datetuple(d), [2008, 8, 8, 0, 0]);
+ d = strptime('2008 - ! 08: 08', '%Y - ! %m: %d');
+ assert.deepEqual(datetuple(d), [2008, 8, 8, 0, 0]);
+ d = strptime('2008-08-08 12:14', '%Y-%m-%d %H:%M');
+ assert.deepEqual(datetuple(d), [2008, 8, 8, 12, 14]);
+ d = strptime('2008-08-08 1:14', '%Y-%m-%d %H:%M');
+ assert.deepEqual(datetuple(d), [2008, 8, 8, 1, 14]);
+ d = strptime('2008-08-08 01:14', '%Y-%m-%d %H:%M');
+ assert.deepEqual(datetuple(d), [2008, 8, 8, 1, 14]);
+ });
+
+ QUnit.module("sliceList");
+ QUnit.test("test slicelist", function (assert) {
+ var list = ['a', 'b', 'c', 'd', 'e', 'f'];
+ assert.deepEqual(cw.utils.sliceList(list, 2), ['c', 'd', 'e', 'f']);
+ assert.deepEqual(cw.utils.sliceList(list, 2, -2), ['c', 'd']);
+ assert.deepEqual(cw.utils.sliceList(list, -3), ['d', 'e', 'f']);
+ assert.deepEqual(cw.utils.sliceList(list, 0, -2), ['a', 'b', 'c', 'd']);
+ assert.deepEqual(cw.utils.sliceList(list), list);
+ });
+
+ QUnit.module("formContents", {
+ setup: function() {
+ $('#qunit-fixture').append('<form id="test-form"></form>');
+ }
+ });
+ // XXX test fckeditor
+ QUnit.test("test formContents", function (assert) {
+ $('#test-form').append('<input name="input-text" ' +
+ 'type="text" value="toto" />');
+ $('#test-form').append('<textarea rows="10" cols="30" '+
+ 'name="mytextarea">Hello World!</textarea> ');
+ $('#test-form').append('<input name="choice" type="radio" ' +
+ 'value="yes" />');
+ $('#test-form').append('<input name="choice" type="radio" ' +
+ 'value="no" checked="checked"/>');
+ $('#test-form').append('<input name="check" type="checkbox" ' +
+ 'value="yes" />');
+ $('#test-form').append('<input name="check" type="checkbox" ' +
+ 'value="no" checked="checked"/>');
+ $('#test-form').append('<select id="theselect" name="theselect" ' +
+ 'multiple="multiple" size="2"></select>');
+ $('#theselect').append('<option selected="selected" ' +
+ 'value="foo">foo</option>' +
+ '<option value="bar">bar</option>');
+ //Append an unchecked radio input : should not be in formContents list
+ $('#test-form').append('<input name="unchecked-choice" type="radio" ' +
+ 'value="one" />');
+ $('#test-form').append('<input name="unchecked-choice" type="radio" ' +
+ 'value="two"/>');
+ assert.deepEqual(cw.utils.formContents($('#test-form')[0]), [
+ ['input-text', 'mytextarea', 'choice', 'check', 'theselect'],
+ ['toto', 'Hello World!', 'no', 'no', 'foo']
+ ]);
+ });
+});
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/web/test/data/static/jstests/utils.js Thu Dec 10 12:34:15 2015 +0100
@@ -0,0 +1,29 @@
+function datetuple(d) {
+ return [d.getFullYear(), d.getMonth()+1, d.getDate(),
+ d.getHours(), d.getMinutes()];
+}
+
+function pprint(obj) {
+ print('{');
+ for(k in obj) {
+ print(' ' + k + ' = ' + obj[k]);
+ }
+ print('}');
+}
+
+function arrayrepr(array) {
+ return '[' + array.join(', ') + ']';
+}
+
+function assertArrayEquals(array1, array2) {
+ if (array1.length != array2.length) {
+ throw new crosscheck.AssertionFailure(array1.join(', ') + ' != ' + array2.join(', '));
+ }
+ for (var i=0; i<array1.length; i++) {
+ if (array1[i] != array2[i]) {
+
+ throw new crosscheck.AssertionFailure(arrayrepr(array1) + ' and ' + arrayrepr(array2)
+ + ' differs at index ' + i);
+ }
+ }
+}
--- a/web/test/data/views.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/data/views.py Thu Dec 10 12:34:15 2015 +0100
@@ -42,10 +42,10 @@
"""
try:
result_dict = {}
- for key, value in self._cw.form.iteritems():
+ for key, value in self._cw.form.items():
result_dict[key] = _recursive_replace_stream_by_content(value)
return result_dict
- except Exception, ex:
+ except Exception as ex:
import traceback as tb
tb.print_exc(ex)
--- a/web/test/jstests/ajax_url0.html Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-<div id="ajaxroot">
- <h1>Hello</h1>
-</div>
--- a/web/test/jstests/ajax_url1.html Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-<div id="ajaxroot">
- <div class="ajaxHtmlHead">
- <cubicweb:script src="http://foo.js" type="text/javascript"> </cubicweb:script>
- </div>
- <h1>Hello</h1>
-</div>
--- a/web/test/jstests/ajax_url2.html Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-<div id="ajaxroot">
- <div class="ajaxHtmlHead">
- <script src="http://foo.js" type="text/javascript"> </script>
- <link rel="stylesheet" type="text/css" media="all" href="qunit.css" />
- </div>
- <h1>Hello</h1>
-</div>
--- a/web/test/jstests/ajaxresult.json Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-["foo", "bar"]
--- a/web/test/jstests/test_ajax.html Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-<html>
- <head>
- <!-- dependencies -->
- <script type="text/javascript">
- var JSON_BASE_URL = '';
- </script>
- <script type="text/javascript" src="../../data/jquery.js"></script>
- <script src="../../data/cubicweb.js" type="text/javascript"></script>
- <script src="../../data/cubicweb.htmlhelpers.js" type="text/javascript"></script>
- <script src="../../data/cubicweb.python.js" type="text/javascript"></script>
- <script src="../../data/cubicweb.compat.js" type="text/javascript"></script>
- <script src="../../data/cubicweb.ajax.js" type="text/javascript"></script>
- <!-- qunit files -->
- <script type="text/javascript" src="../../../devtools/data/qunit.js"></script>
- <link rel="stylesheet" type="text/css" media="all" href="../../../devtools/data/qunit.css" />
- <!-- test suite -->
- <script src="cwmock.js" type="text/javascript"></script>
- <script src="test_ajax.js" type="text/javascript"></script>
- </head>
- <body>
- <div id="main"> </div>
- <h1 id="qunit-header">cubicweb.ajax.js functions tests</h1>
- <h2 id="qunit-banner"></h2>
- <ol id="qunit-tests">
- </body>
-</html>
--- a/web/test/jstests/test_ajax.js Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,274 +0,0 @@
-$(document).ready(function() {
-
- QUnit.module("ajax", {
- setup: function() {
- this.scriptsLength = $('head script[src]').length-1;
- this.cssLength = $('head link[rel=stylesheet]').length-1;
- // re-initialize cw loaded cache so that each tests run in a
- // clean environment, have a lookt at _loadAjaxHtmlHead implementation
- // in cubicweb.ajax.js for more information.
- cw.loaded_scripts = [];
- cw.loaded_links = [];
- },
- teardown: function() {
- $('head script[src]:lt(' + ($('head script[src]').length - 1 - this.scriptsLength) + ')').remove();
- $('head link[rel=stylesheet]:gt(' + this.cssLength + ')').remove();
- }
- });
-
- function jsSources() {
- return $.map($('head script[src]'), function(script) {
- return script.getAttribute('src');
- });
- }
-
- QUnit.test('test simple h1 inclusion (ajax_url0.html)', function (assert) {
- assert.expect(3);
- assert.equal($('#qunit-fixture').children().length, 0);
- var done = assert.async();
- $('#qunit-fixture').loadxhtml(BASE_URL + 'cwsoftwareroot/web/test/jstests/ajax_url0.html')
- .addCallback(function() {
- try {
- assert.equal($('#qunit-fixture').children().length, 1);
- assert.equal($('#qunit-fixture h1').html(), 'Hello');
- } finally {
- done();
- };
- }
- );
- });
-
- QUnit.test('test simple html head inclusion (ajax_url1.html)', function (assert) {
- assert.expect(6);
- var scriptsIncluded = jsSources();
- assert.equal(jQuery.inArray('http://foo.js', scriptsIncluded), - 1);
- var done = assert.async();
- $('#qunit-fixture').loadxhtml(BASE_URL + 'cwsoftwareroot/web/test/jstests/ajax_url1.html')
- .addCallback(function() {
- try {
- var origLength = scriptsIncluded.length;
- scriptsIncluded = jsSources();
- // check that foo.js has been prepended to <head>
- assert.equal(scriptsIncluded.length, origLength + 1);
- assert.equal(scriptsIncluded.indexOf('http://foo.js'), 0);
- // check that <div class="ajaxHtmlHead"> has been removed
- assert.equal($('#qunit-fixture').children().length, 1);
- assert.equal($('div.ajaxHtmlHead').length, 0);
- assert.equal($('#qunit-fixture h1').html(), 'Hello');
- } finally {
- done();
- };
- }
- );
- });
-
- QUnit.test('test addCallback', function (assert) {
- assert.expect(3);
- assert.equal($('#qunit-fixture').children().length, 0);
- var done = assert.async();
- var d = $('#qunit-fixture').loadxhtml(BASE_URL + 'cwsoftwareroot/web/test/jstests/ajax_url0.html');
- d.addCallback(function() {
- try {
- assert.equal($('#qunit-fixture').children().length, 1);
- assert.equal($('#qunit-fixture h1').html(), 'Hello');
- } finally {
- done();
- };
- });
- });
-
- QUnit.test('test callback after synchronous request', function (assert) {
- assert.expect(1);
- var deferred = new Deferred();
- var result = jQuery.ajax({
- url: BASE_URL + 'cwsoftwareroot/web/test/jstests/ajax_url0.html',
- async: false,
- beforeSend: function(xhr) {
- deferred._req = xhr;
- },
- success: function(data, status) {
- deferred.success(data);
- }
- });
- var done = assert.async();
- deferred.addCallback(function() {
- try {
- // add an assertion to ensure the callback is executed
- assert.ok(true, "callback is executed");
- } finally {
- done();
- };
- });
- });
-
- QUnit.test('test addCallback with parameters', function (assert) {
- assert.expect(3);
- assert.equal($('#qunit-fixture').children().length, 0);
- var done = assert.async();
- var d = $('#qunit-fixture').loadxhtml(BASE_URL + 'cwsoftwareroot/web/test/jstests/ajax_url0.html');
- d.addCallback(function(data, req, arg1, arg2) {
- try {
- assert.equal(arg1, 'Hello');
- assert.equal(arg2, 'world');
- } finally {
- done();
- };
- },
- 'Hello', 'world');
- });
-
- QUnit.test('test callback after synchronous request with parameters', function (assert) {
- assert.expect(3);
- var deferred = new Deferred();
- deferred.addCallback(function(data, req, arg1, arg2) {
- // add an assertion to ensure the callback is executed
- try {
- assert.ok(true, "callback is executed");
- assert.equal(arg1, 'Hello');
- assert.equal(arg2, 'world');
- } finally {
- done();
- };
- },
- 'Hello', 'world');
- deferred.addErrback(function() {
- // throw an exception to start errback chain
- try {
- throw this._error;
- } finally {
- done();
- };
- });
- var done = assert.async();
- var result = jQuery.ajax({
- url: BASE_URL + 'cwsoftwareroot/web/test/jstests/ajax_url0.html',
- async: false,
- beforeSend: function(xhr) {
- deferred._req = xhr;
- },
- success: function(data, status) {
- deferred.success(data);
- }
- });
- });
-
- QUnit.test('test addErrback', function (assert) {
- assert.expect(1);
- var done = assert.async();
- var d = $('#qunit-fixture').loadxhtml(BASE_URL + 'cwsoftwareroot/web/test/jstests/nonexistent.html');
- d.addCallback(function() {
- // should not be executed
- assert.ok(false, "callback is executed");
- });
- d.addErrback(function() {
- try {
- assert.ok(true, "errback is executed");
- } finally {
- done();
- };
- });
- });
-
- QUnit.test('test callback execution order', function (assert) {
- assert.expect(3);
- var counter = 0;
- var done = assert.async();
- var d = $('#qunit-fixture').loadxhtml(BASE_URL + 'cwsoftwareroot/web/test/jstests/ajax_url0.html');
- d.addCallback(function() {
- assert.equal(++counter, 1); // should be executed first
- });
- d.addCallback(function() {
- assert.equal(++counter, 2);
- });
- d.addCallback(function() {
- try {
- assert.equal(++counter, 3);
- } finally {
- done();
- }
- });
- });
-
- QUnit.test('test already included resources are ignored (ajax_url1.html)', function (assert) {
- assert.expect(10);
- var scriptsIncluded = jsSources();
- // NOTE:
- assert.equal(jQuery.inArray('http://foo.js', scriptsIncluded), -1);
- assert.equal($('head link').length, 1);
- /* use endswith because in pytest context we have an absolute path */
- assert.ok($('head link').attr('href').endswith('/qunit.css'), 'qunit.css is loaded');
- var done = assert.async();
- $('#qunit-fixture').loadxhtml(BASE_URL + 'cwsoftwareroot/web/test/jstests/ajax_url1.html')
- .addCallback(function() {
- var origLength = scriptsIncluded.length;
- scriptsIncluded = jsSources();
- try {
- // check that foo.js has been inserted in <head>
- assert.equal(scriptsIncluded.length, origLength + 1);
- assert.equal(scriptsIncluded.indexOf('http://foo.js'), 0);
- // check that <div class="ajaxHtmlHead"> has been removed
- assert.equal($('#qunit-fixture').children().length, 1);
- assert.equal($('div.ajaxHtmlHead').length, 0);
- assert.equal($('#qunit-fixture h1').html(), 'Hello');
- // qunit.css is not added twice
- assert.equal($('head link').length, 1);
- /* use endswith because in pytest context we have an absolute path */
- assert.ok($('head link').attr('href').endswith('/qunit.css'), 'qunit.css is loaded');
- } finally {
- done();
- }
- }
- );
- });
-
- QUnit.test('test synchronous request loadRemote', function (assert) {
- var res = loadRemote(BASE_URL + 'cwsoftwareroot/web/test/jstests/ajaxresult.json', {},
- 'GET', true);
- assert.deepEqual(res, ['foo', 'bar']);
- });
-
- QUnit.test('test event on CubicWeb', function (assert) {
- assert.expect(1);
- var done = assert.async();
- var events = null;
- $(CubicWeb).bind('server-response', function() {
- // check that server-response event on CubicWeb is triggered
- events = 'CubicWeb';
- });
- $('#qunit-fixture').loadxhtml(BASE_URL + 'cwsoftwareroot/web/test/jstests/ajax_url0.html')
- .addCallback(function() {
- try {
- assert.equal(events, 'CubicWeb');
- } finally {
- done();
- };
- }
- );
- });
-
- QUnit.test('test event on node', function (assert) {
- assert.expect(3);
- var done = assert.async();
- var nodes = [];
- $('#qunit-fixture').bind('server-response', function() {
- nodes.push('node');
- });
- $(CubicWeb).bind('server-response', function() {
- nodes.push('CubicWeb');
- });
- $('#qunit-fixture').loadxhtml(BASE_URL + 'cwsoftwareroot/web/test/jstests/ajax_url0.html')
- .addCallback(function() {
- try {
- assert.equal(nodes.length, 2);
- // check that server-response event on CubicWeb is triggered
- // only once and event server-response on node is triggered
- assert.equal(nodes[0], 'CubicWeb');
- assert.equal(nodes[1], 'node');
- } finally {
- done();
- };
- }
- );
- });
-});
-
--- a/web/test/jstests/test_htmlhelpers.html Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-<html>
- <head>
- <!-- dependencies -->
- <script type="text/javascript" src="../../data/jquery.js"></script>
- <script src="../../data/cubicweb.python.js" type="text/javascript"></script>
- <script src="../../data/cubicweb.js" type="text/javascript"></script>
- <script src="../../data/cubicweb.compat.js" type="text/javascript"></script>
- <script src="../../data/cubicweb.htmlhelpers.js" type="text/javascript"></script>
- <!-- qunit files -->
- <script type="text/javascript" src="../../../devtools/data/qunit.js"></script>
- <link rel="stylesheet" type="text/css" media="all" href="../../../devtools/data/qunit.css" />
- <!-- test suite -->
- <script src="cwmock.js" type="text/javascript"></script>
- <script src="test_htmlhelpers.js" type="text/javascript"></script>
- </head>
- <body>
- <div id="main"> </div>
- <h1 id="qunit-header">cubicweb.htmlhelpers.js functions tests</h1>
- <h2 id="qunit-banner"></h2>
- <ol id="qunit-tests">
- </body>
-</html>
--- a/web/test/jstests/test_htmlhelpers.js Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-$(document).ready(function() {
-
- QUnit.module("module2", {
- setup: function() {
- $('#qunit-fixture').append('<select id="theselect" multiple="multiple" size="2">' +
- '</select>');
- }
- });
-
- QUnit.test("test first selected", function (assert) {
- $('#theselect').append('<option value="foo">foo</option>' +
- '<option selected="selected" value="bar">bar</option>' +
- '<option value="baz">baz</option>' +
- '<option selected="selecetd"value="spam">spam</option>');
- var selected = firstSelected(document.getElementById("theselect"));
- assert.equal(selected.value, 'bar');
- });
-
- QUnit.test("test first selected 2", function (assert) {
- $('#theselect').append('<option value="foo">foo</option>' +
- '<option value="bar">bar</option>' +
- '<option value="baz">baz</option>' +
- '<option value="spam">spam</option>');
- var selected = firstSelected(document.getElementById("theselect"));
- assert.equal(selected, null);
- });
-
- QUnit.module("visibilty");
- QUnit.test('toggleVisibility', function (assert) {
- $('#qunit-fixture').append('<div id="foo"></div>');
- toggleVisibility('foo');
- assert.ok($('#foo').hasClass('hidden'), 'check hidden class is set');
- });
-
-});
-
--- a/web/test/jstests/test_utils.html Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-<html>
- <head>
- <!-- dependencies -->
- <script type="text/javascript" src="utils.js"></script>
- <script type="text/javascript" src="../../data/jquery.js"></script>
- <script src="../../data/cubicweb.python.js" type="text/javascript"></script>
- <script src="../../data/cubicweb.js" type="text/javascript"></script>
- <script src="../../data/cubicweb.compat.js" type="text/javascript"></script>
- <!-- qunit files -->
- <script type="text/javascript" src="../../../devtools/data/qunit.js"></script>
- <link rel="stylesheet" type="text/css" media="all" href="../../../devtools/data/qunit.css" />
- <!-- test suite -->
- <script src="cwmock.js" type="text/javascript"></script>
- <script src="test_utils.js" type="text/javascript"></script>
- </head>
- <body>
- <div id="main"> </div>
- <h1 id="qunit-header">cw.utils functions tests</h1>
- <h2 id="qunit-banner"></h2>
- <ol id="qunit-tests">
- </body>
-</html>
--- a/web/test/jstests/test_utils.js Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-$(document).ready(function() {
-
- QUnit.module("datetime");
-
- QUnit.test("test full datetime", function (assert) {
- assert.equal(cw.utils.toISOTimestamp(new Date(1986, 3, 18, 10, 30, 0, 0)),
- '1986-04-18 10:30:00');
- });
-
- QUnit.test("test only date", function (assert) {
- assert.equal(cw.utils.toISOTimestamp(new Date(1986, 3, 18)), '1986-04-18 00:00:00');
- });
-
- QUnit.test("test null", function (assert) {
- assert.equal(cw.utils.toISOTimestamp(null), null);
- });
-
- QUnit.module("parsing");
- QUnit.test("test basic number parsing", function (assert) {
- var d = strptime('2008/08/08', '%Y/%m/%d');
- assert.deepEqual(datetuple(d), [2008, 8, 8, 0, 0]);
- d = strptime('2008/8/8', '%Y/%m/%d');
- assert.deepEqual(datetuple(d), [2008, 8, 8, 0, 0]);
- d = strptime('8/8/8', '%Y/%m/%d');
- assert.deepEqual(datetuple(d), [8, 8, 8, 0, 0]);
- d = strptime('0/8/8', '%Y/%m/%d');
- assert.deepEqual(datetuple(d), [0, 8, 8, 0, 0]);
- d = strptime('-10/8/8', '%Y/%m/%d');
- assert.deepEqual(datetuple(d), [-10, 8, 8, 0, 0]);
- d = strptime('-35000', '%Y');
- assert.deepEqual(datetuple(d), [-35000, 1, 1, 0, 0]);
- });
-
- QUnit.test("test custom format parsing", function (assert) {
- var d = strptime('2008-08-08', '%Y-%m-%d');
- assert.deepEqual(datetuple(d), [2008, 8, 8, 0, 0]);
- d = strptime('2008 - ! 08: 08', '%Y - ! %m: %d');
- assert.deepEqual(datetuple(d), [2008, 8, 8, 0, 0]);
- d = strptime('2008-08-08 12:14', '%Y-%m-%d %H:%M');
- assert.deepEqual(datetuple(d), [2008, 8, 8, 12, 14]);
- d = strptime('2008-08-08 1:14', '%Y-%m-%d %H:%M');
- assert.deepEqual(datetuple(d), [2008, 8, 8, 1, 14]);
- d = strptime('2008-08-08 01:14', '%Y-%m-%d %H:%M');
- assert.deepEqual(datetuple(d), [2008, 8, 8, 1, 14]);
- });
-
- QUnit.module("sliceList");
- QUnit.test("test slicelist", function (assert) {
- var list = ['a', 'b', 'c', 'd', 'e', 'f'];
- assert.deepEqual(cw.utils.sliceList(list, 2), ['c', 'd', 'e', 'f']);
- assert.deepEqual(cw.utils.sliceList(list, 2, -2), ['c', 'd']);
- assert.deepEqual(cw.utils.sliceList(list, -3), ['d', 'e', 'f']);
- assert.deepEqual(cw.utils.sliceList(list, 0, -2), ['a', 'b', 'c', 'd']);
- assert.deepEqual(cw.utils.sliceList(list), list);
- });
-
- QUnit.module("formContents", {
- setup: function() {
- $('#qunit-fixture').append('<form id="test-form"></form>');
- }
- });
- // XXX test fckeditor
- QUnit.test("test formContents", function (assert) {
- $('#test-form').append('<input name="input-text" ' +
- 'type="text" value="toto" />');
- $('#test-form').append('<textarea rows="10" cols="30" '+
- 'name="mytextarea">Hello World!</textarea> ');
- $('#test-form').append('<input name="choice" type="radio" ' +
- 'value="yes" />');
- $('#test-form').append('<input name="choice" type="radio" ' +
- 'value="no" checked="checked"/>');
- $('#test-form').append('<input name="check" type="checkbox" ' +
- 'value="yes" />');
- $('#test-form').append('<input name="check" type="checkbox" ' +
- 'value="no" checked="checked"/>');
- $('#test-form').append('<select id="theselect" name="theselect" ' +
- 'multiple="multiple" size="2"></select>');
- $('#theselect').append('<option selected="selected" ' +
- 'value="foo">foo</option>' +
- '<option value="bar">bar</option>');
- //Append an unchecked radio input : should not be in formContents list
- $('#test-form').append('<input name="unchecked-choice" type="radio" ' +
- 'value="one" />');
- $('#test-form').append('<input name="unchecked-choice" type="radio" ' +
- 'value="two"/>');
- assert.deepEqual(cw.utils.formContents($('#test-form')[0]), [
- ['input-text', 'mytextarea', 'choice', 'check', 'theselect'],
- ['toto', 'Hello World!', 'no', 'no', 'foo']
- ]);
- });
-});
-
--- a/web/test/jstests/utils.js Wed Dec 09 18:42:13 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-function datetuple(d) {
- return [d.getFullYear(), d.getMonth()+1, d.getDate(),
- d.getHours(), d.getMinutes()];
-}
-
-function pprint(obj) {
- print('{');
- for(k in obj) {
- print(' ' + k + ' = ' + obj[k]);
- }
- print('}');
-}
-
-function arrayrepr(array) {
- return '[' + array.join(', ') + ']';
-}
-
-function assertArrayEquals(array1, array2) {
- if (array1.length != array2.length) {
- throw new crosscheck.AssertionFailure(array1.join(', ') + ' != ' + array2.join(', '));
- }
- for (var i=0; i<array1.length; i++) {
- if (array1[i] != array2[i]) {
-
- throw new crosscheck.AssertionFailure(arrayrepr(array1) + ' and ' + arrayrepr(array2)
- + ' differs at index ' + i);
- }
- }
-}
--- a/web/test/test_jscript.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/test_jscript.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,42 +1,38 @@
-from cubicweb.devtools.qunit import QUnitTestCase, unittest_main
+from cubicweb.devtools import qunit
from os import path as osp
-class JScript(QUnitTestCase):
+class JScript(qunit.QUnitTestCase):
all_js_tests = (
- ("jstests/test_utils.js", (
- "../../web/data/cubicweb.js",
- "../../web/data/cubicweb.compat.js",
- "../../web/data/cubicweb.python.js",
- "jstests/utils.js",
+ ("/static/jstests/test_utils.js", (
+ "/data/cubicweb.js",
+ "/data/cubicweb.compat.js",
+ "/data/cubicweb.python.js",
+ "/static/jstests/utils.js",
),
),
- ("jstests/test_htmlhelpers.js", (
- "../../web/data/cubicweb.js",
- "../../web/data/cubicweb.compat.js",
- "../../web/data/cubicweb.python.js",
- "../../web/data/cubicweb.htmlhelpers.js",
+ ("/static/jstests/test_htmlhelpers.js", (
+ "/data/cubicweb.js",
+ "/data/cubicweb.compat.js",
+ "/data/cubicweb.python.js",
+ "/data/cubicweb.htmlhelpers.js",
),
),
- ("jstests/test_ajax.js", (
- "../../web/data/cubicweb.python.js",
- "../../web/data/cubicweb.js",
- "../../web/data/cubicweb.compat.js",
- "../../web/data/cubicweb.htmlhelpers.js",
- "../../web/data/cubicweb.ajax.js",
- ), (
- "jstests/ajax_url0.html",
- "jstests/ajax_url1.html",
- "jstests/ajax_url2.html",
- "jstests/ajaxresult.json",
+ ("/static/jstests/test_ajax.js", (
+ "/data/cubicweb.python.js",
+ "/data/cubicweb.js",
+ "/data/cubicweb.compat.js",
+ "/data/cubicweb.htmlhelpers.js",
+ "/data/cubicweb.ajax.js",
),
),
)
if __name__ == '__main__':
- unittest_main()
+ from unittest import main
+ main()
--- a/web/test/test_views.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/test_views.py Thu Dec 10 12:34:15 2015 +0100
@@ -50,19 +50,19 @@
composite entity
"""
with self.admin_access.web_request() as req:
- rset = req.execute('CWUser X WHERE X login "admin"')
+ rset = req.execute(u'CWUser X WHERE X login "admin"')
self.view('copy', rset, req=req)
def test_sortable_js_added(self):
with self.admin_access.web_request() as req:
# sortable.js should not be included by default
rset = req.execute('CWUser X')
- self.assertNotIn('jquery.tablesorter.js', self.view('oneline', rset, req=req).source)
+ self.assertNotIn(b'jquery.tablesorter.js', self.view('oneline', rset, req=req).source)
with self.admin_access.web_request() as req:
# but should be included by the tableview
rset = req.execute('Any P,F,S LIMIT 1 WHERE P is CWUser, P firstname F, P surname S')
- self.assertIn('jquery.tablesorter.js', self.view('table', rset, req=req).source)
+ self.assertIn(b'jquery.tablesorter.js', self.view('table', rset, req=req).source)
def test_js_added_only_once(self):
with self.admin_access.web_request() as req:
@@ -70,14 +70,14 @@
self.vreg.register(SomeView)
rset = req.execute('CWUser X')
source = self.view('someview', rset, req=req).source
- self.assertEqual(source.count('spam.js'), 1)
+ self.assertEqual(source.count(b'spam.js'), 1)
def test_unrelateddivs(self):
with self.admin_access.client_cnx() as cnx:
group = cnx.create_entity('CWGroup', name=u'R&D')
cnx.commit()
with self.admin_access.web_request(relation='in_group_subject') as req:
- rset = req.execute('Any X WHERE X is CWUser, X login "admin"')
+ rset = req.execute(u'Any X WHERE X is CWUser, X login "admin"')
self.view('unrelateddivs', rset, req=req)
--- a/web/test/unittest_application.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_application.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,8 +17,11 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""unit tests for cubicweb.web.application"""
-import base64, Cookie
-import httplib
+import base64
+
+from six import text_type
+from six.moves import http_client
+from six.moves.http_cookies import SimpleCookie
from logilab.common.testlib import TestCase, unittest_main
from logilab.common.decorators import clear_cache, classproperty
@@ -179,8 +182,8 @@
def test_publish_validation_error(self):
with self.admin_access.web_request() as req:
- user = self.user(req)
- eid = unicode(user.eid)
+ user = req.user
+ eid = text_type(user.eid)
req.form = {
'eid': eid,
'__type:'+eid: 'CWUser', '_cw_entity_fields:'+eid: 'login-subject',
@@ -267,14 +270,14 @@
with self.admin_access.web_request(vid='test.ajax.error') as req:
req.ajax_request = True
page = app.handle_request(req, '')
- self.assertEqual(httplib.INTERNAL_SERVER_ERROR,
+ self.assertEqual(http_client.INTERNAL_SERVER_ERROR,
req.status_out)
def _test_cleaned(self, kwargs, injected, cleaned):
with self.admin_access.web_request(**kwargs) as req:
page = self.app_handle_request(req, 'view')
- self.assertNotIn(injected, page)
- self.assertIn(cleaned, page)
+ self.assertNotIn(injected.encode('ascii'), page)
+ self.assertIn(cleaned.encode('ascii'), page)
def test_nonregr_script_kiddies(self):
"""test against current script injection"""
@@ -314,8 +317,8 @@
self.app.handle_request(req, 'login')
self.assertEqual(401, req.status_out)
clear_cache(req, 'get_authorization')
- authstr = base64.encodestring('%s:%s' % (self.admlogin, self.admpassword))
- req.set_request_header('Authorization', 'basic %s' % authstr)
+ authstr = base64.encodestring(('%s:%s' % (self.admlogin, self.admpassword)).encode('ascii'))
+ req.set_request_header('Authorization', 'basic %s' % authstr.decode('ascii'))
self.assertAuthSuccess(req, origsession)
self.assertRaises(LogOut, self.app_handle_request, req, 'logout')
self.assertEqual(len(self.open_sessions), 0)
@@ -328,8 +331,8 @@
except Redirect as redir:
self.fail('anonymous user should get login form')
clear_cache(req, 'get_authorization')
- self.assertIn('__login', form)
- self.assertIn('__password', form)
+ self.assertIn(b'__login', form)
+ self.assertIn(b'__password', form)
self.assertFalse(req.cnx) # Mock cnx are False
req.form['__login'] = self.admlogin
req.form['__password'] = self.admpassword
@@ -361,7 +364,7 @@
def _reset_cookie(self, req):
# preparing the suite of the test
# set session id in cookie
- cookie = Cookie.SimpleCookie()
+ cookie = SimpleCookie()
sessioncookie = self.app.session_handler.session_cookie(req)
cookie[sessioncookie] = req.session.sessionid
req.set_request_header('Cookie', cookie[sessioncookie].OutputString(),
@@ -390,11 +393,11 @@
def test_http_auth_anon_allowed(self):
req, origsession = self.init_authentication('http', 'anon')
self._test_auth_anon(req)
- authstr = base64.encodestring('toto:pouet')
- req.set_request_header('Authorization', 'basic %s' % authstr)
+ authstr = base64.encodestring(b'toto:pouet')
+ req.set_request_header('Authorization', 'basic %s' % authstr.decode('ascii'))
self._test_anon_auth_fail(req)
- authstr = base64.encodestring('%s:%s' % (self.admlogin, self.admpassword))
- req.set_request_header('Authorization', 'basic %s' % authstr)
+ authstr = base64.encodestring(('%s:%s' % (self.admlogin, self.admpassword)).encode('ascii'))
+ req.set_request_header('Authorization', 'basic %s' % authstr.decode('ascii'))
self.assertAuthSuccess(req, origsession)
self.assertRaises(LogOut, self.app_handle_request, req, 'logout')
self.assertEqual(len(self.open_sessions), 0)
--- a/web/test/unittest_facet.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_facet.py Thu Dec 10 12:34:15 2015 +0100
@@ -70,8 +70,8 @@
def test_relation_optional_rel(self):
with self.admin_access.web_request() as req:
- rset = req.cnx.execute('Any X,GROUP_CONCAT(GN) GROUPBY X '
- 'WHERE X in_group G?, G name GN, NOT G name "users"')
+ rset = req.cnx.execute(u'Any X,GROUP_CONCAT(GN) GROUPBY X '
+ 'WHERE X in_group G?, G name GN, NOT G name "users"')
rqlst = rset.syntax_tree().copy()
select = rqlst.children[0]
filtered_variable, baserql = facet.init_facets(rset, select)
@@ -87,18 +87,18 @@
self.assertEqual(f.vocabulary(),
[(u'guests', guests), (u'managers', managers)])
# ensure rqlst is left unmodified
- self.assertEqual(rqlst.as_string(), "DISTINCT Any WHERE X in_group G?, G name GN, NOT G name 'users'")
+ self.assertEqual(rqlst.as_string(), 'DISTINCT Any WHERE X in_group G?, G name GN, NOT G name "users"')
#rqlst = rset.syntax_tree()
self.assertEqual(sorted(f.possible_values()),
[str(guests), str(managers)])
# ensure rqlst is left unmodified
- self.assertEqual(rqlst.as_string(), "DISTINCT Any WHERE X in_group G?, G name GN, NOT G name 'users'")
+ self.assertEqual(rqlst.as_string(), 'DISTINCT Any WHERE X in_group G?, G name GN, NOT G name "users"')
req.form[f.__regid__] = str(guests)
f.add_rql_restrictions()
# selection is cluttered because rqlst has been prepared for facet (it
# is not in real life)
self.assertEqual(f.select.as_string(),
- "DISTINCT Any WHERE X in_group G?, G name GN, NOT G name 'users', X in_group D, D eid %s" % guests)
+ 'DISTINCT Any WHERE X in_group G?, G name GN, NOT G name "users", X in_group D, D eid %s' % guests)
def test_relation_no_relation_1(self):
with self.admin_access.web_request() as req:
@@ -141,12 +141,12 @@
['guests', 'managers'])
# ensure rqlst is left unmodified
self.assertEqual(f.select.as_string(), 'DISTINCT Any WHERE X is CWUser')
- f._cw.form[f.__regid__] = 'guests'
+ f._cw.form[f.__regid__] = u'guests'
f.add_rql_restrictions()
# selection is cluttered because rqlst has been prepared for facet (it
# is not in real life)
self.assertEqual(f.select.as_string(),
- "DISTINCT Any WHERE X is CWUser, X in_group E, E name 'guests'")
+ 'DISTINCT Any WHERE X is CWUser, X in_group E, E name "guests"')
def test_hasrelation(self):
with self.admin_access.web_request() as req:
@@ -207,12 +207,12 @@
['admin', 'anon'])
# ensure rqlst is left unmodified
self.assertEqual(rqlst.as_string(), 'DISTINCT Any WHERE X is CWUser')
- req.form[f.__regid__] = 'admin'
+ req.form[f.__regid__] = u'admin'
f.add_rql_restrictions()
# selection is cluttered because rqlst has been prepared for facet (it
# is not in real life)
self.assertEqual(f.select.as_string(),
- "DISTINCT Any WHERE X is CWUser, X login 'admin'")
+ 'DISTINCT Any WHERE X is CWUser, X login "admin"')
def test_bitfield(self):
with self.admin_access.web_request() as req:
@@ -310,12 +310,12 @@
self.assertEqual(f.possible_values(), ['admin',])
# ensure rqlst is left unmodified
self.assertEqual(rqlst.as_string(), 'DISTINCT Any WHERE X is CWUser')
- req.form[f.__regid__] = 'admin'
+ req.form[f.__regid__] = u'admin'
f.add_rql_restrictions()
# selection is cluttered because rqlst has been prepared for facet (it
# is not in real life)
self.assertEqual(f.select.as_string(),
- "DISTINCT Any WHERE X is CWUser, X created_by G, G owned_by H, H login 'admin'")
+ 'DISTINCT Any WHERE X is CWUser, X created_by G, G owned_by H, H login "admin"')
def test_rql_path_check_filter_label_variable(self):
with self.admin_access.web_request() as req:
@@ -359,13 +359,13 @@
def prepareg_aggregat_rqlst(self, req):
return self.prepare_rqlst(req,
- 'Any 1, COUNT(X) WHERE X is CWUser, X creation_date XD, '
- 'X modification_date XM, Y creation_date YD, Y is CWGroup '
- 'HAVING DAY(XD)>=DAY(YD) AND DAY(XM)<=DAY(YD)', 'X',
- expected_baserql='Any 1,COUNT(X) WHERE X is CWUser, X creation_date XD, '
+ u'Any 1, COUNT(X) WHERE X is CWUser, X creation_date XD, '
+ 'X modification_date XM, Y creation_date YD, Y is CWGroup '
+ 'HAVING DAY(XD)>=DAY(YD) AND DAY(XM)<=DAY(YD)', 'X',
+ expected_baserql=u'Any 1,COUNT(X) WHERE X is CWUser, X creation_date XD, '
'X modification_date XM, Y creation_date YD, Y is CWGroup '
'HAVING DAY(XD) >= DAY(YD), DAY(XM) <= DAY(YD)',
- expected_preparedrql='DISTINCT Any WHERE X is CWUser, X creation_date XD, '
+ expected_preparedrql=u'DISTINCT Any WHERE X is CWUser, X creation_date XD, '
'X modification_date XM, Y creation_date YD, Y is CWGroup '
'HAVING DAY(XD) >= DAY(YD), DAY(XM) <= DAY(YD)')
@@ -390,13 +390,13 @@
filtered_variable=filtered_variable)
self.assertEqual(f.vocabulary(), [(u'admin', u'admin')])
self.assertEqual(f.possible_values(), ['admin'])
- req.form[f.__regid__] = 'admin'
+ req.form[f.__regid__] = u'admin'
f.add_rql_restrictions()
self.assertEqual(f.select.as_string(),
- "DISTINCT Any WHERE X is CWUser, X creation_date XD, "
- "X modification_date XM, Y creation_date YD, Y is CWGroup, "
- "X created_by G, G owned_by H, H login 'admin' "
- "HAVING DAY(XD) >= DAY(YD), DAY(XM) <= DAY(YD)")
+ 'DISTINCT Any WHERE X is CWUser, X creation_date XD, '
+ 'X modification_date XM, Y creation_date YD, Y is CWGroup, '
+ 'X created_by G, G owned_by H, H login "admin" '
+ 'HAVING DAY(XD) >= DAY(YD), DAY(XM) <= DAY(YD)')
def test_aggregat_query_attribute(self):
with self.admin_access.web_request() as req:
@@ -409,12 +409,12 @@
[(u'admin', u'admin'), (u'anon', u'anon')])
self.assertEqual(f.possible_values(),
['admin', 'anon'])
- req.form[f.__regid__] = 'admin'
+ req.form[f.__regid__] = u'admin'
f.add_rql_restrictions()
self.assertEqual(f.select.as_string(),
- "DISTINCT Any WHERE X is CWUser, X creation_date XD, "
- "X modification_date XM, Y creation_date YD, Y is CWGroup, X login 'admin' "
- "HAVING DAY(XD) >= DAY(YD), DAY(XM) <= DAY(YD)")
+ 'DISTINCT Any WHERE X is CWUser, X creation_date XD, '
+ 'X modification_date XM, Y creation_date YD, Y is CWGroup, X login "admin" '
+ 'HAVING DAY(XD) >= DAY(YD), DAY(XM) <= DAY(YD)')
if __name__ == '__main__':
from logilab.common.testlib import unittest_main
--- a/web/test/unittest_form.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_form.py Thu Dec 10 12:34:15 2015 +0100
@@ -21,6 +21,8 @@
from xml.etree.ElementTree import fromstring
from lxml import html
+from six import text_type
+
from logilab.common.testlib import unittest_main
from cubicweb import Binary, ValidationError
@@ -65,19 +67,19 @@
t = req.create_entity('Tag', name=u'x')
form1 = self.vreg['forms'].select('edition', req, entity=t)
choices = [reid for rview, reid in form1.field_by_name('tags', 'subject', t.e_schema).choices(form1)]
- self.assertIn(unicode(b.eid), choices)
+ self.assertIn(text_type(b.eid), choices)
form2 = self.vreg['forms'].select('edition', req, entity=b)
choices = [reid for rview, reid in form2.field_by_name('tags', 'object', t.e_schema).choices(form2)]
- self.assertIn(unicode(t.eid), choices)
+ self.assertIn(text_type(t.eid), choices)
b.cw_clear_all_caches()
t.cw_clear_all_caches()
req.cnx.execute('SET X tags Y WHERE X is Tag, Y is BlogEntry')
choices = [reid for rview, reid in form1.field_by_name('tags', 'subject', t.e_schema).choices(form1)]
- self.assertIn(unicode(b.eid), choices)
+ self.assertIn(text_type(b.eid), choices)
choices = [reid for rview, reid in form2.field_by_name('tags', 'object', t.e_schema).choices(form2)]
- self.assertIn(unicode(t.eid), choices)
+ self.assertIn(text_type(t.eid), choices)
def test_form_field_choices_new_entity(self):
with self.admin_access.web_request() as req:
@@ -217,7 +219,7 @@
eidparam=True, role='subject')
with self.admin_access.web_request() as req:
file = req.create_entity('File', data_name=u"pouet.txt", data_encoding=u'UTF-8',
- data=Binary('new widgets system'))
+ data=Binary(b'new widgets system'))
form = FFForm(req, redirect_path='perdu.com', entity=file)
self.assertMultiLineEqual(self._render_entity_field(req, 'data', form),
'''<input id="data-subject:%(eid)s" name="data-subject:%(eid)s" tabindex="1" type="file" value="" />
@@ -241,7 +243,7 @@
eidparam=True, role='subject')
with self.admin_access.web_request() as req:
file = req.create_entity('File', data_name=u"pouet.txt", data_encoding=u'UTF-8',
- data=Binary('new widgets system'))
+ data=Binary(b'new widgets system'))
form = EFFForm(req, redirect_path='perdu.com', entity=file)
self.assertMultiLineEqual(self._render_entity_field(req, 'data', form),
'''<input id="data-subject:%(eid)s" name="data-subject:%(eid)s" tabindex="1" type="file" value="" />
--- a/web/test/unittest_formfields.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_formfields.py Thu Dec 10 12:34:15 2015 +0100
@@ -21,6 +21,7 @@
from yams.constraints import StaticVocabularyConstraint, SizeConstraint
+import cubicweb
from cubicweb.devtools import TestServerConfiguration
from cubicweb.devtools.testlib import CubicWebTC
from cubicweb.web.formwidgets import PasswordInput, TextArea, Select, Radio
@@ -127,7 +128,7 @@
self.assertIsInstance(field, BooleanField)
self.assertEqual(field.required, False)
self.assertIsInstance(field.widget, Radio)
- self.assertEqual(field.vocabulary(mock(_cw=mock(_=unicode))),
+ self.assertEqual(field.vocabulary(mock(_cw=mock(_=cubicweb._))),
[(u'yes', '1'), (u'no', '')])
def test_bool_field_explicit_choices(self):
@@ -135,7 +136,7 @@
field = guess_field(schema['CWAttribute'], schema['indexed'],
choices=[(u'maybe', '1'), (u'no', '')], req=req)
self.assertIsInstance(field.widget, Radio)
- self.assertEqual(field.vocabulary(mock(req=mock(_=unicode))),
+ self.assertEqual(field.vocabulary(mock(req=mock(_=cubicweb._))),
[(u'maybe', '1'), (u'no', '')])
--- a/web/test/unittest_formwidgets.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_formwidgets.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,23 +17,18 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""unittests for cw.web.formwidgets"""
-from logilab.common.testlib import TestCase, unittest_main, mock_object as mock
-
-from cubicweb.devtools import TestServerConfiguration, fake
-from cubicweb.web import formwidgets, formfields
-
-from cubes.file.entities import File
+from logilab.common.testlib import unittest_main, mock_object as mock
-def setUpModule(*args):
- global schema
- config = TestServerConfiguration('data', apphome=WidgetsTC.datadir)
- config.bootstrap_cubes()
- schema = config.load_schema()
+from cubicweb.devtools import fake
+from cubicweb.devtools.testlib import CubicWebTC
+from cubicweb.web import formwidgets, formfields
+from cubicweb.web.views.forms import FieldsForm
-class WidgetsTC(TestCase):
+
+class WidgetsTC(CubicWebTC):
def test_editableurl_widget(self):
- field = formfields.guess_field(schema['Bookmark'], schema['path'])
+ field = formfields.guess_field(self.schema['Bookmark'], self.schema['path'])
widget = formwidgets.EditableURLWidget()
req = fake.FakeRequest(form={'path-subjectfqs:A': 'param=value&vid=view'})
form = mock(_cw=req, formvalues={}, edited_entity=mock(eid='A'))
@@ -41,7 +36,7 @@
'?param=value%26vid%3Dview')
def test_bitselect_widget(self):
- field = formfields.guess_field(schema['CWAttribute'], schema['ordernum'])
+ field = formfields.guess_field(self.schema['CWAttribute'], self.schema['ordernum'])
field.choices = [('un', '1',), ('deux', '2',)]
widget = formwidgets.BitSelect(settabindex=False)
req = fake.FakeRequest(form={'ordernum-subject:A': ['1', '2']})
@@ -56,5 +51,21 @@
self.assertEqual(widget.process_field_data(form, field),
3)
+ def test_xml_escape_checkbox(self):
+ class TestForm(FieldsForm):
+ bool = formfields.BooleanField(ignore_req_params=True,
+ choices=[('python >> others', '1')],
+ widget=formwidgets.CheckBox())
+ with self.admin_access.web_request() as req:
+ form = TestForm(req, None)
+ form.build_context()
+ field = form.field_by_name('bool')
+ widget = field.widget
+ self.assertMultiLineEqual(widget._render(form, field, None),
+ '<label><input id="bool" name="bool" tabindex="1" '
+ 'type="checkbox" value="1" /> '
+ 'python >> others</label>')
+
+
if __name__ == '__main__':
unittest_main()
--- a/web/test/unittest_http.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_http.py Thu Dec 10 12:34:15 2015 +0100
@@ -253,46 +253,6 @@
req = _test_cache(hin, hout, method='POST')
self.assertCache(412, req.status_out, 'not modifier HEAD verb')
- @tag('expires')
- def test_expires_added(self):
- #: Check that Expires header is added:
- #: - when the page is modified
- #: - when none was already present
- hin = [('if-none-match', 'babar'),
- ]
- hout = [('etag', 'rhino/really-not-babar'),
- ]
- req = _test_cache(hin, hout)
- self.assertCache(None, req.status_out, 'modifier HEAD verb')
- value = req.headers_out.getHeader('expires')
- self.assertIsNotNone(value)
-
- @tag('expires')
- def test_expires_not_added(self):
- #: Check that Expires header is not added if NOT-MODIFIED
- hin = [('if-none-match', 'babar'),
- ]
- hout = [('etag', 'babar'),
- ]
- req = _test_cache(hin, hout)
- self.assertCache(304, req.status_out, 'not modifier HEAD verb')
- value = req.headers_out.getHeader('expires')
- self.assertIsNone(value)
-
- @tag('expires')
- def test_expires_no_overwrite(self):
- #: Check that cache does not overwrite existing Expires header
- hin = [('if-none-match', 'babar'),
- ]
- DATE = 'Sat, 13 Apr 2012 14:39:32 GM'
- hout = [('etag', 'rhino/really-not-babar'),
- ('expires', DATE),
- ]
- req = _test_cache(hin, hout)
- self.assertCache(None, req.status_out, 'not modifier HEAD verb')
- value = req.headers_out.getRawHeaders('expires')
- self.assertEqual(value, [DATE])
-
alloworig = 'access-control-allow-origin'
allowmethods = 'access-control-allow-methods'
--- a/web/test/unittest_idownloadable.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_idownloadable.py Thu Dec 10 12:34:15 2015 +0100
@@ -42,7 +42,7 @@
return self.entity.name() + '.txt'
def download_data(self):
- return 'Babar is not dead!'
+ return b'Babar is not dead!'
class BrokenIDownloadableGroup(IDownloadableUser):
@@ -72,7 +72,7 @@
get('content-disposition'))
self.assertEqual(['text/plain;charset=ascii'],
get('content-type'))
- self.assertEqual('Babar is not dead!', data)
+ self.assertEqual(b'Babar is not dead!', data)
def test_header_with_space(self):
with self.admin_access.web_request() as req:
@@ -87,13 +87,13 @@
get('content-disposition'))
self.assertEqual(['text/plain;charset=ascii'],
get('content-type'))
- self.assertEqual('Babar is not dead!', data)
+ self.assertEqual(b'Babar is not dead!', data)
def test_header_with_space_and_comma(self):
with self.admin_access.web_request() as req:
- self.create_user(req, login=ur'c " l\ a', password='babar')
+ self.create_user(req, login=u'c " l\\ a', password='babar')
req.cnx.commit()
- with self.new_access(ur'c " l\ a').web_request() as req:
+ with self.new_access(u'c " l\\ a').web_request() as req:
req.form['vid'] = 'download'
req.form['eid'] = str(req.user.eid)
data = self.ctrl_publish(req,'view')
@@ -102,7 +102,7 @@
get('content-disposition'))
self.assertEqual(['text/plain;charset=ascii'],
get('content-type'))
- self.assertEqual('Babar is not dead!', data)
+ self.assertEqual(b'Babar is not dead!', data)
def test_header_unicode_filename(self):
with self.admin_access.web_request() as req:
--- a/web/test/unittest_magicsearch.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_magicsearch.py Thu Dec 10 12:34:15 2015 +0100
@@ -21,6 +21,8 @@
import sys
from contextlib import contextmanager
+from six.moves import range
+
from logilab.common.testlib import TestCase, unittest_main
from rql import BadRQLQuery, RQLSyntaxError
@@ -62,19 +64,19 @@
def test_basic_translations(self):
"""tests basic translations (no ambiguities)"""
with self.proc() as proc:
- rql = "Any C WHERE C is Adresse, P adel C, C adresse 'Logilab'"
+ rql = u"Any C WHERE C is Adresse, P adel C, C adresse 'Logilab'"
rql, = proc.preprocess_query(rql)
- self.assertEqual(rql, "Any C WHERE C is EmailAddress, P use_email C, C address 'Logilab'")
+ self.assertEqual(rql, 'Any C WHERE C is EmailAddress, P use_email C, C address "Logilab"')
def test_ambiguous_translations(self):
"""tests possibly ambiguous translations"""
with self.proc() as proc:
- rql = "Any P WHERE P adel C, C is EmailAddress, C nom 'Logilab'"
+ rql = u"Any P WHERE P adel C, C is EmailAddress, C nom 'Logilab'"
rql, = proc.preprocess_query(rql)
- self.assertEqual(rql, "Any P WHERE P use_email C, C is EmailAddress, C alias 'Logilab'")
- rql = "Any P WHERE P is Utilisateur, P adel C, P nom 'Smith'"
+ self.assertEqual(rql, 'Any P WHERE P use_email C, C is EmailAddress, C alias "Logilab"')
+ rql = u"Any P WHERE P is Utilisateur, P adel C, P nom 'Smith'"
rql, = proc.preprocess_query(rql)
- self.assertEqual(rql, "Any P WHERE P is CWUser, P use_email C, P surname 'Smith'")
+ self.assertEqual(rql, 'Any P WHERE P is CWUser, P use_email C, P surname "Smith"')
class QSPreProcessorTC(CubicWebTC):
@@ -330,7 +332,7 @@
# suggestions should contain any possible value for
# a given attribute (limited to 10)
with self.admin_access.web_request() as req:
- for i in xrange(15):
+ for i in range(15):
req.create_entity('Personne', nom=u'n%s' % i, prenom=u'p%s' % i)
req.cnx.commit()
self.assertListEqual(['Any X WHERE X is Personne, X nom "n0"',
--- a/web/test/unittest_propertysheet.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_propertysheet.py Thu Dec 10 12:34:15 2015 +0100
@@ -49,19 +49,14 @@
'a {bgcolor: #FFFFFF; size: 1%;}')
self.assertEqual(ps.process_resource(DATADIR, 'pouet.css'),
self.cachedir)
- self.assertIn('pouet.css', ps._cache)
self.assertFalse(ps.need_reload())
os.utime(self.data('sheet1.py'), None)
- self.assertIn('pouet.css', ps._cache)
self.assertTrue(ps.need_reload())
- self.assertIn('pouet.css', ps._cache)
ps.reload()
- self.assertNotIn('pouet.css', ps._cache)
self.assertFalse(ps.need_reload())
ps.process_resource(DATADIR, 'pouet.css') # put in cache
os.utime(self.data('pouet.css'), None)
self.assertFalse(ps.need_reload())
- self.assertNotIn('pouet.css', ps._cache)
if __name__ == '__main__':
--- a/web/test/unittest_urlpublisher.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_urlpublisher.py Thu Dec 10 12:34:15 2015 +0100
@@ -25,7 +25,7 @@
from cubicweb.rset import ResultSet
from cubicweb.devtools.testlib import CubicWebTC
from cubicweb.devtools.fake import FakeRequest
-from cubicweb.web import NotFound, Redirect
+from cubicweb.web import NotFound, Redirect, views
from cubicweb.web.views.urlrewrite import SimpleReqRewriter
@@ -69,6 +69,7 @@
self.assertEqual("Any X,AA,AB ORDERBY AB WHERE X is_instance_of CWEType, "
"X modification_date AA, X name AB",
rset.printable_rql())
+ self.assertEqual(req.form['vid'], 'sameetypelist')
def test_rest_path_by_attr(self):
with self.admin_access.web_request() as req:
@@ -91,10 +92,11 @@
'X firstname AA, X login AB, X modification_date AC, '
'X surname AD, X login "admin"',
rset.printable_rql())
+ self.assertEqual(req.form['vid'], 'primary')
def test_rest_path_eid(self):
with self.admin_access.web_request() as req:
- ctrl, rset = self.process(req, 'cwuser/eid/%s' % self.user(req).eid)
+ ctrl, rset = self.process(req, 'cwuser/eid/%s' % req.user.eid)
self.assertEqual(ctrl, 'view')
self.assertEqual(len(rset), 1)
self.assertEqual(rset.description[0][0], 'CWUser')
@@ -125,6 +127,15 @@
'X title "hell\'o"',
rset.printable_rql())
+ def test_rest_path_use_vid_from_rset(self):
+ with self.admin_access.web_request(headers={'Accept': 'application/rdf+xml'}) as req:
+ views.VID_BY_MIMETYPE['application/rdf+xml'] = 'rdf'
+ try:
+ ctrl, rset = self.process(req, 'CWEType')
+ finally:
+ views.VID_BY_MIMETYPE.pop('application/rdf+xml')
+ self.assertEqual(req.form['vid'], 'rdf')
+
def test_rest_path_errors(self):
with self.admin_access.web_request() as req:
self.assertRaises(NotFound, self.process, req, 'CWUser/eid/30000')
@@ -141,25 +152,24 @@
self.assertRaises(NotFound, self.process, req, '1/non_action')
self.assertRaises(NotFound, self.process, req, 'CWUser/login/admin/non_action')
-
def test_regexp_path(self):
"""tests the regexp path resolution"""
with self.admin_access.web_request() as req:
ctrl, rset = self.process(req, 'add/Task')
self.assertEqual(ctrl, 'view')
self.assertEqual(rset, None)
- self.assertEqual(req.form, {'etype' : "Task", 'vid' : "creation"})
+ self.assertEqual(req.form, {'etype': "Task", 'vid': "creation"})
self.assertRaises(NotFound, self.process, req, 'add/foo/bar')
def test_nonascii_path(self):
oldrules = SimpleReqRewriter.rules
- SimpleReqRewriter.rules = [(re.compile('/\w+', re.U), dict(vid='foo')),]
+ SimpleReqRewriter.rules = [(re.compile('/\w+', re.U), dict(vid='foo'))]
with self.admin_access.web_request() as req:
try:
path = str(FakeRequest().url_quote(u'été'))
ctrl, rset = self.process(req, path)
self.assertEqual(rset, None)
- self.assertEqual(req.form, {'vid' : "foo"})
+ self.assertEqual(req.form, {'vid': "foo"})
finally:
SimpleReqRewriter.rules = oldrules
--- a/web/test/unittest_urlrewrite.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_urlrewrite.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,6 +16,8 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+from six import text_type
+
from logilab.common import tempattr
from cubicweb.devtools.testlib import CubicWebTC
@@ -137,8 +139,8 @@
rgx_action(r'Any X WHERE X surname %(sn)s, '
'X firstname %(fn)s',
argsgroups=('sn', 'fn'),
- transforms={'sn' : unicode.capitalize,
- 'fn' : unicode.lower,})),
+ transforms={'sn' : text_type.capitalize,
+ 'fn' : text_type.lower,})),
]
with self.admin_access.web_request() as req:
rewriter = TestSchemaBasedRewriter(req)
--- a/web/test/unittest_views_basecontrollers.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_views_basecontrollers.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,12 +17,8 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""cubicweb.web.views.basecontrollers unit tests"""
-from urlparse import urlsplit, urlunsplit, urljoin
-# parse_qs is deprecated in cgi and has been moved to urlparse in Python 2.6
-try:
- from urlparse import parse_qs as url_parse_query
-except ImportError:
- from cgi import parse_qs as url_parse_query
+from six import text_type
+from six.moves.urllib.parse import urlsplit, urlunsplit, urljoin, parse_qs
import lxml
@@ -82,7 +78,7 @@
}
with self.assertRaises(ValidationError) as cm:
self.ctrl_publish(req)
- cm.exception.translate(unicode)
+ cm.exception.translate(text_type)
self.assertEqual({'login-subject': 'the value "admin" is already used, use another one'},
cm.exception.errors)
@@ -136,12 +132,12 @@
user = req.user
groupeids = [eid for eid, in req.execute('CWGroup G WHERE G name '
'in ("managers", "users")')]
- groups = [unicode(eid) for eid in groupeids]
- eid = unicode(user.eid)
+ groups = [text_type(eid) for eid in groupeids]
+ eid = text_type(user.eid)
req.form = {
'eid': eid, '__type:'+eid: 'CWUser',
'_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject,in_group-subject',
- 'login-subject:'+eid: unicode(user.login),
+ 'login-subject:'+eid: text_type(user.login),
'surname-subject:'+eid: u'Th\xe9nault',
'firstname-subject:'+eid: u'Sylvain',
'in_group-subject:'+eid: groups,
@@ -159,7 +155,7 @@
self.create_user(cnx, u'user')
cnx.commit()
with self.new_access(u'user').web_request() as req:
- eid = unicode(req.user.eid)
+ eid = text_type(req.user.eid)
req.form = {
'eid': eid, '__maineid' : eid,
'__type:'+eid: 'CWUser',
@@ -179,12 +175,12 @@
with self.admin_access.web_request() as req:
user = req.user
groupeids = [g.eid for g in user.in_group]
- eid = unicode(user.eid)
+ eid = text_type(user.eid)
req.form = {
'eid': eid,
'__type:'+eid: 'CWUser',
'_cw_entity_fields:'+eid: 'login-subject,firstname-subject,surname-subject',
- 'login-subject:'+eid: unicode(user.login),
+ 'login-subject:'+eid: text_type(user.login),
'firstname-subject:'+eid: u'Th\xe9nault',
'surname-subject:'+eid: u'Sylvain',
}
@@ -207,7 +203,7 @@
'login-subject:X': u'adim',
'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
'surname-subject:X': u'Di Mascio',
- 'in_group-subject:X': unicode(gueid),
+ 'in_group-subject:X': text_type(gueid),
'__type:Y': 'EmailAddress',
'_cw_entity_fields:Y': 'address-subject,use_email-object',
@@ -231,7 +227,7 @@
'__type:Y': 'File',
'_cw_entity_fields:Y': 'data-subject,described_by_test-object',
- 'data-subject:Y': (u'coucou.txt', Binary('coucou')),
+ 'data-subject:Y': (u'coucou.txt', Binary(b'coucou')),
'described_by_test-object:Y': 'X',
}
path, _params = self.expect_redirect_handle_request(req, 'edit')
@@ -256,7 +252,7 @@
'__type:Y': 'File',
'_cw_entity_fields:Y': 'data-subject',
- 'data-subject:Y': (u'coucou.txt', Binary('coucou')),
+ 'data-subject:Y': (u'coucou.txt', Binary(b'coucou')),
}
path, _params = self.expect_redirect_handle_request(req, 'edit')
self.assertTrue(path.startswith('salesterm/'), path)
@@ -274,7 +270,7 @@
# non regression test for #3120495. Without the fix, leads to
# "unhashable type: 'list'" error
with self.admin_access.web_request() as req:
- cwrelation = unicode(req.execute('CWEType X WHERE X name "CWSource"')[0][0])
+ cwrelation = text_type(req.execute('CWEType X WHERE X name "CWSource"')[0][0])
req.form = {'eid': [cwrelation], '__maineid' : cwrelation,
'__type:'+cwrelation: 'CWEType',
@@ -287,7 +283,7 @@
def test_edit_multiple_linked(self):
with self.admin_access.web_request() as req:
- peid = unicode(self.create_user(req, u'adim').eid)
+ peid = text_type(self.create_user(req, u'adim').eid)
req.form = {'eid': [peid, 'Y'], '__maineid': peid,
'__type:'+peid: u'CWUser',
@@ -307,7 +303,7 @@
self.assertEqual(email.address, 'dima@logilab.fr')
# with self.admin_access.web_request() as req:
- emaileid = unicode(email.eid)
+ emaileid = text_type(email.eid)
req.form = {'eid': [peid, emaileid],
'__type:'+peid: u'CWUser',
@@ -329,7 +325,7 @@
with self.admin_access.web_request() as req:
user = req.user
req.form = {'eid': 'X',
- '__cloned_eid:X': unicode(user.eid), '__type:X': 'CWUser',
+ '__cloned_eid:X': text_type(user.eid), '__type:X': 'CWUser',
'_cw_entity_fields:X': 'login-subject,upassword-subject',
'login-subject:X': u'toto',
'upassword-subject:X': u'toto',
@@ -338,7 +334,7 @@
self.ctrl_publish(req)
self.assertEqual({'upassword-subject': u'password and confirmation don\'t match'},
cm.exception.errors)
- req.form = {'__cloned_eid:X': unicode(user.eid),
+ req.form = {'__cloned_eid:X': text_type(user.eid),
'eid': 'X', '__type:X': 'CWUser',
'_cw_entity_fields:X': 'login-subject,upassword-subject',
'login-subject:X': u'toto',
@@ -354,7 +350,7 @@
def test_interval_bound_constraint_success(self):
with self.admin_access.repo_cnx() as cnx:
feid = cnx.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
- {'data': Binary('yo')})[0][0]
+ {'data': Binary(b'yo')})[0][0]
cnx.commit()
with self.admin_access.web_request(rollbackfirst=True) as req:
@@ -362,11 +358,11 @@
'__type:X': 'Salesterm',
'_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
'amount-subject:X': u'-10',
- 'described_by_test-subject:X': unicode(feid),
+ 'described_by_test-subject:X': text_type(feid),
}
with self.assertRaises(ValidationError) as cm:
self.ctrl_publish(req)
- cm.exception.translate(unicode)
+ cm.exception.translate(text_type)
self.assertEqual({'amount-subject': 'value -10 must be >= 0'},
cm.exception.errors)
@@ -375,11 +371,11 @@
'__type:X': 'Salesterm',
'_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
'amount-subject:X': u'110',
- 'described_by_test-subject:X': unicode(feid),
+ 'described_by_test-subject:X': text_type(feid),
}
with self.assertRaises(ValidationError) as cm:
self.ctrl_publish(req)
- cm.exception.translate(unicode)
+ cm.exception.translate(text_type)
self.assertEqual(cm.exception.errors, {'amount-subject': 'value 110 must be <= 100'})
with self.admin_access.web_request(rollbackfirst=True) as req:
@@ -387,7 +383,7 @@
'__type:X': 'Salesterm',
'_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
'amount-subject:X': u'10',
- 'described_by_test-subject:X': unicode(feid),
+ 'described_by_test-subject:X': text_type(feid),
}
self.expect_redirect_handle_request(req, 'edit')
# should be redirected on the created
@@ -400,31 +396,31 @@
constrained attributes"""
with self.admin_access.repo_cnx() as cnx:
feid = cnx.execute('INSERT File X: X data_name "toto.txt", X data %(data)s',
- {'data': Binary('yo')})[0][0]
+ {'data': Binary(b'yo')})[0][0]
seid = cnx.create_entity('Salesterm', amount=0, described_by_test=feid).eid
cnx.commit()
# ensure a value that violate a constraint is properly detected
with self.admin_access.web_request(rollbackfirst=True) as req:
- req.form = {'eid': [unicode(seid)],
+ req.form = {'eid': [text_type(seid)],
'__type:%s'%seid: 'Salesterm',
'_cw_entity_fields:%s'%seid: 'amount-subject',
'amount-subject:%s'%seid: u'-10',
}
self.assertMultiLineEqual('''<script type="text/javascript">
window.parent.handleFormValidationResponse('entityForm', null, null, [false, [%s, {"amount-subject": "value -10 must be >= 0"}], null], null);
-</script>'''%seid, self.ctrl_publish(req, 'validateform'))
+</script>'''%seid, self.ctrl_publish(req, 'validateform').decode('ascii'))
# ensure a value that comply a constraint is properly processed
with self.admin_access.web_request(rollbackfirst=True) as req:
- req.form = {'eid': [unicode(seid)],
+ req.form = {'eid': [text_type(seid)],
'__type:%s'%seid: 'Salesterm',
'_cw_entity_fields:%s'%seid: 'amount-subject',
'amount-subject:%s'%seid: u'20',
}
self.assertMultiLineEqual('''<script type="text/javascript">
window.parent.handleFormValidationResponse('entityForm', null, null, [true, "http://testing.fr/cubicweb/view", null], null);
-</script>''', self.ctrl_publish(req, 'validateform'))
+</script>''', self.ctrl_publish(req, 'validateform').decode('ascii'))
self.assertEqual(20, req.execute('Any V WHERE X amount V, X eid %(eid)s',
{'eid': seid})[0][0])
@@ -433,7 +429,7 @@
'__type:X': 'Salesterm',
'_cw_entity_fields:X': 'amount-subject,described_by_test-subject',
'amount-subject:X': u'0',
- 'described_by_test-subject:X': unicode(feid),
+ 'described_by_test-subject:X': text_type(feid),
}
# ensure a value that is modified in an operation on a modify
@@ -452,11 +448,11 @@
with self.temporary_appobjects(ValidationErrorInOpAfterHook):
self.assertMultiLineEqual('''<script type="text/javascript">
window.parent.handleFormValidationResponse('entityForm', null, null, [false, ["X", {"amount-subject": "value -10 must be >= 0"}], null], null);
-</script>''', self.ctrl_publish(req, 'validateform'))
+</script>''', self.ctrl_publish(req, 'validateform').decode('ascii'))
self.assertMultiLineEqual('''<script type="text/javascript">
window.parent.handleFormValidationResponse('entityForm', null, null, [true, "http://testing.fr/cubicweb/view", null], null);
-</script>''', self.ctrl_publish(req, 'validateform'))
+</script>''', self.ctrl_publish(req, 'validateform').decode('ascii'))
def test_req_pending_insert(self):
"""make sure req's pending insertions are taken into account"""
@@ -541,7 +537,7 @@
def test_redirect_delete_button(self):
with self.admin_access.web_request() as req:
eid = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
- req.form = {'eid': unicode(eid), '__type:%s'%eid: 'BlogEntry',
+ req.form = {'eid': text_type(eid), '__type:%s'%eid: 'BlogEntry',
'__action_delete': ''}
path, params = self.expect_redirect_handle_request(req, 'edit')
self.assertEqual(path, 'blogentry')
@@ -550,14 +546,14 @@
req.execute('SET X use_email E WHERE E eid %(e)s, X eid %(x)s',
{'x': req.user.eid, 'e': eid})
req.cnx.commit()
- req.form = {'eid': unicode(eid), '__type:%s'%eid: 'EmailAddress',
+ req.form = {'eid': text_type(eid), '__type:%s'%eid: 'EmailAddress',
'__action_delete': ''}
path, params = self.expect_redirect_handle_request(req, 'edit')
self.assertEqual(path, 'cwuser/admin')
self.assertIn('_cwmsgid', params)
eid1 = req.create_entity('BlogEntry', title=u'hop', content=u'hop').eid
eid2 = req.create_entity('EmailAddress', address=u'hop@logilab.fr').eid
- req.form = {'eid': [unicode(eid1), unicode(eid2)],
+ req.form = {'eid': [text_type(eid1), text_type(eid2)],
'__type:%s'%eid1: 'BlogEntry',
'__type:%s'%eid2: 'EmailAddress',
'__action_delete': ''}
@@ -607,13 +603,13 @@
groupeids = sorted(eid
for eid, in req.execute('CWGroup G '
'WHERE G name in ("managers", "users")'))
- groups = [unicode(eid) for eid in groupeids]
+ groups = [text_type(eid) for eid in groupeids]
cwetypeeid = req.execute('CWEType X WHERE X name "CWEType"')[0][0]
- basegroups = [unicode(eid)
+ basegroups = [text_type(eid)
for eid, in req.execute('CWGroup G '
'WHERE X read_permission G, X eid %(x)s',
{'x': cwetypeeid})]
- cwetypeeid = unicode(cwetypeeid)
+ cwetypeeid = text_type(cwetypeeid)
req.form = {
'eid': cwetypeeid,
'__type:'+cwetypeeid: 'CWEType',
@@ -662,7 +658,7 @@
'_cw_entity_fields:X': 'login-subject,upassword-subject,in_group-subject',
'login-subject:X': u'adim',
'upassword-subject:X': u'toto', 'upassword-subject-confirm:X': u'toto',
- 'in_group-subject:X': `gueid`,
+ 'in_group-subject:X': repr(gueid),
'__type:Y': 'EmailAddress',
'_cw_entity_fields:Y': 'address-subject,alias-subject,use_email-object',
@@ -737,7 +733,7 @@
'__type:Y': 'File',
'_cw_entity_fields:Y': 'data-subject',
- 'data-subject:Y': (u'coucou.txt', Binary('coucou')),
+ 'data-subject:Y': (u'coucou.txt', Binary(b'coucou')),
}
values_by_eid = dict((eid, req.extract_entity_params(eid, minparams=2))
for eid in req.edited_eids())
@@ -783,7 +779,7 @@
rset = self.john.as_rset()
rset.req = req
source = ctrl.publish()
- self.assertTrue(source.startswith('<div>'))
+ self.assertTrue(source.startswith(b'<div>'))
# def test_json_exec(self):
# rql = 'Any T,N WHERE T is Tag, T name N'
@@ -824,7 +820,7 @@
rset.req = req
source = ctrl.publish()
# maydel jscall
- self.assertIn('ajaxBoxRemoveLinkedEntity', source)
+ self.assertIn(b'ajaxBoxRemoveLinkedEntity', source)
def test_pending_insertion(self):
with self.remote_calling('add_pending_inserts', [['12', 'tags', '13']]) as (_, req):
@@ -887,16 +883,16 @@
# silly tests
def test_external_resource(self):
with self.remote_calling('external_resource', 'RSS_LOGO') as (res, _):
- self.assertEqual(json_dumps(self.config.uiprops['RSS_LOGO']),
+ self.assertEqual(json_dumps(self.config.uiprops['RSS_LOGO']).encode('ascii'),
res)
def test_i18n(self):
with self.remote_calling('i18n', ['bimboom']) as (res, _):
- self.assertEqual(json_dumps(['bimboom']), res)
+ self.assertEqual(json_dumps(['bimboom']).encode('ascii'), res)
def test_format_date(self):
with self.remote_calling('format_date', '2007-01-01 12:00:00') as (res, _):
- self.assertEqual(json_dumps('2007/01/01'), res)
+ self.assertEqual(json_dumps('2007/01/01').encode('ascii'), res)
def test_ajaxfunc_noparameter(self):
@ajaxfunc
@@ -968,7 +964,7 @@
def js_foo(self):
return u'hello'
with self.remote_calling('foo') as (res, _):
- self.assertEqual(res, u'hello')
+ self.assertEqual(res, b'hello')
def test_monkeypatch_jsoncontroller_xhtmlize(self):
with self.assertRaises(RemoteCallFailed):
@@ -979,7 +975,7 @@
def js_foo(self):
return u'hello'
with self.remote_calling('foo') as (res, _):
- self.assertEqual(u'<div>hello</div>', res)
+ self.assertEqual(b'<div>hello</div>', res)
def test_monkeypatch_jsoncontroller_jsonize(self):
with self.assertRaises(RemoteCallFailed):
@@ -990,7 +986,7 @@
def js_foo(self):
return 12
with self.remote_calling('foo') as (res, _):
- self.assertEqual(res, '12')
+ self.assertEqual(res, b'12')
def test_monkeypatch_jsoncontroller_stdfunc(self):
@monkeypatch(JSonController)
@@ -998,7 +994,7 @@
def js_reledit_form(self):
return 12
with self.remote_calling('reledit_form') as (res, _):
- self.assertEqual(res, '12')
+ self.assertEqual(res, b'12')
class UndoControllerTC(CubicWebTC):
@@ -1042,7 +1038,7 @@
"""
with self.admin_access.web_request() as req:
scheme, netloc, path, query, fragment = urlsplit(url)
- query_dict = url_parse_query(query)
+ query_dict = parse_qs(query)
expected_url = urljoin(req.base_url(), expected_path)
self.assertEqual( urlunsplit((scheme, netloc, path, None, None)), expected_url)
@@ -1058,17 +1054,6 @@
result = controller.publish(rset=None)
self.assertURLPath(cm.exception.location, rpath)
- def test_redirect_default(self):
- with self.admin_access.web_request() as req:
- txuuid = self.txuuid_toto_email
- req.form['txuuid'] = txuuid
- req.session.data['breadcrumbs'] = [ urljoin(req.base_url(), path)
- for path in ('tata', 'toto',)]
- controller = self.vreg['controllers'].select('undo', req)
- with self.assertRaises(Redirect) as cm:
- result = controller.publish(rset=None)
- self.assertURLPath(cm.exception.location, 'toto')
-
class LoginControllerTC(CubicWebTC):
--- a/web/test/unittest_views_baseviews.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_views_baseviews.py Thu Dec 10 12:34:15 2015 +0100
@@ -129,8 +129,8 @@
source_lines = [line.strip()
for line in html_source.splitlines(False)
if line.strip()]
- self.assertListEqual(['<!DOCTYPE html>',
- '<html xmlns:cubicweb="http://www.cubicweb.org" lang="en">'],
+ self.assertListEqual([b'<!DOCTYPE html>',
+ b'<html xmlns:cubicweb="http://www.cubicweb.org" lang="en">'],
source_lines[:2])
def test_set_doctype_no_reset_xmldecl(self):
@@ -151,9 +151,9 @@
source_lines = [line.strip()
for line in html_source.splitlines(False)
if line.strip()]
- self.assertListEqual([html_doctype,
- '<html xmlns:cubicweb="http://www.cubicweb.org" lang="cz">',
- '<head>'],
+ self.assertListEqual([html_doctype.encode('ascii'),
+ b'<html xmlns:cubicweb="http://www.cubicweb.org" lang="cz">',
+ b'<head>'],
source_lines[:3])
if __name__ == '__main__':
--- a/web/test/unittest_views_csv.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_views_csv.py Thu Dec 10 12:34:15 2015 +0100
@@ -30,19 +30,19 @@
self.assertEqual(req.headers_out.getRawHeaders('content-type'),
['text/comma-separated-values;charset=UTF-8'])
expected_data = "String;COUNT(CWUser)\nguests;1\nmanagers;1"
- self.assertMultiLineEqual(expected_data, data)
+ self.assertMultiLineEqual(expected_data, data.decode('utf-8'))
def test_csvexport_on_empty_rset(self):
"""Should return the CSV header.
"""
with self.admin_access.web_request() as req:
- rset = req.execute('Any GN,COUNT(X) GROUPBY GN ORDERBY GN '
- 'WHERE X in_group G, G name GN, X login "Miles"')
+ rset = req.execute(u'Any GN,COUNT(X) GROUPBY GN ORDERBY GN '
+ 'WHERE X in_group G, G name GN, X login "Miles"')
data = self.view('csvexport', rset, req=req)
self.assertEqual(req.headers_out.getRawHeaders('content-type'),
['text/comma-separated-values;charset=UTF-8'])
expected_data = "String;COUNT(CWUser)"
- self.assertMultiLineEqual(expected_data, data)
+ self.assertMultiLineEqual(expected_data, data.decode('utf-8'))
if __name__ == '__main__':
--- a/web/test/unittest_views_editforms.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_views_editforms.py Thu Dec 10 12:34:15 2015 +0100
@@ -255,4 +255,3 @@
if __name__ == '__main__':
unittest_main()
-
--- a/web/test/unittest_views_errorform.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_views_errorform.py Thu Dec 10 12:34:15 2015 +0100
@@ -50,8 +50,8 @@
req.data['excinfo'] = sys.exc_info()
req.data['ex'] = e
html = self.view('error', req=req)
- self.failUnless(re.search(r'^<input name="__signature" type="hidden" '
- 'value="[0-9a-f]{32}" />$',
+ self.assertTrue(re.search(b'^<input name="__signature" type="hidden" '
+ b'value="[0-9a-f]{32}" />$',
html.source, re.M))
--- a/web/test/unittest_views_json.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_views_json.py Thu Dec 10 12:34:15 2015 +0100
@@ -16,12 +16,14 @@
#
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+from six import binary_type
+
from cubicweb.devtools.testlib import CubicWebTC
class JsonViewsTC(CubicWebTC):
anonymize = True
- res_jsonp_data = '[["guests", 1]]'
+ res_jsonp_data = b'[["guests", 1]]'
def setUp(self):
super(JsonViewsTC, self).setUp()
@@ -36,7 +38,7 @@
def test_json_rsetexport_empty_rset(self):
with self.admin_access.web_request() as req:
- rset = req.execute('Any X WHERE X is CWUser, X login "foobarbaz"')
+ rset = req.execute(u'Any X WHERE X is CWUser, X login "foobarbaz"')
data = self.view('jsonexport', rset, req=req)
self.assertEqual(req.headers_out.getRawHeaders('content-type'), ['application/json'])
self.assertListEqual(data, [])
@@ -47,10 +49,10 @@
'rql': u'Any GN,COUNT(X) GROUPBY GN ORDERBY GN '
'WHERE X in_group G, G name GN'})
data = self.ctrl_publish(req, ctrl='jsonp')
- self.assertIsInstance(data, str)
+ self.assertIsInstance(data, binary_type)
self.assertEqual(req.headers_out.getRawHeaders('content-type'), ['application/javascript'])
# because jsonp anonymizes data, only 'guests' group should be found
- self.assertEqual(data, 'foo(%s)' % self.res_jsonp_data)
+ self.assertEqual(data, b'foo(' + self.res_jsonp_data + b')')
def test_json_rsetexport_with_jsonp_and_bad_vid(self):
with self.admin_access.web_request() as req:
@@ -61,7 +63,7 @@
data = self.ctrl_publish(req, ctrl='jsonp')
self.assertEqual(req.headers_out.getRawHeaders('content-type'), ['application/javascript'])
# result should be plain json, not the table view
- self.assertEqual(data, 'foo(%s)' % self.res_jsonp_data)
+ self.assertEqual(data, b'foo(' + self.res_jsonp_data + b')')
def test_json_ersetexport(self):
with self.admin_access.web_request() as req:
@@ -71,7 +73,7 @@
self.assertEqual(data[0]['name'], 'guests')
self.assertEqual(data[1]['name'], 'managers')
- rset = req.execute('Any G WHERE G is CWGroup, G name "foo"')
+ rset = req.execute(u'Any G WHERE G is CWGroup, G name "foo"')
data = self.view('ejsonexport', rset, req=req)
self.assertEqual(req.headers_out.getRawHeaders('content-type'), ['application/json'])
self.assertEqual(data, [])
@@ -79,7 +81,7 @@
class NotAnonymousJsonViewsTC(JsonViewsTC):
anonymize = False
- res_jsonp_data = '[["guests", 1], ["managers", 1]]'
+ res_jsonp_data = b'[["guests", 1], ["managers", 1]]'
if __name__ == '__main__':
from logilab.common.testlib import unittest_main
--- a/web/test/unittest_views_searchrestriction.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_views_searchrestriction.py Thu Dec 10 12:34:15 2015 +0100
@@ -37,62 +37,62 @@
@property
def select(self):
- return self.parse('Any B,(NOW - CD),S,V,U,GROUP_CONCAT(TN),VN,P,CD,BMD '
- 'GROUPBY B,CD,S,V,U,VN,P,BMD '
- 'WHERE B in_state S, B creation_date CD, '
- 'B modification_date BMD, T? tags B, T name TN, '
- 'V? bookmarked_by B, V title VN, B created_by U?, '
- 'B in_group P, P name "managers"')
+ return self.parse(u'Any B,(NOW - CD),S,V,U,GROUP_CONCAT(TN),VN,P,CD,BMD '
+ 'GROUPBY B,CD,S,V,U,VN,P,BMD '
+ 'WHERE B in_state S, B creation_date CD, '
+ 'B modification_date BMD, T? tags B, T name TN, '
+ 'V? bookmarked_by B, V title VN, B created_by U?, '
+ 'B in_group P, P name "managers"')
def test_1(self):
self.assertEqual(self._generate(self.select, 'in_state', 'subject', 'name'),
- "DISTINCT Any A,C ORDERBY C WHERE B in_group P, P name 'managers', "
- "B in_state A, B is CWUser, A name C")
+ 'DISTINCT Any A,C ORDERBY C WHERE B in_group P, P name "managers", '
+ 'B in_state A, B is CWUser, A name C')
def test_2(self):
self.assertEqual(self._generate(self.select, 'tags', 'object', 'name'),
- "DISTINCT Any A,C ORDERBY C WHERE B in_group P, P name 'managers', "
- "A tags B, B is CWUser, A name C")
+ 'DISTINCT Any A,C ORDERBY C WHERE B in_group P, P name "managers", '
+ 'A tags B, B is CWUser, A name C')
def test_3(self):
self.assertEqual(self._generate(self.select, 'created_by', 'subject', 'login'),
- "DISTINCT Any A,C ORDERBY C WHERE B in_group P, P name 'managers', "
- "B created_by A, B is CWUser, A login C")
+ 'DISTINCT Any A,C ORDERBY C WHERE B in_group P, P name "managers", '
+ 'B created_by A, B is CWUser, A login C')
def test_4(self):
- self.assertEqual(self._generate(self.parse('Any X WHERE X is CWUser'), 'created_by', 'subject', 'login'),
+ self.assertEqual(self._generate(self.parse(u'Any X WHERE X is CWUser'), 'created_by', 'subject', 'login'),
"DISTINCT Any A,B ORDERBY B WHERE X is CWUser, X created_by A, A login B")
def test_5(self):
- self.assertEqual(self._generate(self.parse('Any X,L WHERE X is CWUser, X login L'), 'created_by', 'subject', 'login'),
+ self.assertEqual(self._generate(self.parse(u'Any X,L WHERE X is CWUser, X login L'), 'created_by', 'subject', 'login'),
"DISTINCT Any A,B ORDERBY B WHERE X is CWUser, X created_by A, A login B")
def test_nonregr1(self):
- select = self.parse('Any T,V WHERE T bookmarked_by V?, '
- 'V in_state VS, VS name "published", T created_by U')
+ select = self.parse(u'Any T,V WHERE T bookmarked_by V?, '
+ 'V in_state VS, VS name "published", T created_by U')
self.assertEqual(self._generate(select, 'created_by', 'subject', 'login'),
"DISTINCT Any A,B ORDERBY B WHERE T created_by U, "
"T created_by A, T is Bookmark, A login B")
def test_nonregr2(self):
#'DISTINCT Any X,TMP,N WHERE P name TMP, X version_of P, P is Project, X is Version, not X in_state S,S name "published", X num N ORDERBY TMP,N'
- select = self.parse('DISTINCT Any V,TN,L ORDERBY TN,L WHERE T nom TN, V connait T, T is Personne, V is CWUser,'
- 'NOT V in_state VS, VS name "published", V login L')
+ select = self.parse(u'DISTINCT Any V,TN,L ORDERBY TN,L WHERE T nom TN, V connait T, T is Personne, V is CWUser,'
+ 'NOT V in_state VS, VS name "published", V login L')
rschema = self.schema['connait']
- for rdefs in rschema.rdefs.itervalues():
+ for rdefs in rschema.rdefs.values():
rdefs.cardinality = '++'
try:
self.assertEqual(self._generate(select, 'in_state', 'subject', 'name'),
- "DISTINCT Any A,B ORDERBY B WHERE V is CWUser, "
- "NOT EXISTS(V in_state VS), VS name 'published', "
- "V in_state A, A name B")
+ 'DISTINCT Any A,B ORDERBY B WHERE V is CWUser, '
+ 'NOT EXISTS(V in_state VS), VS name "published", '
+ 'V in_state A, A name B')
finally:
- for rdefs in rschema.rdefs.itervalues():
+ for rdefs in rschema.rdefs.values():
rdefs.cardinality = '**'
def test_nonregr3(self):
#'DISTINCT Any X,TMP,N WHERE P name TMP, X version_of P, P is Project, X is Version, not X in_state S,S name "published", X num N ORDERBY TMP,N'
- select = self.parse('DISTINCT Any X, MAX(Y) GROUPBY X WHERE X is CWUser, Y is Bookmark, X in_group A')
+ select = self.parse(u'DISTINCT Any X, MAX(Y) GROUPBY X WHERE X is CWUser, Y is Bookmark, X in_group A')
self.assertEqual(self._generate(select, 'in_group', 'subject', 'name'),
"DISTINCT Any B,C ORDERBY C WHERE X is CWUser, X in_group B, B name C")
--- a/web/test/unittest_views_staticcontrollers.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_views_staticcontrollers.py Thu Dec 10 12:34:15 2015 +0100
@@ -70,12 +70,21 @@
with self._publish_static_files(fname) as req:
self.assertEqual(200, req.status_out)
self.assertIn('last-modified', req.headers_out)
+ self.assertIn('expires', req.headers_out)
+ self.assertEqual(req.get_response_header('cache-control'),
+ {'max-age': 604800})
next_headers = {
'if-modified-since': req.get_response_header('last-modified', raw=True),
}
with self._publish_static_files(fname, next_headers) as req:
self.assertEqual(304, req.status_out)
+ def _check_datafile_redirect(self, fname, expected):
+ with self._publish_static_files(fname) as req:
+ self.assertEqual(302, req.status_out)
+ self.assertEqual(req.get_response_header('location'),
+ req.base_url() + expected)
+
def _check_no_datafile(self, fname):
with self._publish_static_files(fname) as req:
self.assertEqual(404, req.status_out)
@@ -90,10 +99,12 @@
self._check_no_datafile('data/%s/cubicweb.css' % ('0'*len(hash)))
with tempattr(self.vreg.config, 'mode', 'notest'):
- self._check_datafile_ok('data/cubicweb.css')
+ self.config._init_base_url() # reset config.datadir_url
+ self._check_datafile_redirect('data/cubicweb.css', 'data/%s/cubicweb.css' % hash)
self._check_datafile_ok('data/%s/cubicweb.css' % hash)
- self._check_no_datafile('data/does/not/exist')
- self._check_no_datafile('data/%s/cubicweb.css' % ('0'*len(hash)))
+ self._check_no_datafile('data/%s/does/not/exist' % hash)
+ self._check_datafile_redirect('data/%s/does/not/exist' % ('0'*len(hash)),
+ 'data/%s/%s/does/not/exist' % (hash, '0'*len(hash)))
class ConcatFilesTC(CubicWebTC):
@@ -120,12 +131,12 @@
yield res, req
def expected_content(self, js_files):
- content = u''
+ content = b''
for js_file in js_files:
dirpath, rid = self.config.locate_resource(js_file)
if dirpath is not None: # ignore resources not found
- with open(osp.join(dirpath, rid)) as f:
- content += f.read() + '\n'
+ with open(osp.join(dirpath, rid), 'rb') as f:
+ content += f.read() + b'\n'
return content
def test_cache(self):
@@ -162,4 +173,3 @@
if __name__ == '__main__':
from logilab.common.testlib import unittest_main
unittest_main()
-
--- a/web/test/unittest_viewselector.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_viewselector.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,6 +17,7 @@
# You should have received a copy of the GNU Lesser General Public License along
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""XXX rename, split, reorganize this"""
+from __future__ import print_function
from logilab.common.testlib import unittest_main
@@ -76,9 +77,9 @@
try:
self.assertSetEqual(list(content), expected)
except Exception:
- print registry, sorted(expected), sorted(content)
- print 'no more', [v for v in expected if not v in content]
- print 'missing', [v for v in content if not v in expected]
+ print(registry, sorted(expected), sorted(content))
+ print('no more', [v for v in expected if not v in content])
+ print('missing', [v for v in content if not v in expected])
raise
def setUp(self):
@@ -421,7 +422,7 @@
def test_interface_selector(self):
with self.admin_access.web_request() as req:
- req.create_entity('File', data_name=u'bim.png', data=Binary('bim'))
+ req.create_entity('File', data_name=u'bim.png', data=Binary(b'bim'))
# image primary view priority
rset = req.execute('File X WHERE X data_name "bim.png"')
self.assertIsInstance(self.vreg['views'].select('primary', req, rset=rset),
@@ -430,21 +431,21 @@
def test_score_entity_selector(self):
with self.admin_access.web_request() as req:
- req.create_entity('File', data_name=u'bim.png', data=Binary('bim'))
+ req.create_entity('File', data_name=u'bim.png', data=Binary(b'bim'))
# image/ehtml primary view priority
rset = req.execute('File X WHERE X data_name "bim.png"')
self.assertIsInstance(self.vreg['views'].select('image', req, rset=rset),
idownloadable.ImageView)
self.assertRaises(NoSelectableObject, self.vreg['views'].select, 'ehtml', req, rset=rset)
- fileobj = req.create_entity('File', data_name=u'bim.html', data=Binary('<html>bam</html'))
+ fileobj = req.create_entity('File', data_name=u'bim.html', data=Binary(b'<html>bam</html'))
# image/ehtml primary view priority
rset = req.execute('File X WHERE X data_name "bim.html"')
self.assertIsInstance(self.vreg['views'].select('ehtml', req, rset=rset),
idownloadable.EHTMLView)
self.assertRaises(NoSelectableObject, self.vreg['views'].select, 'image', req, rset=rset)
- fileobj = req.create_entity('File', data_name=u'bim.txt', data=Binary('boum'))
+ fileobj = req.create_entity('File', data_name=u'bim.txt', data=Binary(b'boum'))
# image/ehtml primary view priority
rset = req.execute('File X WHERE X data_name "bim.txt"')
self.assertRaises(NoSelectableObject, self.vreg['views'].select, 'image', req, rset=rset)
@@ -461,7 +462,7 @@
obj = self.vreg['views'].select(vid, req, rset=rset, **args)
return obj.render(**args)
except Exception:
- print vid, rset, args
+ print(vid, rset, args)
raise
def test_form(self):
@@ -476,12 +477,12 @@
def test_properties(self):
- self.assertEqual(sorted(k for k in self.vreg['propertydefs'].iterkeys()
+ self.assertEqual(sorted(k for k in self.vreg['propertydefs']
if k.startswith('ctxcomponents.edit_box')),
['ctxcomponents.edit_box.context',
'ctxcomponents.edit_box.order',
'ctxcomponents.edit_box.visible'])
- self.assertEqual([k for k in self.vreg['propertyvalues'].iterkeys()
+ self.assertEqual([k for k in self.vreg['propertyvalues']
if not k.startswith('system.version')],
[])
self.assertEqual(self.vreg.property_value('ctxcomponents.edit_box.visible'), True)
--- a/web/test/unittest_webconfig.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/test/unittest_webconfig.py Thu Dec 10 12:34:15 2015 +0100
@@ -56,5 +56,3 @@
if __name__ == '__main__':
unittest_main()
-
-
--- a/web/uicfg.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/uicfg.py Thu Dec 10 12:34:15 2015 +0100
@@ -26,4 +26,3 @@
warn('[3.16] moved to cubicweb.web.views.uicfg',
DeprecationWarning, stacklevel=2)
-
--- a/web/uihelper.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/uihelper.py Thu Dec 10 12:34:15 2015 +0100
@@ -45,6 +45,7 @@
"""
__docformat__ = "restructuredtext en"
+from six import add_metaclass
from logilab.common.deprecation import deprecated
from cubicweb.web.views import uicfg
@@ -93,6 +94,7 @@
super(meta_formconfig, cls).__init__(name, bases, classdict)
+@add_metaclass(meta_formconfig)
class FormConfig:
"""helper base class to define uicfg rules on a given entity type.
@@ -162,7 +164,6 @@
inlined = ('use_email',)
"""
- __metaclass__ = meta_formconfig
formtype = 'main'
etype = None # must be defined in concrete subclasses
hidden = ()
--- a/web/views/__init__.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/__init__.py Thu Dec 10 12:34:15 2015 +0100
@@ -23,6 +23,8 @@
import sys
import tempfile
+from six import add_metaclass
+
from rql import nodes
from logilab.mtconverter import xml_escape
from logilab.common.deprecation import class_deprecated
@@ -77,7 +79,7 @@
#'text/xml': 'xml',
# XXX rss, owl...
}
-def vid_from_rset(req, rset, schema):
+def vid_from_rset(req, rset, schema, check_table=True):
"""given a result set, return a view id"""
if rset is None:
return 'index'
@@ -90,7 +92,7 @@
return 'noresult'
# entity result set
if not schema.eschema(rset.description[0][0]).final:
- if need_table_view(rset, schema):
+ if check_table and need_table_view(rset, schema):
return 'table'
if nb_rows == 1:
if req.search_state[0] == 'normal':
@@ -127,8 +129,8 @@
+@add_metaclass(class_deprecated)
class TmpFileViewMixin(object):
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.18] %(cls)s is deprecated'
binary = True
content_type = 'application/octet-stream'
--- a/web/views/actions.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/actions.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""Set of HTML base actions"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from warnings import warn
@@ -76,7 +76,7 @@
return 0
select = rqlst.children[0]
if len(select.defined_vars) == 1 and len(select.solutions) == 1:
- rset._searched_etype = select.solutions[0].itervalues().next()
+ rset._searched_etype = next(iter(select.solutions[0].values()))
eschema = req.vreg.schema.eschema(rset._searched_etype)
if not (eschema.final or eschema.is_subobject(strict=True)) \
and eschema.has_perm(req, 'add'):
--- a/web/views/ajaxcontroller.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/ajaxcontroller.py Thu Dec 10 12:34:15 2015 +0100
@@ -66,6 +66,8 @@
from warnings import warn
from functools import partial
+from six import PY2, text_type
+
from logilab.common.date import strptime
from logilab.common.registry import yes
from logilab.common.deprecation import deprecated
@@ -84,7 +86,7 @@
if extraargs is None:
return {}
# we receive unicode keys which is not supported by the **syntax
- return dict((str(key), value) for key, value in extraargs.iteritems())
+ return dict((str(key), value) for key, value in extraargs.items())
class AjaxController(Controller):
@@ -117,7 +119,9 @@
raise RemoteCallFailed('no method specified')
# 1/ check first for old-style (JSonController) ajax func for bw compat
try:
- func = getattr(basecontrollers.JSonController, 'js_%s' % fname).im_func
+ func = getattr(basecontrollers.JSonController, 'js_%s' % fname)
+ if PY2:
+ func = func.__func__
func = partial(func, self)
except AttributeError:
# 2/ check for new-style (AjaxController) ajax func
@@ -150,7 +154,7 @@
if result is None:
return ''
# get unicode on @htmlize methods, encoded string on @jsonize methods
- elif isinstance(result, unicode):
+ elif isinstance(result, text_type):
return result.encode(self._cw.encoding)
return result
--- a/web/views/authentication.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/authentication.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,12 +19,9 @@
__docformat__ = "restructuredtext en"
-from threading import Lock
-
-from logilab.common.decorators import clear_cache
from logilab.common.deprecation import class_renamed
-from cubicweb import AuthenticationError, BadConnectionId
+from cubicweb import AuthenticationError
from cubicweb.view import Component
from cubicweb.web import InvalidSession
@@ -101,41 +98,11 @@
'("ie" instead of "ei")')
-class AbstractAuthenticationManager(Component):
- """authenticate user associated to a request and check session validity"""
- __abstract__ = True
- __regid__ = 'authmanager'
- def __init__(self, repo):
- self.vreg = repo.vreg
-
- def validate_session(self, req, session):
- """check session validity, reconnecting it to the repository if the
- associated connection expired in the repository side (hence the
- necessity for this method).
-
- raise :exc:`InvalidSession` if session is corrupted for a reason or
- another and should be closed
- """
- raise NotImplementedError()
-
- def authenticate(self, req):
- """authenticate user using connection information found in the request,
- and return corresponding a :class:`~cubicweb.dbapi.Connection` instance,
- as well as login and authentication information dictionary used to open
- the connection.
-
- raise :exc:`cubicweb.AuthenticationError` if authentication failed
- (no authentication info found or wrong user/password)
- """
- raise NotImplementedError()
-
-
-class RepositoryAuthenticationManager(AbstractAuthenticationManager):
+class RepositoryAuthenticationManager(object):
"""authenticate user associated to a request and check session validity"""
def __init__(self, repo):
- super(RepositoryAuthenticationManager, self).__init__(repo)
self.repo = repo
vreg = repo.vreg
self.log_queries = vreg.config['query-log-file']
@@ -205,4 +172,3 @@
def _authenticate(self, login, authinfo):
sessionid = self.repo.connect(login, **authinfo)
return self.repo._sessions[sessionid]
-
--- a/web/views/autoform.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/autoform.py Thu Dec 10 12:34:15 2015 +0100
@@ -119,10 +119,12 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from warnings import warn
+from six.moves import range
+
from logilab.mtconverter import xml_escape
from logilab.common.decorators import iclassmethod, cached
from logilab.common.deprecation import deprecated
@@ -355,7 +357,7 @@
self.w(self._cw._('no such entity type %s') % self.etype)
return
entity = cls(self._cw)
- entity.eid = self._cw.varmaker.next()
+ entity.eid = next(self._cw.varmaker)
return entity
def call(self, i18nctx, **kwargs):
@@ -491,7 +493,8 @@
pendings.remove( (int(eidfrom), rel, int(eidto)) )
@ajaxfunc(output_type='json')
-def remove_pending_insert(self, (eidfrom, rel, eidto)):
+def remove_pending_insert(self, args):
+ eidfrom, rel, eidto = args
_remove_pending(self._cw, eidfrom, rel, eidto, 'insert')
@ajaxfunc(output_type='json')
@@ -500,11 +503,13 @@
_add_pending(self._cw, eidfrom, rel, eidto, 'insert')
@ajaxfunc(output_type='json')
-def remove_pending_delete(self, (eidfrom, rel, eidto)):
+def remove_pending_delete(self, args):
+ eidfrom, rel, eidto = args
_remove_pending(self._cw, eidfrom, rel, eidto, 'delete')
@ajaxfunc(output_type='json')
-def add_pending_delete(self, (eidfrom, rel, eidto)):
+def add_pending_delete(self, args):
+ eidfrom, rel, eidto = args
_add_pending(self._cw, eidfrom, rel, eidto, 'delete')
@@ -608,7 +613,7 @@
toggleable_rel_link_func = toggleable_relation_link
else:
toggleable_rel_link_func = lambda x, y, z: u''
- for row in xrange(rset.rowcount):
+ for row in range(rset.rowcount):
nodeid = relation_id(entity.eid, rschema, role,
rset[row][0])
if nodeid in pending_deletes:
@@ -737,7 +742,8 @@
copy_nav_params = True
form_buttons = [fw.SubmitButton(),
fw.Button(stdmsgs.BUTTON_APPLY, cwaction='apply'),
- fw.Button(stdmsgs.BUTTON_CANCEL, cwaction='cancel')]
+ fw.Button(stdmsgs.BUTTON_CANCEL,
+ {'class': fw.Button.css_class + ' cwjs-edition-cancel'})]
# for attributes selection when searching in uicfg.autoform_section
formtype = 'main'
# set this to a list of [(relation, role)] if you want to explictily tell
@@ -1048,4 +1054,4 @@
AutomaticEntityForm.error('field for %s %s may not be found in schema' % (rtype, role))
return None
- vreg.register_all(globals().itervalues(), __name__)
+ vreg.register_all(globals().values(), __name__)
--- a/web/views/basecomponents.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/basecomponents.py Thu Dec 10 12:34:15 2015 +0100
@@ -21,7 +21,7 @@
* the logged user link
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from logilab.mtconverter import xml_escape
from logilab.common.registry import yes
--- a/web/views/basecontrollers.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/basecontrollers.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,10 +20,12 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from warnings import warn
+from six import text_type
+
from logilab.common.deprecation import deprecated
from cubicweb import (NoSelectableObject, ObjectNotFound, ValidationError,
@@ -124,7 +126,6 @@
def publish(self, rset=None):
"""publish a request, returning an encoded string"""
view, rset = self._select_view_and_rset(rset)
- self.add_to_breadcrumbs(view)
view.set_http_cache_headers()
if self._cw.is_client_cache_valid():
return ''
@@ -158,13 +159,6 @@
view = req.vreg['views'].select(vid, req, rset=rset)
return view, rset
- def add_to_breadcrumbs(self, view):
- # update breadcrumbs **before** validating cache, unless the view
- # specifies explicitly it should not be added to breadcrumb or the
- # view is a binary view
- if view.add_to_breadcrumbs and not view.binary:
- self._cw.update_breadcrumbs()
-
def execute_linkto(self, eid=None):
"""XXX __linkto parameter may cause security issue
@@ -233,7 +227,7 @@
except Exception as ex:
req.cnx.rollback()
req.exception('unexpected error while validating form')
- return (False, str(ex).decode('utf-8'), ctrl._edited_entity)
+ return (False, text_type(ex), ctrl._edited_entity)
return (False, '???', None)
@@ -255,9 +249,8 @@
# XXX unclear why we have a separated controller here vs
# js_validate_form on the json controller
status, args, entity = _validate_form(self._cw, self._cw.vreg)
- domid = self._cw.form.get('__domid', 'entityForm').encode(
- self._cw.encoding)
- return self.response(domid, status, args, entity)
+ domid = self._cw.form.get('__domid', 'entityForm')
+ return self.response(domid, status, args, entity).encode(self._cw.encoding)
class JSonController(Controller):
@@ -306,5 +299,4 @@
def redirect(self, msg=None):
req = self._cw
msg = msg or req._("transaction undone")
- self._return_to_lastpage( dict(_cwmsgid= req.set_redirect_message(msg)) )
-
+ self._redirect({'_cwmsgid': req.set_redirect_message(msg)})
--- a/web/views/basetemplates.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/basetemplates.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""default templates for CubicWeb web client"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from logilab.mtconverter import xml_escape
from logilab.common.deprecation import class_renamed
--- a/web/views/baseviews.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/baseviews.py Thu Dec 10 12:34:15 2015 +0100
@@ -76,11 +76,13 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from datetime import timedelta
from warnings import warn
+from six.moves import range
+
from rql import nodes
from logilab.mtconverter import TransformError, xml_escape
@@ -231,8 +233,8 @@
"""
rset = self.cw_rset
if rset is None:
- raise NotImplementedError, self
- for i in xrange(len(rset)):
+ raise NotImplementedError(self)
+ for i in range(len(rset)):
self.wview(self.__regid__, rset, row=i, **kwargs)
if len(rset) > 1:
self.w(u"\n")
@@ -314,7 +316,7 @@
self.w(u'<ul>\n')
else:
self.w(u'<ul%s class="%s">\n' % (listid, klass or 'section'))
- for i in xrange(self.cw_rset.rowcount):
+ for i in range(self.cw_rset.rowcount):
self.cell_call(row=i, col=0, vid=subvid, klass=klass, **kwargs)
self.w(u'</ul>\n')
if title:
@@ -393,7 +395,7 @@
@property
def title(self):
- etype = iter(self.cw_rset.column_types(0)).next()
+ etype = next(iter(self.cw_rset.column_types(0)))
return display_name(self._cw, etype, form='plural')
def call(self, **kwargs):
@@ -427,7 +429,7 @@
def call(self, subvid=None, **kwargs):
kwargs['vid'] = subvid
rset = self.cw_rset
- for i in xrange(len(rset)):
+ for i in range(len(rset)):
self.cell_call(i, 0, **kwargs)
if i < rset.rowcount-1:
self.w(self.separator)
--- a/web/views/bookmark.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/bookmark.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""Primary view for bookmarks + user's bookmarks box"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from logilab.mtconverter import xml_escape
--- a/web/views/boxes.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/boxes.py Thu Dec 10 12:34:15 2015 +0100
@@ -26,10 +26,12 @@
* startup views box
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from warnings import warn
+from six import text_type, add_metaclass
+
from logilab.mtconverter import xml_escape
from logilab.common.deprecation import class_deprecated
@@ -93,7 +95,7 @@
etypes = self.cw_rset.column_types(0)
if len(etypes) == 1:
plural = self.cw_rset.rowcount > 1 and 'plural' or ''
- etypelabel = display_name(self._cw, iter(etypes).next(), plural)
+ etypelabel = display_name(self._cw, next(iter(etypes)), plural)
title = u'%s - %s' % (title, etypelabel.lower())
w(title)
@@ -216,7 +218,7 @@
@property
def domid(self):
- return super(RsetBox, self).domid + unicode(abs(id(self))) + unicode(abs(id(self.cw_rset)))
+ return super(RsetBox, self).domid + text_type(abs(id(self))) + text_type(abs(id(self.cw_rset)))
def render_title(self, w):
w(self.cw_extra_kwargs['title'])
@@ -231,9 +233,9 @@
# helper classes ##############################################################
+@add_metaclass(class_deprecated)
class SideBoxView(EntityView):
"""helper view class to display some entities in a sidebox"""
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.10] SideBoxView is deprecated, use RsetBox instead (%(cls)s)'
__regid__ = 'sidebox'
--- a/web/views/calendar.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/calendar.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""html calendar views"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
import copy
from datetime import timedelta
--- a/web/views/csvexport.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/csvexport.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,10 @@
"""csv export views"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
+
+from six import PY2
+from six.moves import range
from cubicweb.schema import display_name
from cubicweb.predicates import any_rset, empty_rset
@@ -29,7 +32,7 @@
"""mixin class for CSV views"""
templatable = False
content_type = "text/comma-separated-values"
- binary = True # avoid unicode assertion
+ binary = PY2 # python csv module is unicode aware in py3k
csv_params = {'dialect': 'excel',
'quotechar': '"',
'delimiter': ';',
@@ -88,7 +91,7 @@
rows_by_type = {}
writer = self.csvwriter()
rowdef_by_type = {}
- for index in xrange(len(self.cw_rset)):
+ for index in range(len(self.cw_rset)):
entity = self.cw_rset.complete_entity(index)
if entity.e_schema not in rows_by_type:
rowdef_by_type[entity.e_schema] = [rs for rs, at in entity.e_schema.attribute_definitions()
@@ -98,8 +101,7 @@
rows = rows_by_type[entity.e_schema]
rows.append([entity.printable_value(rs.type, format='text/plain')
for rs in rowdef_by_type[entity.e_schema]])
- for rows in rows_by_type.itervalues():
+ for rows in rows_by_type.values():
writer.writerows(rows)
# use two empty lines as separator
writer.writerows([[], []])
-
--- a/web/views/cwproperties.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/cwproperties.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""Specific views for CWProperty (eg site/user preferences"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from logilab.mtconverter import xml_escape
@@ -119,10 +119,10 @@
_ = self._cw._
self.w(u'<h1>%s</h1>\n' % _(self.title))
for label, group, form in sorted((_(g), g, f)
- for g, f in mainforms.iteritems()):
+ for g, f in mainforms.items()):
self.wrap_main_form(group, label, form)
for label, group, objects in sorted((_(g), g, o)
- for g, o in groupedforms.iteritems()):
+ for g, o in groupedforms.items()):
self.wrap_grouped_form(group, label, objects)
@property
@@ -171,7 +171,7 @@
entity = self.cwprops_rset.get_entity(values[key], 0)
else:
entity = self._cw.vreg['etypes'].etype_class('CWProperty')(self._cw)
- entity.eid = self._cw.varmaker.next()
+ entity.eid = next(self._cw.varmaker)
entity.cw_attr_cache['pkey'] = key
entity.cw_attr_cache['value'] = self._cw.vreg.property_value(key)
return entity
@@ -224,7 +224,7 @@
(make_togglable_link('fieldset_' + group, label)))
self.w(u'<div id="fieldset_%s" %s>' % (group, status))
sorted_objects = sorted((self._cw.__('%s_%s' % (group, o)), o, f)
- for o, f in objects.iteritems())
+ for o, f in objects.items())
for label, oid, form in sorted_objects:
self.wrap_object_form(group, oid, label, form)
self.w(u'</div>')
--- a/web/views/cwsources.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/cwsources.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,20 +20,23 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
import logging
from itertools import repeat
+
+from six.moves import range
+
from logilab.mtconverter import xml_escape
from logilab.common.decorators import cachedproperty
from cubicweb import Unauthorized, tags
from cubicweb.utils import make_uid
from cubicweb.predicates import (is_instance, score_entity, has_related_entities,
- match_user_groups, match_kwargs, match_view)
+ match_user_groups, match_kwargs, match_view, one_line_rset)
from cubicweb.view import EntityView, StartupView
from cubicweb.schema import META_RTYPES, VIRTUAL_RTYPES, display_name
-from cubicweb.web import formwidgets as wdgs, facet
+from cubicweb.web import Redirect, formwidgets as wdgs, facet, action
from cubicweb.web.views import add_etype_button
from cubicweb.web.views import (uicfg, tabs, actions, ibreadcrumbs, navigation,
tableview, pyviews)
@@ -95,7 +98,7 @@
if hostconfig:
self.w(u'<h3>%s</h3>' % self._cw._('CWSourceHostConfig_plural'))
self._cw.view('table', hostconfig, w=self.w,
- displaycols=range(2),
+ displaycols=list(range(2)),
cellvids={1: 'editable-final'})
@@ -186,7 +189,7 @@
warning(_('relation %(rtype)s with %(etype)s as %(role)s is '
'supported but no target type supported') %
{'rtype': rschema, 'role': role, 'etype': etype})
- for rtype, rdefs in self.srelations.iteritems():
+ for rtype, rdefs in self.srelations.items():
if rdefs is None:
rschema = self.schema[rtype]
for subj, obj in rschema.rdefs:
@@ -223,6 +226,36 @@
layout_args = {'display_filter': 'top'}
+class CWSourceSyncAction(action.Action):
+ __regid__ = 'cw.source-sync'
+ __select__ = (action.Action.__select__ & match_user_groups('managers')
+ & one_line_rset() & is_instance('CWSource')
+ & score_entity(lambda x: x.name != 'system'))
+
+ title = _('synchronize')
+ category = 'mainactions'
+ order = 20
+
+ def url(self):
+ entity = self.cw_rset.get_entity(self.cw_row or 0, self.cw_col or 0)
+ return entity.absolute_url(vid=self.__regid__)
+
+
+class CWSourceSyncView(EntityView):
+ __regid__ = 'cw.source-sync'
+ __select__ = (match_user_groups('managers')
+ & one_line_rset() & is_instance('CWSource')
+ & score_entity(lambda x: x.name != 'system'))
+
+ title = _('synchronize')
+
+ def entity_call(self, entity):
+ self._cw.call_service('source-sync', source_eid=entity.eid)
+ msg = self._cw._('Source has been synchronized')
+ url = entity.absolute_url(tab='cwsource-imports', __message=msg)
+ raise Redirect(url)
+
+
# sources management view ######################################################
--- a/web/views/cwuser.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/cwuser.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,10 +18,13 @@
"""Specific views for users and groups"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from hashlib import sha1 # pylint: disable=E0611
+from six import text_type
+from six.moves import range
+
from logilab.mtconverter import xml_escape
from cubicweb import tags
@@ -64,7 +67,7 @@
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3org/2000/01/rdf-schema#"
xmlns:foaf="http://xmlns.com/foaf/0.1/"> '''% self._cw.encoding)
- for i in xrange(self.cw_rset.rowcount):
+ for i in range(self.cw_rset.rowcount):
self.cell_call(i, 0)
self.w(u'</rdf:RDF>\n')
@@ -250,6 +253,6 @@
'group': tableview.MainEntityColRenderer(),
'nb_users': tableview.EntityTableColRenderer(
header=_('num. users'),
- renderfunc=lambda w,x: w(unicode(x.num_users())),
+ renderfunc=lambda w,x: w(text_type(x.num_users())),
sortfunc=lambda x: x.num_users()),
}
--- a/web/views/debug.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/debug.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,10 +18,12 @@
"""management and error screens"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from time import strftime, localtime
+from six import text_type
+
from logilab.mtconverter import xml_escape
from cubicweb.predicates import none_rset, match_user_groups
@@ -33,7 +35,7 @@
if dict:
w(u'<ul>')
for key in sorted(dict):
- w(u'<li><span class="label">%s</span>: <span>%s</span></li>' % (
+ w(u'<li><span>%s</span>: <span>%s</span></li>' % (
xml_escape(str(key)), xml_escape(repr(dict[key]))))
w(u'</ul>')
@@ -71,31 +73,23 @@
dtformat = req.property_value('ui.datetime-format')
_ = req._
w = self.w
+ repo = req.cnx.repo
# generic instance information
w(u'<h2>%s</h2>' % _('Instance'))
- w(u'<table>')
- w(u'<tr><th align="left">%s</th><td>%s</td></tr>' % (
- _('config type'), self._cw.vreg.config.name))
- w(u'<tr><th align="left">%s</th><td>%s</td></tr>' % (
- _('config mode'), self._cw.vreg.config.mode))
- w(u'<tr><th align="left">%s</th><td>%s</td></tr>' % (
- _('instance home'), self._cw.vreg.config.apphome))
- w(u'</table>')
- vcconf = req.vreg.config.vc_config()
+ pyvalue = ((_('config type'), self._cw.vreg.config.name),
+ (_('config mode'), self._cw.vreg.config.mode),
+ (_('instance home'), self._cw.vreg.config.apphome))
+ self.wview('pyvaltable', pyvalue=pyvalue, header_column_idx=0)
+ vcconf = repo.get_versions()
w(u'<h3>%s</h3>' % _('versions configuration'))
- w(u'<table>')
- w(u'<tr><th align="left">%s</th><td>%s</td></tr>' % (
- 'CubicWeb', vcconf.get('cubicweb', _('no version information'))))
- for cube in sorted(self._cw.vreg.config.cubes()):
- cubeversion = vcconf.get(cube, _('no version information'))
- w(u'<tr><th align="left">%s</th><td>%s</td></tr>' % (
- cube, cubeversion))
- w(u'</table>')
+ missing = _('no version information')
+ pyvalue = [('CubicWeb', vcconf.get('cubicweb', missing))]
+ pyvalue += [(cube, vcconf.get(cube, missing))
+ for cube in sorted(self._cw.vreg.config.cubes())]
+ self.wview('pyvaltable', pyvalue=pyvalue, header_column_idx=0)
# repository information
- repo = req.vreg.config.repository(None)
w(u'<h2>%s</h2>' % _('Repository'))
w(u'<h3>%s</h3>' % _('resources usage'))
- w(u'<table>')
stats = self._cw.call_service('repo_stats')
stats['looping_tasks'] = ', '.join('%s (%s seconds)' % (n, i) for n, i in stats['looping_tasks'])
stats['threads'] = ', '.join(sorted(stats['threads']))
@@ -104,11 +98,13 @@
continue
if k.endswith('_cache_size'):
stats[k] = '%s / %s' % (stats[k]['size'], stats[k]['maxsize'])
- for element in sorted(stats):
- w(u'<tr><th align="left">%s</th><td>%s %s</td></tr>'
- % (element, xml_escape(unicode(stats[element])),
- element.endswith('percent') and '%' or '' ))
- w(u'</table>')
+ def format_stat(sname, sval):
+ return '%s %s' % (xml_escape(text_type(sval)),
+ sname.endswith('percent') and '%' or '')
+ pyvalue = [(sname, format_stat(sname, sval))
+ for sname, sval in sorted(stats.items())]
+ self.wview('pyvaltable', pyvalue=pyvalue, header_column_idx=0)
+ # open repo sessions
if req.cnx.is_repo_in_memory and req.user.is_in_group('managers'):
w(u'<h3>%s</h3>' % _('opened sessions'))
sessions = repo._sessions.values()
@@ -116,7 +112,7 @@
w(u'<ul>')
for session in sessions:
w(u'<li>%s (%s: %s)<br/>' % (
- xml_escape(unicode(session)),
+ xml_escape(text_type(session)),
_('last usage'),
strftime(dtformat, localtime(session.timestamp))))
dict_to_html(w, session.data)
@@ -126,12 +122,9 @@
w(u'<p>%s</p>' % _('no repository sessions found'))
# web server information
w(u'<h2>%s</h2>' % _('Web server'))
- w(u'<table>')
- w(u'<tr><th align="left">%s</th><td>%s</td></tr>' % (
- _('base url'), req.base_url()))
- w(u'<tr><th align="left">%s</th><td>%s</td></tr>' % (
- _('data directory url'), req.datadir_url))
- w(u'</table>')
+ pyvalue = ((_('base url'), req.base_url()),
+ (_('data directory url'), req.datadir_url))
+ self.wview('pyvaltable', pyvalue=pyvalue, header_column_idx=0)
from cubicweb.web.application import SESSION_MANAGER
if SESSION_MANAGER is not None and req.user.is_in_group('managers'):
sessions = SESSION_MANAGER.current_sessions()
@@ -170,7 +163,7 @@
continue
self.w(u'<h3 id="%s">%s</h3>' % (key, key))
if self._cw.vreg[key]:
- values = sorted(self._cw.vreg[key].iteritems())
+ values = sorted(self._cw.vreg[key].items())
self.wview('pyvaltable', pyvalue=[(key, xml_escape(repr(val)))
for key, val in values])
else:
--- a/web/views/dotgraphview.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/dotgraphview.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""some basic stuff to build dot generated graph images"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
import tempfile
import os
--- a/web/views/editcontroller.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/editcontroller.py Thu Dec 10 12:34:15 2015 +0100
@@ -24,6 +24,8 @@
from datetime import datetime
+from six import text_type
+
from logilab.common.deprecation import deprecated
from logilab.common.graph import ordered_nodes
@@ -93,9 +95,9 @@
def update_query(self, eid):
varmaker = rqlvar_maker()
- var = varmaker.next()
+ var = next(varmaker)
while var in self.kwargs:
- var = varmaker.next()
+ var = next(varmaker)
rql = 'SET %s WHERE X eid %%(%s)s' % (','.join(self.edited), var)
if self.restrictions:
rql += ', %s' % ','.join(self.restrictions)
@@ -143,7 +145,7 @@
values_by_eid = dict((eid, req.extract_entity_params(eid, minparams=2))
for eid in req.edited_eids())
# iterate over all the edited entities
- for eid, values in values_by_eid.iteritems():
+ for eid, values in values_by_eid.items():
# add eid to the dependency graph
graph.setdefault(eid, set())
# search entity's edited fields for mandatory inlined relation
@@ -197,7 +199,7 @@
if '__linkto' in req.form and 'eid' in req.form:
self.execute_linkto()
elif not ('__delete' in req.form or '__insert' in req.form):
- raise ValidationError(None, {None: unicode(ex)})
+ raise ValidationError(None, {None: text_type(ex)})
# all pending inlined relations to newly created entities have been
# treated now (pop to ensure there are no attempt to add new ones)
pending_inlined = req.data.pop('pending_inlined')
@@ -215,7 +217,7 @@
autoform.delete_relations(self._cw, todelete)
self._cw.remove_pending_operations()
if self.errors:
- errors = dict((f.name, unicode(ex)) for f, ex in self.errors)
+ errors = dict((f.name, text_type(ex)) for f, ex in self.errors)
raise ValidationError(valerror_eid(form.get('__maineid')), errors)
def _insert_entity(self, etype, eid, rqlquery):
@@ -265,7 +267,7 @@
for form_, field in req.data['pending_inlined'].pop(entity.eid, ()):
rqlquery.set_inlined(field.name, form_.edited_entity.eid)
if self.errors:
- errors = dict((f.role_name(), unicode(ex)) for f, ex in self.errors)
+ errors = dict((f.role_name(), text_type(ex)) for f, ex in self.errors)
raise ValidationError(valerror_eid(entity.eid), errors)
if eid is None: # creation or copy
entity.eid = eid = self._insert_entity(etype, formparams['eid'], rqlquery)
@@ -316,7 +318,7 @@
"""handle edition for the (rschema, x) relation of the given entity
"""
if values:
- rqlquery.set_inlined(field.name, iter(values).next())
+ rqlquery.set_inlined(field.name, next(iter(values)))
elif form.edited_entity.has_eid():
self.handle_relation(form, field, values, origvalues)
@@ -355,13 +357,13 @@
for eid, etype in eidtypes:
entity = self._cw.entity_from_eid(eid, etype)
path, params = entity.cw_adapt_to('IEditControl').after_deletion_path()
- redirect_info.add( (path, tuple(params.iteritems())) )
+ redirect_info.add( (path, tuple(params.items())) )
entity.cw_delete()
if len(redirect_info) > 1:
# In the face of ambiguity, refuse the temptation to guess.
self._after_deletion_path = 'view', ()
else:
- self._after_deletion_path = iter(redirect_info).next()
+ self._after_deletion_path = next(iter(redirect_info))
if len(eidtypes) > 1:
self._cw.set_message(self._cw._('entities deleted'))
else:
@@ -388,13 +390,6 @@
self._default_publish()
self.reset()
- def _action_cancel(self):
- errorurl = self._cw.form.get('__errorurl')
- if errorurl:
- self._cw.cancel_edition(errorurl)
- self._cw.set_message(self._cw._('edit canceled'))
- return self.reset()
-
def _action_delete(self):
self.delete_entities(self._cw.edited_eids(withtype=True))
return self.reset()
--- a/web/views/editforms.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/editforms.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,10 +20,12 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from copy import copy
+from six.moves import range
+
from logilab.mtconverter import xml_escape
from logilab.common.decorators import cached
from logilab.common.registry import yes
@@ -145,7 +147,7 @@
# selector
etype = kwargs.pop('etype', self._cw.form.get('etype'))
entity = self._cw.vreg['etypes'].etype_class(etype)(self._cw)
- entity.eid = self._cw.varmaker.next()
+ entity.eid = next(self._cw.varmaker)
self.render_form(entity)
def form_title(self, entity):
@@ -197,7 +199,7 @@
entity.complete()
self.newentity = copy(entity)
self.copying = entity
- self.newentity.eid = self._cw.varmaker.next()
+ self.newentity.eid = next(self._cw.varmaker)
self.w(u'<script type="text/javascript">updateMessage("%s");</script>\n'
% self._cw._(self.warning_message))
super(CopyFormView, self).render_form(self.newentity)
@@ -230,7 +232,7 @@
def __init__(self, req, rset, **kwargs):
kwargs.setdefault('__redirectrql', rset.printable_rql())
super(TableEditForm, self).__init__(req, rset=rset, **kwargs)
- for row in xrange(len(self.cw_rset)):
+ for row in range(len(self.cw_rset)):
form = self._cw.vreg['forms'].select('edition', self._cw,
rset=self.cw_rset, row=row,
formtype='muledit',
--- a/web/views/editviews.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/editviews.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""Some views used to help to the edition process"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from logilab.common.decorators import cached
from logilab.mtconverter import xml_escape
--- a/web/views/facets.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/facets.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""the facets box and some basic facets"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from warnings import warn
@@ -168,7 +168,7 @@
DeprecationWarning, stacklevel=2)
else:
vidargs = {}
- vidargs = dict((k, v) for k, v in vidargs.iteritems() if v)
+ vidargs = dict((k, v) for k, v in vidargs.items() if v)
facetargs = xml_escape(json_dumps([divid, vid, paginate, vidargs]))
w(u'<form id="%sForm" class="%s" method="post" action="" '
'cubicweb:facetargs="%s" >' % (divid, cssclass, facetargs))
--- a/web/views/formrenderers.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/formrenderers.py Thu Dec 10 12:34:15 2015 +0100
@@ -33,10 +33,12 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from warnings import warn
+from six import text_type
+
from logilab.mtconverter import xml_escape
from logilab.common.registry import yes
@@ -119,7 +121,7 @@
data.insert(0, errormsg)
# NOTE: we call unicode because `tag` objects may be found within data
# e.g. from the cwtags library
- w(''.join(unicode(x) for x in data))
+ w(''.join(text_type(x) for x in data))
def render_content(self, w, form, values):
if self.display_progress_div:
@@ -241,7 +243,7 @@
if form.fieldsets_in_order:
fieldsets = form.fieldsets_in_order
else:
- fieldsets = byfieldset.iterkeys()
+ fieldsets = byfieldset
for fieldset in list(fieldsets):
try:
fields = byfieldset.pop(fieldset)
@@ -542,4 +544,3 @@
self._render_fields(fields, w, form)
self.render_child_forms(w, form, values)
w(u'</fieldset>')
-
--- a/web/views/forms.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/forms.py Thu Dec 10 12:34:15 2015 +0100
@@ -48,6 +48,9 @@
from warnings import warn
import time
+import inspect
+
+from six import text_type
from logilab.common import dictattr, tempattr
from logilab.common.decorators import iclassmethod, cached
@@ -257,7 +260,7 @@
editedfields = self._cw.form['_cw_fields']
except KeyError:
raise RequestError(self._cw._('no edited fields specified'))
- entityform = entity and self.field_by_name.im_func.func_code.co_argcount == 4 # XXX
+ entityform = entity and len(inspect.getargspec(self.field_by_name)) == 4 # XXX
for editedfield in splitstrip(editedfields):
try:
name, role = editedfield.split('-')
@@ -286,7 +289,7 @@
except ProcessFormError as exc:
errors.append((field, exc))
if errors:
- errors = dict((f.role_name(), unicode(ex)) for f, ex in errors)
+ errors = dict((f.role_name(), text_type(ex)) for f, ex in errors)
raise ValidationError(None, errors)
return processed
@@ -377,7 +380,7 @@
Warning: this method must be called only when all form fields are setup
"""
- for (rtype, role), eids in self.linked_to.iteritems():
+ for (rtype, role), eids in self.linked_to.items():
# if the relation is already setup by a form field, do not add it
# in a __linkto hidden to avoid setting it twice in the controller
try:
--- a/web/views/ibreadcrumbs.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/ibreadcrumbs.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,10 +18,12 @@
"""breadcrumbs components definition for CubicWeb web client"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from warnings import warn
+from six import text_type
+
from logilab.mtconverter import xml_escape
from cubicweb import tags, uilib
@@ -141,7 +143,7 @@
xml_escape(url), xml_escape(uilib.cut(title, textsize))))
else:
textsize = self._cw.property_value('navigation.short-line-size')
- w(xml_escape(uilib.cut(unicode(part), textsize)))
+ w(xml_escape(uilib.cut(text_type(part), textsize)))
class BreadCrumbETypeVComponent(BreadCrumbEntityVComponent):
--- a/web/views/idownloadable.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/idownloadable.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,7 +20,9 @@
=====================================================
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
+
+from six.moves import range
from logilab.mtconverter import BINARY_ENCODINGS, TransformError, xml_escape
from logilab.common.deprecation import class_renamed, deprecated
@@ -166,7 +168,7 @@
def call(self, **kwargs):
rset = self.cw_rset
- for i in xrange(len(rset)):
+ for i in range(len(rset)):
self.w(u'<div class="efile">')
self.wview(self.__regid__, rset, row=i, col=0, **kwargs)
self.w(u'</div>')
@@ -199,6 +201,3 @@
title = _('embedded html')
_embedding_tag = tags.iframe
-
-
-
--- a/web/views/json.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/json.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""json export views"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from cubicweb.uilib import rest_traceback
@@ -64,7 +64,7 @@
# use ``application/javascript`` if ``callback`` parameter is
# provided, keep ``application/json`` otherwise
self._cw.set_content_type('application/javascript')
- json_data = b'%s(%s)' % (json_padding, json_data)
+ json_data = json_padding + b'(' + json_data + b')'
return json_data
@@ -85,7 +85,8 @@
indent = int(self._cw.form['_indent'])
else:
indent = None
- self.w(json_dumps(data, indent=indent))
+ # python's json.dumps escapes non-ascii characters
+ self.w(json_dumps(data, indent=indent).encode('ascii'))
class JsonRsetView(JsonMixIn, AnyRsetView):
--- a/web/views/magicsearch.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/magicsearch.py Thu Dec 10 12:34:15 2015 +0100
@@ -23,6 +23,8 @@
import re
from logging import getLogger
+from six import text_type
+
from yams.interfaces import IVocabularyConstraint
from rql import RQLSyntaxError, BadRQLQuery, parse
@@ -86,7 +88,7 @@
else:
# Only one possible translation, no ambiguity
if len(translation_set) == 1:
- relation.r_type = iter(translations[rtype]).next()
+ relation.r_type = next(iter(translations[rtype]))
# More than 1 possible translation => resolve it later
else:
ambiguous_nodes[relation] = (lhs.name, translation_set)
@@ -386,7 +388,7 @@
self.processors = sorted(processors, key=lambda x: x.priority)
def process_query(self, uquery):
- assert isinstance(uquery, unicode)
+ assert isinstance(uquery, text_type)
try:
procname, query = uquery.split(':', 1)
proc = self.by_name[procname.strip().lower()]
@@ -589,7 +591,7 @@
"""
schema = self._cw.vreg.schema
relations = set()
- untyped_dest_var = rqlvar_maker(defined=select.defined_vars).next()
+ untyped_dest_var = next(rqlvar_maker(defined=select.defined_vars))
# for each solution
# 1. find each possible relation
# 2. for each relation:
@@ -643,7 +645,7 @@
vocab_kwargs = {}
if rtype_incomplete_value:
vocab_rql += ', X %s LIKE %%(value)s' % user_rtype
- vocab_kwargs['value'] = '%s%%' % rtype_incomplete_value
+ vocab_kwargs['value'] = u'%s%%' % rtype_incomplete_value
vocab += [value for value, in
self._cw.execute(vocab_rql, vocab_kwargs)]
return sorted(set(vocab))
--- a/web/views/management.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/management.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""security management and error screens"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from logilab.mtconverter import xml_escape
@@ -137,7 +137,7 @@
# if excinfo is not None, it's probably not a bug
if excinfo is None:
return
- vcconf = self._cw.vreg.config.vc_config()
+ vcconf = self._cw.cnx.repo.get_versions()
w(u"<div>")
eversion = vcconf.get('cubicweb', self._cw._('no version information'))
# NOTE: tuple wrapping needed since eversion is itself a tuple
@@ -169,7 +169,7 @@
binfo += u'\n\n:URL: %s\n' % req.url()
if not '__bugreporting' in req.form:
binfo += u'\n:form params:\n'
- binfo += u'\n'.join(u' * %s = %s' % (k, v) for k, v in req.form.iteritems())
+ binfo += u'\n'.join(u' * %s = %s' % (k, v) for k, v in req.form.items())
binfo += u'\n\n:CubicWeb version: %s\n' % (eversion,)
for pkg, pkgversion in cubes:
binfo += u":Cube %s version: %s\n" % (pkg, pkgversion)
--- a/web/views/navigation.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/navigation.py Thu Dec 10 12:34:15 2015 +0100
@@ -46,10 +46,12 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from datetime import datetime
+from six import text_type
+
from rql.nodes import VariableRef, Constant
from logilab.mtconverter import xml_escape
@@ -192,10 +194,10 @@
return entity.printable_value(attrname, format='text/plain')
elif col is None: # smart links disabled.
def index_display(row):
- return unicode(row)
+ return text_type(row)
elif self._cw.vreg.schema.eschema(rset.description[0][col]).final:
def index_display(row):
- return unicode(rset[row][col])
+ return text_type(rset[row][col])
else:
def index_display(row):
return rset.get_entity(row, col).view('text')
--- a/web/views/owl.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/owl.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,7 +19,9 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
+
+from six.moves import range
from logilab.mtconverter import TransformError, xml_escape
@@ -166,7 +168,7 @@
def call(self):
self.w(OWL_OPENING_ROOT % {'appid': self._cw.vreg.schema.name})
- for i in xrange(self.cw_rset.rowcount):
+ for i in range(self.cw_rset.rowcount):
self.cell_call(i, 0)
self.w(OWL_CLOSING_ROOT)
--- a/web/views/plots.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/plots.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,10 @@
"""basic plot views"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
+
+from six import add_metaclass
+from six.moves import range
from logilab.common.date import datetime2ticks
from logilab.common.deprecation import class_deprecated
@@ -83,9 +86,10 @@
def _render(self, *args, **kwargs):
raise NotImplementedError
+
+@add_metaclass(class_deprecated)
class FlotPlotWidget(PlotWidget):
"""PlotRenderer widget using Flot"""
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.14] cubicweb.web.views.plots module is deprecated, use the jqplot cube instead'
onload = u"""
var fig = jQuery('#%(figid)s');
@@ -117,7 +121,7 @@
if req.ie_browser():
req.add_js('excanvas.js')
req.add_js(('jquery.flot.js', 'cubicweb.flot.js'))
- figid = u'figure%s' % req.varmaker.next()
+ figid = u'figure%s' % next(req.varmaker)
plotdefs = []
plotdata = []
self.w(u'<div id="%s" style="width: %spx; height: %spx;"></div>' %
@@ -137,8 +141,8 @@
'dateformat': '"%s"' % fmt})
+@add_metaclass(class_deprecated)
class PlotView(baseviews.AnyRsetView):
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.14] cubicweb.web.views.plots module is deprecated, use the jqplot cube instead'
__regid__ = 'plot'
title = _('generic plot')
@@ -154,7 +158,7 @@
abscissa = [row[0] for row in self.cw_rset]
plots = []
nbcols = len(self.cw_rset.rows[0])
- for col in xrange(1, nbcols):
+ for col in range(1, nbcols):
data = [row[col] for row in self.cw_rset]
plots.append(filterout_nulls(abscissa, data))
plotwidget = FlotPlotWidget(varnames, plots, timemode=self.timemode)
--- a/web/views/primary.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/primary.py Thu Dec 10 12:34:15 2015 +0100
@@ -38,7 +38,7 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from warnings import warn
--- a/web/views/pyviews.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/pyviews.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,6 +19,9 @@
"""
__docformat__ = "restructuredtext en"
+from six import text_type
+from six.moves import range
+
from cubicweb.view import View
from cubicweb.predicates import match_kwargs
from cubicweb.web.views import tableview
@@ -38,7 +41,7 @@
w(self.empty_cell_content)
def render_cell(self, w, rownum):
- w(unicode(self.data[rownum][self.colid]))
+ w(text_type(self.data[rownum][self.colid]))
class PyValTableView(tableview.TableMixIn, View):
@@ -100,7 +103,7 @@
def build_column_renderers(self):
return [self.column_renderer(colid)
- for colid in xrange(len(self.pyvalue[0]))]
+ for colid in range(len(self.pyvalue[0]))]
def facets_form(self, mainvar=None):
return None # not supported
--- a/web/views/rdf.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/rdf.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,9 @@
"""base xml and rss views"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
+
+from six.moves import range
from yams import xy
@@ -56,7 +58,7 @@
graph.bind('cw', CW)
for prefix, xmlns in xy.XY.prefixes.items():
graph.bind(prefix, rdflib.Namespace(xmlns))
- for i in xrange(self.cw_rset.rowcount):
+ for i in range(self.cw_rset.rowcount):
entity = self.cw_rset.complete_entity(i, 0)
self.entity2graph(graph, entity)
self.w(graph.serialize(format=self.format))
--- a/web/views/reledit.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/reledit.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,7 +20,7 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
import copy
from warnings import warn
@@ -259,7 +259,7 @@
elif action == 'add':
add_etype = self._compute_ttypes(rschema, role)[0]
_new_entity = self._cw.vreg['etypes'].etype_class(add_etype)(self._cw)
- _new_entity.eid = self._cw.varmaker.next()
+ _new_entity.eid = next(self._cw.varmaker)
edit_entity = _new_entity
# XXX see forms.py ~ 276 and entities.linked_to method
# is there another way?
@@ -292,7 +292,7 @@
cwtarget='eformframe', cssclass='releditForm',
**formargs)
# pass reledit arguments
- for pname, pvalue in event_args.iteritems():
+ for pname, pvalue in event_args.items():
form.add_hidden('__reledit|' + pname, pvalue)
# handle buttons
if form.form_buttons: # edition, delete
@@ -402,4 +402,3 @@
assert args['reload'].startswith('http')
view = req.vreg['views'].select('reledit', req, rset=rset, rtype=args['rtype'])
return self._call_view(view, **args)
-
--- a/web/views/schema.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/schema.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""Specific views for schema related entities"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from itertools import cycle
@@ -26,6 +26,8 @@
import os, os.path as osp
import codecs
+from six import text_type
+
from logilab.common.graph import GraphGenerator, DotBackend
from logilab.common.ureports import Section, Table
from logilab.common.registry import yes
@@ -114,7 +116,7 @@
def grouped_permissions_table(self, rschema):
# group relation definitions with identical permissions
perms = {}
- for rdef in rschema.rdefs.itervalues():
+ for rdef in rschema.rdefs.values():
rdef_perms = []
for action in rdef.ACTIONS:
groups = sorted(rdef.get_groups(action))
@@ -131,7 +133,7 @@
_ = self._cw._
w(u'<div style="margin: 0px 1.5em">')
tmpl = u'<strong>%s</strong> %s <strong>%s</strong>'
- for perm, rdefs in perms.iteritems():
+ for perm, rdefs in perms.items():
w(u'<div>%s</div>' % u', '.join(
tmpl % (_(s.type), _(rschema.type), _(o.type)) for s, o in rdefs))
# accessing rdef from previous loop by design: only used to get
@@ -279,7 +281,7 @@
def cell_call(self, row, col):
defaultval = self.cw_rset.rows[row][col]
if defaultval is not None:
- self.w(unicode(self.cw_rset.rows[row][col].unzpickle()))
+ self.w(text_type(self.cw_rset.rows[row][col].unzpickle()))
class CWETypeRelationCardinalityCell(baseviews.FinalView):
__regid__ = 'etype-rel-cardinality-cell'
@@ -487,7 +489,7 @@
entity = self.cw_rset.get_entity(row, col)
rschema = self._cw.vreg.schema.rschema(entity.rtype.name)
rdef = rschema.rdefs[(entity.stype.name, entity.otype.name)]
- constraints = [xml_escape(unicode(c)) for c in getattr(rdef, 'constraints')]
+ constraints = [xml_escape(text_type(c)) for c in getattr(rdef, 'constraints')]
self.w(u'<br/>'.join(constraints))
class CWAttributeOptionsCell(EntityView):
@@ -557,8 +559,9 @@
def __init__(self, visitor, cw):
self.visitor = visitor
self.cw = cw
- self.nextcolor = cycle( ('#ff7700', '#000000',
- '#ebbc69', '#888888') ).next
+ self._cycle = iter(cycle(('#ff7700', '#000000', '#ebbc69', '#888888')))
+ self.nextcolor = lambda: next(self._cycle)
+
self.colors = {}
def node_properties(self, eschema):
--- a/web/views/sessions.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/sessions.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,20 +19,28 @@
__docformat__ = "restructuredtext en"
from time import time
+from logging import getLogger
-from cubicweb import RepositoryError, Unauthorized, BadConnectionId
-from cubicweb.web import InvalidSession, component
+from logilab.common.registry import RegistrableObject
+
+from cubicweb import RepositoryError, Unauthorized, BadConnectionId, set_log_methods
+from cubicweb.predicates import yes
+from cubicweb.web import InvalidSession
+
+from cubicweb.web.views import authentication
-class AbstractSessionManager(component.Component):
+class AbstractSessionManager(RegistrableObject):
"""manage session data associated to a session identifier"""
__abstract__ = True
+ __select__ = yes()
+ __registry__ = 'sessions'
__regid__ = 'sessionmanager'
def __init__(self, repo):
vreg = repo.vreg
self.session_time = vreg.config['http-session-time'] or None
- self.authmanager = vreg['components'].select('authmanager', repo=repo)
+ self.authmanager = authentication.RepositoryAuthenticationManager(repo)
interval = (self.session_time or 0) / 2.
if vreg.config.anonymous_user()[0] is not None:
self.cleanup_anon_session_time = vreg.config['cleanup-anonymous-session-time'] or 5 * 60
@@ -53,15 +61,7 @@
closed, total = 0, 0
for session in self.current_sessions():
total += 1
- try:
- last_usage_time = session.cnx.check()
- except AttributeError:
- last_usage_time = session.mtime
- except BadConnectionId:
- self.close_session(session)
- closed += 1
- continue
-
+ last_usage_time = session.mtime
no_use_time = (time() - last_usage_time)
if session.anonymous_session:
if no_use_time >= self.cleanup_anon_session_time:
@@ -95,11 +95,14 @@
raise NotImplementedError()
+set_log_methods(AbstractSessionManager, getLogger('cubicweb.sessionmanager'))
+
+
class InMemoryRepositorySessionManager(AbstractSessionManager):
"""manage session data associated to a session identifier"""
def __init__(self, *args, **kwargs):
- AbstractSessionManager.__init__(self, *args, **kwargs)
+ super(InMemoryRepositorySessionManager, self).__init__(*args, **kwargs)
# XXX require a RepositoryAuthenticationManager which violates
# authenticate interface by returning a session instead of a user
#assert isinstance(self.authmanager, RepositoryAuthenticationManager)
--- a/web/views/sparql.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/sparql.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,9 @@
"""SPARQL integration"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
+
+from six.moves import range
from yams import xy
from rql import TypeResolverException
@@ -111,7 +113,7 @@
rqlst = self.cw_rset.syntax_tree().children[0]
varnames = [var.name for var in rqlst.selection]
results = E.results()
- for rowidx in xrange(len(self.cw_rset)):
+ for rowidx in range(len(self.cw_rset)):
result = E.result()
for colidx, varname in enumerate(varnames):
result.append(self.cell_binding(rowidx, colidx, varname))
@@ -140,4 +142,4 @@
def registration_callback(vreg):
if Sparql2rqlTranslator is not None:
- vreg.register_all(globals().itervalues(), __name__)
+ vreg.register_all(globals().values(), __name__)
--- a/web/views/startup.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/startup.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,7 +22,7 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from logilab.common.textutils import unormalize
from logilab.common.deprecation import deprecated
@@ -106,7 +106,7 @@
def entity_types_table(self, eschemas):
infos = sorted(self.entity_types(eschemas),
- key=lambda (l,a,e): unormalize(l))
+ key=lambda t: unormalize(t[0]))
q, r = divmod(len(infos), 2)
if r:
infos.append( (None, ' ', ' ') )
@@ -172,4 +172,3 @@
@deprecated('[3.11] display_folders method is deprecated, backport it if needed')
def display_folders(self):
return 'Folder' in self._cw.vreg.schema and self._cw.execute('Any COUNT(X) WHERE X is Folder')[0][0]
-
--- a/web/views/staticcontrollers.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/staticcontrollers.py Thu Dec 10 12:34:15 2015 +0100
@@ -33,7 +33,7 @@
from logging import getLogger
from cubicweb import Forbidden
-from cubicweb.web import NotFound
+from cubicweb.web import NotFound, Redirect
from cubicweb.web.http_headers import generateDateTime
from cubicweb.web.controller import Controller
from cubicweb.web.views.urlrewrite import URLRewriter
@@ -66,9 +66,10 @@
if not debugmode:
# XXX: Don't provide additional resource information to error responses
#
- # the HTTP RFC recommands not going further than 1 year ahead
- expires = datetime.now() + timedelta(days=6*30)
+ # the HTTP RFC recommends not going further than 1 year ahead
+ expires = datetime.now() + timedelta(seconds=self.max_age(path))
self._cw.set_header('Expires', generateDateTime(mktime(expires.timetuple())))
+ self._cw.set_header('Cache-Control', 'max-age=%s' % self.max_age(path))
# XXX system call to os.stats could be cached once and for all in
# production mode (where static files are not expected to change)
@@ -140,7 +141,7 @@
"""return the filepath that will be used to cache concatenation of `paths`
"""
_, ext = osp.splitext(paths[0])
- fname = 'cache_concat_' + hashlib.md5(';'.join(paths)).hexdigest() + ext
+ fname = 'cache_concat_' + hashlib.md5((';'.join(paths)).encode('ascii')).hexdigest() + ext
return osp.join(self.config.appdatahome, 'uicache', fname)
def concat_cached_filepath(self, paths):
@@ -167,7 +168,7 @@
with open(osp.join(dirpath, rid), 'rb') as source:
for line in source:
f.write(line)
- f.write('\n')
+ f.write(b'\n')
f.close()
except:
os.remove(tmpfile)
@@ -200,11 +201,13 @@
paths = relpath[len(self.data_modconcat_basepath):].split(',')
filepath = self.concat_files_registry.concat_cached_filepath(paths)
else:
- # skip leading '/data/' and url params
- if relpath.startswith(self.base_datapath):
- prefix = self.base_datapath
- else:
+ if not relpath.startswith(self.base_datapath):
+ # /data/foo, redirect to /data/{hash}/foo
prefix = 'data/'
+ relpath = relpath[len(prefix):]
+ raise Redirect(self._cw.data_url(relpath), 302)
+ # skip leading '/data/{hash}/' and url params
+ prefix = self.base_datapath
relpath = relpath[len(prefix):]
relpath = relpath.split('?', 1)[0]
dirpath, rid = config.locate_resource(relpath)
--- a/web/views/tableview.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/tableview.py Thu Dec 10 12:34:15 2015 +0100
@@ -42,7 +42,7 @@
.. autoclass:: cubicweb.web.views.tableview.TableLayout
:members:
-There is by default only on table layout, using the 'table_layout' identifier,
+There is by default only one table layout, using the 'table_layout' identifier,
that is referenced by table views
:attr:`cubicweb.web.views.tableview.TableMixIn.layout_id`. If you want to
customize the look and feel of your table, you can either replace the default
@@ -52,21 +52,24 @@
Notice you can gives options to the layout using a `layout_args` dictionary on
your class.
-If you can still find a view that suit your needs, you should take a look at the
+If you still can't find a view that suit your needs, you should take a look at the
class below that is the common abstract base class for the three views defined
-above and implements you own class.
+above and implement your own class.
.. autoclass:: cubicweb.web.views.tableview.TableMixIn
:members:
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from warnings import warn
from copy import copy
from types import MethodType
+from six import string_types, add_metaclass, create_bound_method
+from six.moves import range
+
from logilab.mtconverter import xml_escape
from logilab.common.decorators import cachedproperty
from logilab.common.deprecation import class_deprecated
@@ -162,7 +165,7 @@
def __init__(self, req, view, **kwargs):
super(TableLayout, self).__init__(req, **kwargs)
- for key, val in self.cw_extra_kwargs.items():
+ for key, val in list(self.cw_extra_kwargs.items()):
if hasattr(self.__class__, key) and not key[0] == '_':
setattr(self, key, val)
self.cw_extra_kwargs.pop(key)
@@ -225,7 +228,7 @@
def render_table_body(self, w, colrenderers):
w(u'<tbody>')
- for rownum in xrange(self.view.table_size):
+ for rownum in range(self.view.table_size):
self.render_row(w, rownum, colrenderers)
w(u'</tbody>')
@@ -284,7 +287,7 @@
attrs = renderer.attributes.copy()
if renderer.sortable:
sortvalue = renderer.sortvalue(rownum)
- if isinstance(sortvalue, basestring):
+ if isinstance(sortvalue, string_types):
sortvalue = sortvalue[:self.sortvalue_limit]
if sortvalue is not None:
attrs[u'cubicweb:sortvalue'] = js_dumps(sortvalue)
@@ -646,10 +649,10 @@
# compute displayed columns
if self.displaycols is None:
if headers is not None:
- displaycols = range(len(headers))
+ displaycols = list(range(len(headers)))
else:
rqlst = self.cw_rset.syntax_tree()
- displaycols = range(len(rqlst.children[0].selection))
+ displaycols = list(range(len(rqlst.children[0].selection)))
else:
displaycols = self.displaycols
# compute table headers
@@ -723,7 +726,7 @@
for aname, member in[('renderfunc', renderfunc),
('sortfunc', sortfunc)]:
if isinstance(member, MethodType):
- member = MethodType(member.im_func, acopy, acopy.__class__)
+ member = create_bound_method(member.__func__, acopy)
setattr(acopy, aname, member)
return acopy
finally:
@@ -918,13 +921,13 @@
################################################################################
+@add_metaclass(class_deprecated)
class TableView(AnyRsetView):
"""The table view accepts any non-empty rset. It uses introspection on the
result set to compute column names and the proper way to display the cells.
It is however highly configurable and accepts a wealth of options.
"""
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.14] %(cls)s is deprecated'
__regid__ = 'table'
title = _('table')
@@ -977,9 +980,9 @@
if 'displaycols' in self._cw.form:
displaycols = [int(idx) for idx in self._cw.form['displaycols']]
elif headers is not None:
- displaycols = range(len(headers))
+ displaycols = list(range(len(headers)))
else:
- displaycols = range(len(self.cw_rset.syntax_tree().children[0].selection))
+ displaycols = list(range(len(self.cw_rset.syntax_tree().children[0].selection)))
return displaycols
def _setup_tablesorter(self, divid):
@@ -1143,7 +1146,7 @@
else:
column.append_renderer(subvid or 'incontext', colindex)
if cellattrs and colindex in cellattrs:
- for name, value in cellattrs[colindex].iteritems():
+ for name, value in cellattrs[colindex].items():
column.add_attr(name, value)
# add column
columns.append(column)
@@ -1184,8 +1187,8 @@
title = _('editable-table')
+@add_metaclass(class_deprecated)
class CellView(EntityView):
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.14] %(cls)s is deprecated'
__regid__ = 'cell'
__select__ = nonempty_rset()
@@ -1271,6 +1274,7 @@
finalview = 'editable-final'
+@add_metaclass(class_deprecated)
class EntityAttributesTableView(EntityView):
"""This table displays entity attributes in a table and allow to set a
specific method to help building cell content for each attribute as well as
@@ -1282,7 +1286,6 @@
Table will render column header using the method header_for_COLNAME if
defined otherwise COLNAME will be used.
"""
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.14] %(cls)s is deprecated'
__abstract__ = True
columns = ()
@@ -1298,7 +1301,7 @@
self.w(u'<table class="%s">' % self.table_css)
self.table_header(sample)
self.w(u'<tbody>')
- for row in xrange(self.cw_rset.rowcount):
+ for row in range(self.cw_rset.rowcount):
self.cell_call(row=row, col=0)
self.w(u'</tbody>')
self.w(u'</table>')
@@ -1333,4 +1336,3 @@
colname = self._cw._(column)
self.w(u'<th>%s</th>' % xml_escape(colname))
self.w(u'</tr></thead>\n')
-
--- a/web/views/tabs.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/tabs.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,9 @@
"""base classes to handle tabbed views"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
+
+from six import string_types
from logilab.common.deprecation import class_renamed
from logilab.mtconverter import xml_escape
@@ -114,7 +116,7 @@
active_tab = uilib.domid(default_tab)
viewsvreg = self._cw.vreg['views']
for tab in tabs:
- if isinstance(tab, basestring):
+ if isinstance(tab, string_types):
tabid, tabkwargs = tab, {}
else:
tabid, tabkwargs = tab
--- a/web/views/timetable.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/timetable.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,9 @@
"""html timetable views"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
+
+from six.moves import range
from logilab.mtconverter import xml_escape
from logilab.common.date import ONEDAY, date_range, todatetime
@@ -51,7 +53,7 @@
users = []
users_max = {}
# XXX: try refactoring with calendar.py:OneMonthCal
- for row in xrange(self.cw_rset.rowcount):
+ for row in range(self.cw_rset.rowcount):
task = self.cw_rset.get_entity(row, 0)
icalendarable = task.cw_adapt_to('ICalendarable')
if len(self.cw_rset[row]) > 1 and self.cw_rset.description[row][1] == 'CWUser':
@@ -88,7 +90,7 @@
rows = []
# colors here are class names defined in cubicweb.css
- colors = ["col%x" % i for i in xrange(12)]
+ colors = ["col%x" % i for i in range(12)]
next_color_index = 0
visited_tasks = {} # holds a description of a task for a user
--- a/web/views/treeview.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/treeview.py Thu Dec 10 12:34:15 2015 +0100
@@ -20,7 +20,7 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from warnings import warn
@@ -140,7 +140,7 @@
ajaxargs = json.loads(form.pop('morekwargs'))
# got unicode & python keywords must be strings
morekwargs.update(dict((str(k), v)
- for k, v in ajaxargs.iteritems()))
+ for k, v in ajaxargs.items()))
toplevel_thru_ajax = form.pop('treeview_top', False) or initial_thru_ajax
toplevel = toplevel_thru_ajax or (initial_load and not form.get('fname'))
return subvid, treeid, toplevel_thru_ajax, toplevel
--- a/web/views/uicfg.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/uicfg.py Thu Dec 10 12:34:15 2015 +0100
@@ -57,6 +57,8 @@
from warnings import warn
+from six import string_types
+
from cubicweb import neg_role
from cubicweb.rtags import (RelationTags, RelationTagsBool, RelationTagsSet,
RelationTagsDict, NoTargetRelationTagsDict,
@@ -267,7 +269,7 @@
if not 'inlined' in sectdict:
sectdict['inlined'] = sectdict['main']
# recompute formsections and set it to avoid recomputing
- for formtype, section in sectdict.iteritems():
+ for formtype, section in sectdict.items():
formsections.add('%s_%s' % (formtype, section))
def tag_relation(self, key, formtype, section):
@@ -302,7 +304,7 @@
rtags[section] = value
cls = self.tag_container_cls
rtags = cls('_'.join([section,value])
- for section,value in rtags.iteritems())
+ for section,value in rtags.items())
return rtags
def get(self, *key):
@@ -650,7 +652,7 @@
self.tag_relation((sschema, rschema, oschema, role), True)
def _tag_etype_attr(self, etype, attr, desttype='*', *args, **kwargs):
- if isinstance(attr, basestring):
+ if isinstance(attr, string_types):
attr, role = attr, 'subject'
else:
attr, role = attr
@@ -687,5 +689,5 @@
def registration_callback(vreg):
- vreg.register_all(globals().itervalues(), __name__)
+ vreg.register_all(globals().values(), __name__)
indexview_etype_section.init(vreg.schema)
--- a/web/views/undohistory.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/undohistory.py Thu Dec 10 12:34:15 2015 +0100
@@ -17,7 +17,7 @@
# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from logilab.common.registry import Predicate
@@ -46,7 +46,7 @@
def __str__(self):
return '%s(%s)' % (self.__class__.__name__, ', '.join(
- "%s=%v" % (str(k), str(v)) for k, v in kwargs.iteritems() ))
+ "%s=%v" % (str(k), str(v)) for k, v in kwargs.items() ))
def __call__(self, cls, req, tx_action=None, **kwargs):
# tx_action is expected to be a transaction.AbstractAction
--- a/web/views/urlpublishing.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/urlpublishing.py Thu Dec 10 12:34:15 2015 +0100
@@ -60,7 +60,7 @@
from rql import TypeResolverException
from cubicweb import RegistryException
-from cubicweb.web import NotFound, Redirect, component
+from cubicweb.web import NotFound, Redirect, component, views
class PathDontMatch(Exception):
@@ -201,18 +201,14 @@
return self.handle_etype_attr(req, cls, attrname, value)
return self.handle_etype(req, cls)
- def set_vid_for_rset(self, req, cls, rset):# cls is there to ease overriding
+ def set_vid_for_rset(self, req, cls, rset): # cls is there to ease overriding
if rset.rowcount == 0:
raise NotFound()
- # we've to set a default vid here, since vid_from_rset may try to use a
- # table view if fetch_rql include some non final relation
- if rset.rowcount == 1:
- req.form.setdefault('vid', 'primary')
- else: # rset.rowcount >= 1
- if len(rset.column_types(0)) > 1:
- req.form.setdefault('vid', 'list')
- else:
- req.form.setdefault('vid', 'sameetypelist')
+ if 'vid' not in req.form:
+ # check_table=False tells vid_from_rset not to try to use a table view if fetch_rql
+ # include some non final relation
+ req.form['vid'] = views.vid_from_rset(req, rset, req.vreg.schema,
+ check_table=False)
def handle_etype(self, req, cls):
rset = req.execute(cls.fetch_rql(req.user))
--- a/web/views/urlrewrite.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/urlrewrite.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,6 +19,8 @@
import re
+from six import string_types, add_metaclass
+
from cubicweb.uilib import domid
from cubicweb.appobject import AppObject
@@ -51,6 +53,7 @@
return super(metarewriter, mcs).__new__(mcs, name, bases, classdict)
+@add_metaclass(metarewriter)
class URLRewriter(AppObject):
"""Base class for URL rewriters.
@@ -64,7 +67,6 @@
should be tried first. The higher the priority is, the earlier the
rewriter will be tried.
"""
- __metaclass__ = metarewriter
__registry__ = 'urlrewriting'
__abstract__ = True
priority = 1
@@ -122,14 +124,14 @@
required_groups = None
if required_groups and not req.user.matching_groups(required_groups):
continue
- if isinstance(inputurl, basestring):
+ if isinstance(inputurl, string_types):
if inputurl == uri:
req.form.update(infos)
break
elif inputurl.match(uri): # it's a regexp
# XXX what about i18n? (vtitle for instance)
for param, value in infos.items():
- if isinstance(value, basestring):
+ if isinstance(value, string_types):
req.form[param] = inputurl.sub(value, uri)
else:
req.form[param] = value
@@ -222,7 +224,7 @@
required_groups = None
if required_groups and not req.user.matching_groups(required_groups):
continue
- if isinstance(inputurl, basestring):
+ if isinstance(inputurl, string_types):
if inputurl == uri:
return callback(inputurl, uri, req, self._cw.vreg.schema)
elif inputurl.match(uri): # it's a regexp
--- a/web/views/vcard.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/vcard.py Thu Dec 10 12:34:15 2015 +0100
@@ -23,7 +23,7 @@
from cubicweb.predicates import is_instance
from cubicweb.view import EntityView
-_ = unicode
+from cubicweb import _
VCARD_PHONE_TYPES = {'home': 'HOME', 'office': 'WORK', 'mobile': 'CELL', 'fax': 'FAX'}
--- a/web/views/wdoc.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/wdoc.py Thu Dec 10 12:34:15 2015 +0100
@@ -35,7 +35,7 @@
from cubicweb.view import StartupView
from cubicweb.uilib import rest_publish
from cubicweb.web import NotFound, action
-_ = unicode
+from cubicweb import _
# table of content management #################################################
@@ -73,7 +73,7 @@
def build_toc(config):
alltocfiles = reversed(tuple(config.locate_all_files('toc.xml')))
- maintoc = parse(alltocfiles.next()).getroot()
+ maintoc = parse(next(alltocfiles)).getroot()
maintoc.parent = None
index = {}
build_toc_index(maintoc, index)
@@ -229,4 +229,3 @@
def url(self):
return self._cw.build_url('doc/about')
-
--- a/web/views/workflow.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/workflow.py Thu Dec 10 12:34:15 2015 +0100
@@ -22,11 +22,13 @@
"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
import os
from warnings import warn
+from six import add_metaclass
+
from logilab.mtconverter import xml_escape
from logilab.common.graph import escape
from logilab.common.deprecation import class_deprecated
@@ -116,7 +118,7 @@
'changestate', self._cw, entity=entity, transition=transition,
redirect_path=self.redirectpath(entity), **kwargs)
trinfo = self._cw.vreg['etypes'].etype_class('TrInfo')(self._cw)
- trinfo.eid = self._cw.varmaker.next()
+ trinfo.eid = next(self._cw.varmaker)
subform = self._cw.vreg['forms'].select('edition', self._cw, entity=trinfo,
mainform=False)
subform.field_by_name('wf_info_for', 'subject').value = entity.eid
@@ -429,8 +431,8 @@
return WorkflowDotPropsHandler(self._cw)
+@add_metaclass(class_deprecated)
class TmpPngView(TmpFileViewMixin, EntityView):
- __metaclass__ = class_deprecated
__deprecation_warning__ = '[3.18] %(cls)s is deprecated'
__regid__ = 'tmppng'
__select__ = match_form_params('tmpfile')
--- a/web/views/xbel.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/xbel.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,9 @@
"""xbel views"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
+
+from six.moves import range
from logilab.mtconverter import xml_escape
@@ -42,7 +44,7 @@
self.w(u'<!DOCTYPE xbel PUBLIC "+//IDN python.org//DTD XML Bookmark Exchange Language 1.0//EN//XML" "http://www.python.org/topics/xml/dtds/xbel-1.0.dtd">')
self.w(u'<xbel version="1.0">')
self.w(u'<title>%s</title>' % self._cw._('bookmarks'))
- for i in xrange(self.cw_rset.rowcount):
+ for i in range(self.cw_rset.rowcount):
self.cell_call(i, 0)
self.w(u"</xbel>")
@@ -65,4 +67,3 @@
def url(self, entity):
return entity.actual_url()
-
--- a/web/views/xmlrss.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/views/xmlrss.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,11 +18,13 @@
"""base xml and rss views"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
from base64 import b64encode
from time import timezone
+from six.moves import range
+
from logilab.mtconverter import xml_escape
from cubicweb.predicates import (is_instance, non_final_entity, one_line_rset,
@@ -64,7 +66,7 @@
"""display a list of entities by calling their <item_vid> view"""
self.w(u'<?xml version="1.0" encoding="%s"?>\n' % self._cw.encoding)
self.w(u'<%s size="%s">\n' % (self.xml_root, len(self.cw_rset)))
- for i in xrange(self.cw_rset.rowcount):
+ for i in range(self.cw_rset.rowcount):
self.cell_call(i, 0)
self.w(u'</%s>\n' % self.xml_root)
@@ -256,7 +258,7 @@
def call(self):
"""display a list of entities by calling their <item_vid> view"""
self._open()
- for i in xrange(self.cw_rset.rowcount):
+ for i in range(self.cw_rset.rowcount):
self.cell_call(i, 0)
self._close()
--- a/web/webconfig.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/webconfig.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,7 +18,7 @@
"""web ui configuration for cubicweb instances"""
__docformat__ = "restructuredtext en"
-_ = unicode
+from cubicweb import _
import os
import hmac
@@ -26,6 +26,8 @@
from os.path import join, exists, split, isdir
from warnings import warn
+from six import text_type
+
from logilab.common.decorators import cached, cachedproperty
from logilab.common.deprecation import deprecated
from logilab.common.configuration import merge_options
@@ -280,18 +282,7 @@
continue
yield key, pdef
- # don't use @cached: we want to be able to disable it while this must still
- # be cached
- def repository(self, vreg=None):
- """return the instance's repository object"""
- try:
- return self.__repo
- except AttributeError:
- from cubicweb.repoapi import get_repository
- repo = get_repository(config=self, vreg=vreg)
- self.__repo = repo
- return repo
-
+ @deprecated('[3.22] call req.cnx.repo.get_versions() directly')
def vc_config(self):
return self.repository().get_versions()
@@ -305,7 +296,7 @@
user = self['anonymous-user'] or None
passwd = self['anonymous-password']
if user:
- user = unicode(user)
+ user = text_type(user)
except KeyError:
user, passwd = None, None
except UnicodeDecodeError:
@@ -317,17 +308,17 @@
"""This random key/salt is used to sign content to be sent back by
browsers, eg. in the error report form.
"""
- return str(uuid4())
+ return str(uuid4()).encode('ascii')
def sign_text(self, text):
"""sign some text for later checking"""
# hmac.new expect bytes
- if isinstance(text, unicode):
+ if isinstance(text, text_type):
text = text.encode('utf-8')
# replace \r\n so we do not depend on whether a browser "reencode"
# original message using \r\n or not
return hmac.new(self._instance_salt,
- text.strip().replace('\r\n', '\n')).hexdigest()
+ text.strip().replace(b'\r\n', b'\n')).hexdigest()
def check_text_sign(self, text, signature):
"""check the text signature is equal to the given signature"""
@@ -472,7 +463,7 @@
staticdir = join(staticdir, rdir)
if not isdir(staticdir) and 'w' in mode:
os.makedirs(staticdir)
- return file(join(staticdir, filename), mode)
+ return open(join(staticdir, filename), mode)
def static_file_add(self, rpath, data):
stream = self.static_file_open(rpath)
--- a/web/webctl.py Wed Dec 09 18:42:13 2015 +0100
+++ b/web/webctl.py Thu Dec 10 12:34:15 2015 +0100
@@ -18,6 +18,7 @@
"""cubicweb-ctl commands and command handlers common to twisted/modpython
web configuration
"""
+from __future__ import print_function
__docformat__ = "restructuredtext en"
@@ -44,7 +45,7 @@
def bootstrap(self, cubes, automatic=False, inputlevel=0):
"""bootstrap this configuration"""
if not automatic:
- print '\n' + underline_title('Generic web configuration')
+ print('\n' + underline_title('Generic web configuration'))
config = self.config
config.input_config('web', inputlevel)
if ASK.confirm('Allow anonymous access ?', False):
@@ -87,8 +88,8 @@
copy(osp.join(resource_dir, resource_path), dest_resource)
# handle md5 version subdirectory
linkdir(dest, osp.join(dest, config.instance_md5_version()))
- print ('You can use apache rewrite rule below :\n'
- 'RewriteRule ^/data/(.*) %s/$1 [L]' % dest)
+ print('You can use apache rewrite rule below :\n'
+ 'RewriteRule ^/data/(.*) %s/$1 [L]' % dest)
def _datadirs(self, config, repo=None):
if repo is None:
--- a/wsgi/__init__.py Wed Dec 09 18:42:13 2015 +0100
+++ b/wsgi/__init__.py Thu Dec 10 12:34:15 2015 +0100
@@ -27,11 +27,9 @@
__docformat__ = "restructuredtext en"
from email import message, message_from_string
-from Cookie import SimpleCookie
-from StringIO import StringIO
-from cgi import parse_header
from pprint import pformat as _pformat
+from six.moves.http_cookies import SimpleCookie
def pformat(obj):
"""pretty prints `obj` if possible"""
--- a/wsgi/handler.py Wed Dec 09 18:42:13 2015 +0100
+++ b/wsgi/handler.py Thu Dec 10 12:34:15 2015 +0100
@@ -19,7 +19,9 @@
__docformat__ = "restructuredtext en"
-from itertools import chain, repeat, izip
+from itertools import chain, repeat
+
+from six.moves import zip
from cubicweb import AuthenticationError
from cubicweb.web import DirectResponse
@@ -78,7 +80,7 @@
def __init__(self, code, req, body=None):
text = STATUS_CODE_TEXT.get(code, 'UNKNOWN STATUS CODE')
self.status = '%s %s' % (code, text)
- self.headers = list(chain(*[izip(repeat(k), v)
+ self.headers = list(chain(*[zip(repeat(k), v)
for k, v in req.headers_out.getAllRawHeaders()]))
self.headers = [(str(k), str(v)) for k, v in self.headers]
if body:
--- a/wsgi/request.py Wed Dec 09 18:42:13 2015 +0100
+++ b/wsgi/request.py Thu Dec 10 12:34:15 2015 +0100
@@ -27,13 +27,12 @@
import tempfile
-from StringIO import StringIO
-from urllib import quote
-from urlparse import parse_qs
-from warnings import warn
+from io import BytesIO
+
+from six.moves.urllib.parse import parse_qs
from cubicweb.multipart import (
- copy_file, parse_form_data, MultipartError, parse_options_header)
+ copy_file, parse_form_data, parse_options_header)
from cubicweb.web import RequestError
from cubicweb.web.request import CubicWebRequestBase
from cubicweb.wsgi import pformat, normalize_header
@@ -59,7 +58,7 @@
length = 0
# wsgi.input is not seekable, so copy the request contents to a temporary file
if length < 100000:
- self.content = StringIO()
+ self.content = BytesIO()
else:
self.content = tempfile.TemporaryFile()
copy_file(environ['wsgi.input'], self.content, maxread=length)
@@ -82,7 +81,7 @@
headers= headers_in)
self.content = environ['wsgi.input']
if files is not None:
- for key, part in files.iteritems():
+ for key, part in files.items():
self.form[key] = (part.filename, part.file)
def __repr__(self):
@@ -149,15 +148,10 @@
if params is None:
return
encoding = self.encoding
- for param, val in params.iteritems():
+ for param, val in params.items():
if isinstance(val, (tuple, list)):
- val = [
- unicode(x, encoding) if isinstance(x, str) else x
- for x in val]
if len(val) == 1:
val = val[0]
- elif isinstance(val, str):
- val = unicode(val, encoding)
if param in self.no_script_form_params and val:
val = self.no_script_form_param(param, val)
if param == '_cwmsgid':
--- a/wsgi/test/unittest_wsgi.py Wed Dec 09 18:42:13 2015 +0100
+++ b/wsgi/test/unittest_wsgi.py Thu Dec 10 12:34:15 2015 +0100
@@ -1,7 +1,7 @@
# encoding=utf-8
import webtest.app
-from StringIO import StringIO
+from io import BytesIO
from cubicweb.devtools.webtest import CubicWebTestTC
@@ -21,11 +21,11 @@
r = webtest.app.TestRequest.blank('/', {
'CONTENT_LENGTH': 12,
'CONTENT_TYPE': 'text/plain',
- 'wsgi.input': StringIO('some content')})
+ 'wsgi.input': BytesIO(b'some content')})
req = CubicWebWsgiRequest(r.environ, self.vreg)
- self.assertEqual('some content', req.content.read())
+ self.assertEqual(b'some content', req.content.read())
def test_http_scheme(self):
r = webtest.app.TestRequest.blank('/', {
@@ -52,11 +52,11 @@
self.assertTrue(req.https)
def test_big_content(self):
- content = 'x'*100001
+ content = b'x'*100001
r = webtest.app.TestRequest.blank('/', {
'CONTENT_LENGTH': len(content),
'CONTENT_TYPE': 'text/plain',
- 'wsgi.input': StringIO(content)})
+ 'wsgi.input': BytesIO(content)})
req = CubicWebWsgiRequest(r.environ, self.vreg)
@@ -94,14 +94,14 @@
def test_post_files(self):
content_type, params = self.webapp.encode_multipart(
- (), (('filefield', 'aname', 'acontent'),))
+ (), (('filefield', 'aname', b'acontent'),))
r = webtest.app.TestRequest.blank(
'/', POST=params, content_type=content_type)
req = CubicWebWsgiRequest(r.environ, self.vreg)
self.assertIn('filefield', req.form)
fieldvalue = req.form['filefield']
self.assertEqual(u'aname', fieldvalue[0])
- self.assertEqual('acontent', fieldvalue[1].read())
+ self.assertEqual(b'acontent', fieldvalue[1].read())
def test_post_unicode_urlencoded(self):
params = 'arg=%C3%A9'
@@ -115,3 +115,8 @@
super(WSGIAppTC, cls).init_config(config)
config.https_uiprops = None
config.https_datadir_url = None
+
+
+if __name__ == '__main__':
+ import unittest
+ unittest.main()