diff --git a/src/csvw/metadata.py b/src/csvw/metadata.py
index 6f17514..3467529 100644
--- a/src/csvw/metadata.py
+++ b/src/csvw/metadata.py
@@ -16,6 +16,7 @@ import warnings
 import itertools
 import collections
 from urllib.parse import urljoin
+from urllib.request import urlopen
 
 from ._compat import pathlib, py3_unicode_to_str, json_open
 
@@ -489,6 +490,13 @@ class Schema(Description):
             col._parent = self
             col._number = i + 1
 
+    @classmethod
+    def fromvalue(cls, v):
+        if isinstance(v, str):
+            # The schema is referenced with a URL
+            v = json.loads(urlopen(v).read().decode('utf8'))
+        return cls(**cls.partition_properties(v))
+
     @property
     def columndict(self):
         return {c.header: c for c in self.columns}

Support for remote table schemas?
CSV on the Web officially specifies that table schemas can be metadata files remotely located on the Web via a URL, see definition from the [spec](https://www.w3.org/TR/tabular-metadata/):

> `tableSchema`: An object property that provides a single schema description as described in section 5.5 Schemas, used as the default for all the tables in the group. This may be provided as an embedded object within the JSON metadata or as a URL reference to a separate JSON object that is a schema description.

Currently, this library doesn't offer this feature.

I can see two possible solutions for now:
1) Implement referencing and loading of remote schemas directly within this library.
2) Make a screening step and inject any remotely located table schemas into the JSON before feeding it to this library.

Naturally, I would prefer option 1. I'm aware there is the caveat that then validation cannot happen offline. One could imagine caching, though. What do you think on this? Can you imagine this feature being added in principle?
diff --git a/tests/test_metadata.py b/tests/test_metadata.py
index b10f8ab..febcb5a 100644
--- a/tests/test_metadata.py
+++ b/tests/test_metadata.py
@@ -1,3 +1,4 @@
+import io
 import json
 import shutil
 import collections
@@ -712,3 +713,30 @@ AF,9799379"""}
                 data['country_slice.csv'].replace('AF;AD', 'AF;AX'), encoding='utf-8')
             with pytest.raises(ValueError):
                 tg.check_referential_integrity()
+
+    def test_remote_schema(self, mocker, tmpdir):
+        schema = """
+        {
+            "columns": [
+                {"name": "countryCode", "datatype": "string"},
+                {"name": "name", "datatype": "string"}
+            ]
+        }
+        """
+        mocker.patch(
+            'csvw.metadata.urlopen', mocker.Mock(return_value=io.BytesIO(schema.encode('utf8'))))
+        tg = self._make_tablegroup(
+            tmpdir,
+            metadata="""{
+  "@context": "http://www.w3.org/ns/csvw",
+  "tables": [{
+    "url": "countries.csv",
+    "tableSchema": "url"
+  }]
+}""")
+        assert len(tg.tables[0].tableSchema.columns) == 2
+
+        # The remote content has been inlined:
+        out = pathlib.Path(str(tmpdir)) / 'md.json'
+        tg.to_file(out)
+        assert 'countryCode' in out.read_text(encoding='utf8')

pip install -e .[dev,test]
parse_log_pytest
requirements.txt
pytest pytest-mock pytest-cov
apt-get update apt-get install -y gcc
3.7
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
attrs==24.2.0
bleach==6.0.0
certifi @ file:///croot/certifi_1671487769961/work/certifi
cffi==1.15.1
charset-normalizer==3.4.1
coverage==7.2.7
cryptography==44.0.2
-e git+https://github.com/cldf/csvw.git@0eccd438b6770ad628223f77a582b55067b06002#egg=csvw
docutils==0.20.1
exceptiongroup==1.2.2
flake8==5.0.4
idna==3.10
importlib-metadata==4.2.0
iniconfig==2.0.0
isodate==0.7.2
jaraco.classes==3.2.3
jeepney==0.9.0
keyring==23.9.3
markdown-it-py==2.2.0
mccabe==0.7.0
mdurl==0.1.2
mock==5.2.0
more-itertools==9.1.0
packaging==24.0
pkginfo==1.10.0
pluggy==1.2.0
pycodestyle==2.9.1
pycparser==2.21
pyflakes==2.5.0
Pygments==2.17.2
pytest==7.4.4
pytest-cov==4.1.0
pytest-mock==3.11.1
python-dateutil==2.9.0.post0
readme-renderer==37.3
requests==2.31.0
requests-toolbelt==1.0.0
rfc3986==2.0.0
rich==13.8.1
SecretStorage==3.3.3
six==1.17.0
tomli==2.0.1
twine==4.0.2
typing_extensions==4.7.1
uritemplate==4.1.1
urllib3==2.0.7
webencodings==0.5.1
zipp==3.15.0

name: csvw
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2022.12.7=py37h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=22.3.1=py37h06a4308_0
  - python=3.7.16=h7a1cb2a_0
  - readline=8.2=h5eee18b_0
  - setuptools=65.6.3=py37h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.38.4=py37h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==24.2.0
      - bleach==6.0.0
      - cffi==1.15.1
      - charset-normalizer==3.4.1
      - coverage==7.2.7
      - cryptography==44.0.2
      - docutils==0.20.1
      - exceptiongroup==1.2.2
      - flake8==5.0.4
      - idna==3.10
      - importlib-metadata==4.2.0
      - iniconfig==2.0.0
      - isodate==0.7.2
      - jaraco-classes==3.2.3
      - jeepney==0.9.0
      - keyring==23.9.3
      - markdown-it-py==2.2.0
      - mccabe==0.7.0
      - mdurl==0.1.2
      - mock==5.2.0
      - more-itertools==9.1.0
      - packaging==24.0
      - pkginfo==1.10.0
      - pluggy==1.2.0
      - pycodestyle==2.9.1
      - pycparser==2.21
      - pyflakes==2.5.0
      - pygments==2.17.2
      - pytest==7.4.4
      - pytest-cov==4.1.0
      - pytest-mock==3.11.1
      - python-dateutil==2.9.0.post0
      - readme-renderer==37.3
      - requests==2.31.0
      - requests-toolbelt==1.0.0
      - rfc3986==2.0.0
      - rich==13.8.1
      - secretstorage==3.3.3
      - six==1.17.0
      - tomli==2.0.1
      - twine==4.0.2
      - typing-extensions==4.7.1
      - uritemplate==4.1.1
      - urllib3==2.0.7
      - webencodings==0.5.1
      - zipp==3.15.0
prefix: /opt/conda/envs/csvw

tests/test_metadata.py::TestTableGroup::test_remote_schema
tests/test_metadata.py::test_URITemplate tests/test_metadata.py::test_Link tests/test_metadata.py::test_column_init tests/test_metadata.py::TestColumnAccess::test_get_column tests/test_metadata.py::TestDialect::test_doubleQuote tests/test_metadata.py::TestNaturalLanguage::test_string tests/test_metadata.py::TestNaturalLanguage::test_array tests/test_metadata.py::TestNaturalLanguage::test_object tests/test_metadata.py::TestNaturalLanguage::test_error tests/test_metadata.py::TestNaturalLanguage::test_serialize tests/test_metadata.py::TestColumn::test_read_rite_with_separator tests/test_metadata.py::TestColumn::test_read_required_empty_string tests/test_metadata.py::TestColumn::test_read_required_empty_string_no_null tests/test_metadata.py::TestColumn::test_reuse_datatype tests/test_metadata.py::TestLink::test_link tests/test_metadata.py::TestTable::test_roundtrip tests/test_metadata.py::TestTable::test_read_write tests/test_metadata.py::TestTable::test_iteritems_column_renaming tests/test_metadata.py::TestTable::test_unspecified_column_in_table_without_url tests/test_metadata.py::TestTableGroup::test_iteritems_column_renaming tests/test_metadata.py::TestTableGroup::test_roundtrip tests/test_metadata.py::TestTableGroup::test_copy tests/test_metadata.py::TestTableGroup::test_write_all tests/test_metadata.py::TestTableGroup::test_all tests/test_metadata.py::TestTableGroup::test_separator tests/test_metadata.py::TestTableGroup::test_None_value_in_common_props tests/test_metadata.py::TestTableGroup::test_virtual_columns1 tests/test_metadata.py::TestTableGroup::test_virtual_columns2 tests/test_metadata.py::TestTableGroup::test_required_column1 tests/test_metadata.py::TestTableGroup::test_write tests/test_metadata.py::TestTableGroup::test_spec_examples tests/test_metadata.py::TestTableGroup::test_foreign_keys tests/test_metadata.py::TestTableGroup::test_foreignkeys tests/test_metadata.py::TestTableGroup::test_foreignkeys_2
src/csvw/metadata.py
src/csvw/metadata.py